Skip to Content
Author's profile photo Milton Chandradas

Building Windows application on SAP Mobile Platform SDK – Part 2

Update:  The code for the sample application and the How To Guide for this series is now published.

In my previous blog, I had talked about the onboarding process to uniquely identify a device with the SMP Server.  The next logical progression in this blog series is to write about how devices can retrieve data from the backend and also how devices can make changes to the backend data.  As part of this blog, I will try and post code for another sample application that illustrates how to retrieve data and make changes to backend using the SAP Mobile Platform SDK (hereinafter referred to as “SMP SDK” or “SDK”).

CRUD operations

In order to retrieve data from the backend, an HTTP GET request is made along with the application connection id in the headers.

HTTP Request

URL: http://<hostname>:<port>/<appid>/<CollectionName>

Method: GET

Header: { X-SMP-APPCID : <app connection id> }



To accomplish this using the SMP SDK, the following steps need to be taken.  Creating an ODataStore instance and calling OpenAsync is only done once for a session.  From there on, it’s a matter of calling ScheduleReadEntitySet method any number of times.


GETFlow.PNG


The ODataStore library is used to interact with the SMP Server to submit HTTP requests to either GET data or perform CUD operations.  An ODataStore instance is required to interact with an OData Service.  The ODataStore hides a lot of complexities and makes interacting with OData source fairly easy for the developer.   To create an instance of the ODataStore, the developer can use either one of the 2 constructors.  The default value for the 2nd EntityFormat parameter is XML format. However, using JSON format considerably reduces the network traffic.


public ODataStore(string serviceUri, ODataStore.EntityFormat entityFormat = ODataStore.EntityFormat.XML);
public ODataStore(Uri serviceUri, ODataStore.EntityFormat entityFormat = ODataStore.EntityFormat.XML);
public enum EntityFormat
{
    JSON = 0,
    XML = 1,
}
// Sample code snippet for creating an ODataStore
var store = new ODataStore(uri);


Once an instance of ODataStore is created, the method OpenAsync is called.  This method retrieves the service document and the metadata document.   When making the OpenAsync call, it is also necessary to pass in the user credentials and the application connection id as header values.


var client = new SAP.Net.Http.HttpClient( new System.Net.Http.HttpClientHandler { Credentials = new NetworkCredential(“user", “password") }, true);
client.DefaultRequestHeaders.TryAddWithoutValidation("X-SMP-APPCID",appconnid);
await store.OpenAsync(client);


The ScheduleReadEntitySet method is used to schedule an HTTP GET request.  This method takes the collection name as a parameter.  The Response object is then called asynchronously to submit the request.


var execution = store.ScheduleReadEntitySet(collectionName);
var response = await execution.Response;


The response object is then cast as an ODataEntitySet and can be immediately bound to an UI control.  The ODataEntitySet is an IObservableCollection which allows the UI controls to automatically update themselves when the collection is changed.


var response = await execution.Response;
this.EntitySet = (SAP.Data.OData.Online.ODataEntitySet)((IODataResponseSingle)response).Payload;
// Bind this.EntitySet directly to UI controls


Making changes to the backend

The ScheduleCreateEntity method is used to create an entity in the backend.  This method takes an ODataEntity and the CollectionName as parameters.  An entity is created locally and passed in as parameter to the ScheduleCreateEntity method.

POSTFlow.PNG


var entity = new SAP.Data.OData.Online.ODataEntity(“TypeName");
entity.Properties["ID"].Value = XYZ;
entity.Properties["Name"].Value = “<XYZ>";
store.AllocateProperties(entity, SAP.Data.OData.Store.PropertyCreationMode.All);
var execution = store.ScheduleCreateEntity(entity, collectionName);
var response = await execution.Response;


Similarly, the ScheduleUpdateEntity is used to update an entity in the backend.  This method takes an ODataEntity as a parameter.  It is recommended to use the DeepCopy() method to make a real copy of an entity (not just a reference copy).  Make the necessary updates on the temporary ODataEntity. This way, even if the update operation fails (network disconnects, server error or whatever), the original entity is still intact and the app would not be in an inconsistent state.


var copiedEntity = entity.DeepCopy();      
copiedEntity.Properties[“Name"].Value = newName;
var execution = store.ScheduleUpdateEntity(copiedEntity);
var response = await execution.Response;


The ScheduleDeleteEntity method is used to delete an entity in the backend.



var execution = store.ScheduleDeleteEntity(entity);
var response = await execution.Response;


Update:  The code for the sample application and the How To Guide is now published.  The Windows Store Flight Sample Application Series illustrates the various techniques involved in creating an online Windows Store application using the Windows SMP 3.0 SP05 SDK.  This sample application series uses the universal Windows app project templates to build apps that can run on Windows Phones, tablets, laptops and workstations.

In conclusion, in this blog I have highlighted some of the important methods involved in performing CRUD operations against an OData Source using the SAP Mobile Platform.  This current version of SMP SDK only supports online functionality for Windows.  However, future releases of the SMP SDK will support additional functionality.  In upcoming blogs, I will talk more about the newer functionality and also provide more code samples to help build Windows applications using the new SAP Mobile Platform SDK.  Also, if you have questions building Windows applications, please feel free to reach out to me.

Assigned Tags

      24 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Markus Reich
      Markus Reich

      Hi,

      great blog, but I can't find the Windows Desktop SDK in SAP App Store?

      br

      Meex

      Author's profile photo Milton Chandradas
      Milton Chandradas
      Blog Post Author

      SAP Mobile Platform SDK SP05 (referred to as "SMP SDK") contains the Windows SDK.  If you install SMP SDK in the default location, you will find the Windows SDK in the following folder: C:\SAP\MobileSDK3\NativeSDK\ODataFramework\Windows

      The size of the Windows SDK is only about 250 kb.  They are packaged as NuGet packages.  The .nupkg files contain libraries for both Windows Store and Windows Desktop applications. 

      Author's profile photo Markus Reich
      Markus Reich

      ok thx, but where can I download can't find SP05?

      Author's profile photo Milton Chandradas
      Milton Chandradas
      Blog Post Author

      You can download it from Service marketplace (http://service.sap.com/swdc).

      /wp-content/uploads/2014/09/sdk_552686.png 

      Author's profile photo Markus Reich
      Markus Reich

      perfect, thx for your help

      Author's profile photo Markus Reich
      Markus Reich

      Hi, I've some problems creating the Online ODataStore 🙁

      May you can provice your complete code snippet?

      regards

      Meex

      Author's profile photo Milton Chandradas
      Milton Chandradas
      Blog Post Author

      The sample application will be published in a couple of days.  In the meantime, if you have any questions, contact me.  [Removed by Moderator]

      Author's profile photo Markus Reich
      Markus Reich

      Hi Milton,

      I have another question 🙂

      As EntitySet is a dynamic data structure, is it possible to use LINQ to query against a returned entityset? We want to load the data once from backend to our app, and then the user should have the possibility to search the EntitySet?

      regards

      Meex

      Author's profile photo Markus Reich
      Markus Reich

      ok found it myself 🙂

      var entities = from entity in EntitySet

                                     where ((string)entity.Properties["Description"].Value).Contains("Test")

                                     select entity;

      Meex

      Author's profile photo Milton Chandradas
      Milton Chandradas
      Blog Post Author

      // LINQ extension method using the lambda style

      var filteredEntitySet = entitySet.Where(e => ((string)e.Properties["Address/State"].Value) == "WA");

      // LINQ extension method using the SQL style

      var filteredEntitySet = from e in entitySet

      where ((string)e.Properties["Address/State"].Value) == "WA"

                              select e;

      foreach (var e in filteredEntitySet)

      {

          Console.WriteLine(e.Properties["Name"].Value);

      }

      Author's profile photo Markus Reich
      Markus Reich

      is there a way to transform ODataEntity to XML or JSON? I want to serialize the object so ein can store data in as BLOB in sqlite DB?

      regards

      Meex

      Author's profile photo Milton Chandradas
      Milton Chandradas
      Blog Post Author

      var execution = Store.ScheduleReadEntitySet(collectionName);

      IODataResponse response = await execution.Response;

      string json = JsonConvert.SerializeObject(((IODataResponseSingle)response).Payload);

      You can add the Newtonsoft.Json nuget package and use the code above to serialize the object as JSON. 

      Author's profile photo Markus Reich
      Markus Reich

      Hi Milton,

      thx for your answer! Serialize works, but I have a problem deserializing the json to a entity set? Is there hint?

      regards

      Meex

      Author's profile photo William Griep
      William Griep

      Was there an SDK change from SP5 to SP6 that would cause problems wtih the sample?

      ODataContext.DownloadRelatedItems breaks when trying to use the navigationProperty.AssociationResourcePath.  That value is a mangled URI that ScheduleRequest fails on.

      We worked around that by extracting the CarrierCollection("airlinecode")/carrierFlights from the URI and passing it in as the resourcePath instead of the mangled URI.

      Beyond that, we have problems booking flights and haven't figured out a work around yet.

      Author's profile photo Milton Chandradas
      Milton Chandradas
      Blog Post Author

      It should work fine.  What error are you getting when trying to use the navigationProperty.AssociationResourcePath ?  Is it implemented in the backend OData source ?

      navProp.png

      Also, does your metadata document have a navigation property named carrierFlights ?

      /wp-content/uploads/2015/01/metadata_628427.png

      Author's profile photo Milton Chandradas
      Milton Chandradas
      Blog Post Author

      Your workaround should also work.  Your approach requires prior knowledge of the relationship between the tables, whereas the approach above queries for the relationship and figures out the related table. 

      Author's profile photo William Griep
      William Griep

      The value I get for navigationProperty.AssociationResourcePath is:

      https://sapes1.sapdevcenter.com/sap/opu/odata/IWFND/RMTSAMPLEFLIGHT/CarrierCollection('AA')/carrierFlights

      I haven't try running this against SP5 of the SDK, but this is the value I get against SP6 of SMP 3.0 SDK.

      Regarding the metadata document, where does this reside?

      Author's profile photo Markus Reich
      Markus Reich

      Hi, for CRUD operations you need to send a X-CSRF-TOKEN, I've tried this, but I still get a 403 satus. Maybe you can provide an example?

      kind regards

      Meex

      Author's profile photo Markus Reich
      Markus Reich

      ok, found it 🙂

      There's a parameter you can set => client.ShouldHandleXcsrfToken = true

      Author's profile photo Markus Reich
      Markus Reich

      Hi Milton,

      would it be possible to provide an example for a Deep Create / Deep Insert with the SDK?

      best regards

      Meex

      Author's profile photo Former Member
      Former Member

      Hi Milton,

      could you please explain how to get a specific entity? For example I have a flight with an id == 3 and want only this on entity.

      Regards,

      Hendrik

      Author's profile photo Former Member
      Former Member

      public async Task ReadEntity(string resourcePath)

      {

      var execution = Store.ScheduleReadEntity(resourcePath);

      IODataResponse response = await execution.Response;

      this.Entity = (SAP.Data.OData.Online.ODataEntity)((IODataResponseSingle)response).Payload;

      }

      await ReadEntity("Suppliers(3)");

      Author's profile photo Maged Kamal
      Maged Kamal

      Hi Milton,

      Currently I am building an online windows application that will be deployed on an Intermec  device with OS version  "Windows Embeded handhled 6.5 classic, CE OS 5.2.29040". can I use online oData SDK for communicating with SAP?

      Regards,

      Maged

      Author's profile photo Former Member
      Former Member

      Hi Milton,

      How to create a Entity set with json string?

      I tried in below way but its throwing a  error message while adding the data as Object reference not found.

      Dictionary<string, IODataNavigationProperty> navigationProperties = new Dictionary<string, IODataNavigationProperty>();

      Dictionary<IODataAnnotationName, string> annotations = new Dictionary<IODataAnnotationName, string>();

      ODataEntity odataEntity = new ODataEntity("EntityType", navigationProperties, annotations);

      odataEntity.Properties[key].Value = "SAP";