Getting safe–limited–meta information from a Turnkey app

I have stated on numerous occasions that MDriven Turnkey is not only for AngularJS and MVC. MDriven Turnkey is a complete information delivery architecture that is just as suitable for building highly secured native apps for other platforms. In some articles and videos I have shown this for Windows WPF and Windows Store applications.

One important requirement for this to be possible is that the turnkey system can expose just enough meta information so that a native client knows what the turnkey system in question offers / but not so much that we compromise security or divulge internal details on how our system is built.

What is enough then. Well - we need to expose the main menu so that the native app knows what it should show the user. For each main menu action we need to say what view that will be brought up. For each view we need to expose what fields, widgets and texts that the UI contains. And what actions are available from the view in question based on the current selection state of the view.

In the samples below you will want to replace the first part of the url to the one that points to your application.

Getting the main menu

https://mdriventurnkey-0006.azurewebsites.net/MDriven/GlobalActionsMeta?targetgroup=

And you get this:


<?xml version="1.0" encoding="utf-8"?>
<root>
  <menugroups>
    <menugroup Name="Views" Sortkey="004"/>
    <menugroup Name="ValueStores" Sortkey="005"/>
    <menugroup Name="Edit" Sortkey="002"/>
    <menugroup Name="File" Sortkey="001"/>
    <menugroup Name="Seekers" Sortkey="003"/>
  </menugroups>
  <actions>
    <action MenuGroup="ValueStores" MenuGroupSortKey="005" DividerGroupTag="" DividerGroupTagSortKey="" Name="ShowManageBrands" Presentation="Show Manage Brands" BringUpViewModel="ManageBrands" ExecuteFrameworkRuntimeAction="None"/>
    <action MenuGroup="Views" MenuGroupSortKey="004" DividerGroupTag="" DividerGroupTagSortKey="" Name="ShowAllRentalContracts" Presentation="Show All Rental Contracts" BringUpViewModel="AllRentalContracts" ExecuteFrameworkRuntimeAction="None"/>
    <action MenuGroup="Edit" MenuGroupSortKey="002" DividerGroupTag="" DividerGroupTagSortKey="" Name="Redo" Presentation="Redo" ExecuteFrameworkRuntimeAction="Redo"/>
    <action MenuGroup="Edit" MenuGroupSortKey="002" DividerGroupTag="" DividerGroupTagSortKey="" Name="Undo" Presentation="Undo" ExecuteFrameworkRuntimeAction="Undo"/>
    <action MenuGroup="File" MenuGroupSortKey="001" DividerGroupTag="" DividerGroupTagSortKey="" Name="Save" Presentation="Save" ExecuteFrameworkRuntimeAction="Save"/>
    <action MenuGroup="Views" MenuGroupSortKey="004" DividerGroupTag="" DividerGroupTagSortKey="" Name="ShowAllCars" Presentation="Show All Cars" BringUpViewModel="AllCars" ExecuteFrameworkRuntimeAction="None"/>
    <action MenuGroup="File" MenuGroupSortKey="001" DividerGroupTag="" DividerGroupTagSortKey="" Name="Refresh" Presentation="Refresh" ExecuteFrameworkRuntimeAction="Refresh"/>
  </actions>
</root>

The MenuGroups are the ones you defined in your model and the actions are all Global Actions from your model. You get sort keys that should be treated as alphanumeric sorts in order to get the menu in the designed order. Sort on MenuGroupSortKey, then DividerGroupTagSortKey. Put a Divider between items that has different DividerGroupTags. Create the MenuItem with presentation as stated in the presentation attribute.

When user wants to execute –it can either be a FrameworkAction like Save,Exit,Undo,Redo or a navigation – on navigation the BringUpViewModel attribute is set.

This information just states the obvious about your applications main menu and no need to be keep it safe – it is benign data.

If you want to filter away actions based on targetgroup – this is when your app has different audiences – you can provide the target group name in the call. TargetGroups are really a special use of the AccessGroup concept that is explained here.

To Actually implement the execution of the action you execute a REST operation like this:

https://mdriventurnkey-0006.azurewebsites.net/api/open?VMClassId=MAINMENU;ShowAllCars&ResetServerApp=false

It is the name of the action that is important “ShowAllCars” and the fact that you state that this is the MAINMENU. You do not need to worry about access control – the server will make sure the caller is authenticated if there are accessgroup needs for this menu action.

You will get something like this back:

"943a7840-796e-4370-bd37-d407ffa48aa9¤$null$;AllCars"
The part after the “¤” is the VMClassId : $null$;AllCars
The guid before is the VM’s server identity.
You now have enough information to pull data from the serverstream for the target view. You do this with the REST call:
https://mdriventurnkey-0006.azurewebsites.net/api/ServerStream?VMId=943a7840-796e-4370-bd37-d407ffa48aa9&cursor=0
The VMId is the guid we got back from “open”. The cursor is where in the message stream we are – since we just started for this UI it is zero.

We get json back:



[
  {
    "VMClassName": "AllCars",
    "Action": "CreateCar",
    "Enable": true,
    "Presentation": "Create Car",
    "SortKey": "000000##000000#CreateCar",
    "IsModal": false,
    "View": null,
    "PresentationOfTarget": "",
    "AreYouSureQuestion": "",
    "Class": null,
    "GroupHeader": "Car",
    "SubMenuGroup": "",
    "SubMenuGroupSortKey": "",
    "MNo": 1,
    "CType": "ServerUpdateCommand_Action",
    "IsGarbage": false
  },
  {
    "VMClassName": "AllCars",
    "Action": "ViewCarLocation",
    "Enable": false,
    "Presentation": "View Car Location",
    "SortKey": "000000##000000#ViewCarLocation",
    "IsModal": false,
    "View": "CarLocation",
    "PresentationOfTarget": "",
    "AreYouSureQuestion": "",
    "Class": null,
    "GroupHeader": "Car",
    "SubMenuGroup": "",
    "SubMenuGroupSortKey": "",
    "MNo": 2,
    "CType": "ServerUpdateCommand_Action",
    "IsGarbage": false
  },
  {
    "Attribute": "AllCar",
    "UpdateType": "Add",
    "NewValues": [ "5!1;AllCar" ],
    "OldValues": null,
    "NewValuesStartIndex": 0,
    "OldValuesStartIndex": -1,
    "VMClassId": "$null$;AllCars",
    "MNo": 3,
    "CType": "ServerUpdateCommand_UpdateCollection",
    "IsGarbage": false
  },
  {
    "Attribute": "AllCar",
    "UpdateType": "Add",
    "NewValues": [ "5!97;AllCar" ],
    "OldValues": null,
    "NewValuesStartIndex": 1,
    "OldValuesStartIndex": -1,
    "VMClassId": "$null$;AllCars",
    "MNo": 4,
    "CType": "ServerUpdateCommand_UpdateCollection",
    "IsGarbage": false
  },
  {
    "Attribute": "AllCar",
    "UpdateType": "Add",
    "NewValues": [ "5!98;AllCar" ],
    "OldValues": null,
    "NewValuesStartIndex": 2,
    "OldValuesStartIndex": -1,
    "VMClassId": "$null$;AllCars",
    "MNo": 5,
    "CType": "ServerUpdateCommand_UpdateCollection",
    "IsGarbage": false
  },
  {
    "Attribute": "AllCar",
    "UpdateType": "Add",
    "NewValues": [ "5!4;AllCar" ],
    "OldValues": null,
    "NewValuesStartIndex": 3,
    "OldValuesStartIndex": -1,
    "VMClassId": "$null$;AllCars",
    "MNo": 6,
    "CType": "ServerUpdateCommand_UpdateCollection",
    "IsGarbage": false
  },
  {
    "IsDirty": false,
    "ServerQueueLength": 6,
    "MessagesReceivedFromClient": 0,
    "SuggestCallbackInSecs": 0,
    "NumVmsInApp": "1",
    "InstanceId": 1,
    "ServersHighestMNo": 6,
    "ServerStatus": "OK-09:43:31.934",
    "RootObjectStatus": "isnull",
    "WindowHeader": "AllCars",
    "AsyncQueueCount": 0,
    "MarkersForActionsRunning": 0,
    "MNo": 7,
    "CType": "ServerUpdateCommand_AppInfo",
    "IsGarbage": false
  }
]

This JSON is what builds up  the data hierarchy that we designed in the ViewModelEditor in MDriven Designer.

This data should be polled continuously according to the information in the object that always comes last “CType: ServerUpdateCommand_AppInfo”. In this special object you see your new cursor id == MNo=7, and when we should ask the server again is stated in SuggestCallbackInSecs=0 – so in this case we should call right back since there are probably more to fetch.

Getting a UI definition

Once we build up the data this way we still need to understand on the client side how to display it. So we need to find the meta information of the UI-Hints that explains what kind of UI-widgets we should use and where they should go on the screen relative to each other. That is done like this:

https://mdriventurnkey-0006.azurewebsites.net/MDriven/ViewMeta?view=AllCars

And we get xml back:


<root RowHeight="20" ColWidth="50">
  <control type="grid" owner="AllCars" name="AllCar" root="vCurrent_AllCars" label="All Car" labelspan="1" colspan="3" rowspan="5" x="0" y="0" nesting="AllCar">
    <control type="textbox" name="AsString" label="As String" colspan="1"/>
    <control type="textbox" name="RegistrationNumber" label="Registration Number" colspan="3"/>
  </control>
  <control type="textbox" owner="TheCar" name="RegistrationNumber" root="vCurrent_TheCar" label="Registration Number" labelspan="1" colspan="1" rowspan="1" x="4" y="0"/>
  <control type="combobox" owner="TheCar" name="Brand" root="vCurrent_TheCar" label="Brand" labelspan="1" colspan="1" rowspan="1" x="4" y="1" picklist="BrandPickList" displaymember="Presentation"/>
  <control type="image" owner="TheCar" name="Brand_BrandImage" root="vCurrent_TheCar" label="Brand Image" labelspan="1" colspan="1" rowspan="2" x="4" y="2"/>
</root>

This xml holds enough information to put the designed widgets on a screen and set up binding to the data hierarcy that we stream in with the Json above. It even encapsulate any tagged values you have enclosed in your design.

The full-stack proof of concept implementation is in our WPF/Win10/Universal/PortableLibrary stack that we will make available now.

This page was edited 48 days ago on 02/10/2024. What links here