WinRT : Data access. N tiers considerations
As a developer of entreprise applications, you need to know which method you need to use to query your server database.
You must determinate the best way to expose your entities, which format (XML, JSON, binary), which kind of protocol specification (SOAP, ODATA …) and maybe your transfer protocol (HTTP, HTTPS, TCP)
In this series of articles, we will see some considerations with differents technics:
- WCF Web Services: Based on SOAP protocol specification and XML format, Web Services is available through WCF configuration (based on basicHttpBinding)
- WCF Data Services : WCF DS is the implementation of the ODATA specfication. You can get XML or JSON datas, using REST queries.
- WCF HTTP / NET.TCP: You take control on which kind of format and method you want to use. You need to specify the binding and you need to implement the correct binding. This technic is powerful, but your client application needs to know the protocol, entities and the querying method.
- HttpClient: Without WCF support, you can make http request (POST or GET) to a service exposing datas.
In this series, we will see some considerations on each technics. It’s not basic tutorials, but rather some advices on each of them:
- Part One : WCF Data Services
- Part Two : WCF Web Services
- Part Three : WCF Http / Net.Tcp
- Part Four : HttpClient
You will find a sample for each part, based on a simple application.
WCF Data Services
You will find the solution here : WCFDataServicesForWinRT.zip
Definition
ODATA : It’s a standardized protocol for creating and consuming data. OData builds on core protocols like HTTP and commonly accepted methodologies like REST.
WCF Data Services : It’s the Microsoft SDK ODATA’s implementation. It works great on .NET and WinRT. Visual Studio can generate code for an ODATA Server and a for Client requester, to simplify your work.
To work with WCF DS (and WinRT) you need to install the Windows Store Apps SDK : https://msdn.microsoft.com/en-us/jj658961
When you have installed the SDK, you can add references to WCF DS, like you can see in this screenshot. Note that the WCF DS versions is 5.0. This version doesn’t support JSON request, natively (we will explain this part later in this article)
Visual Studio solution
My solution is composed with 2 projects. The first one is a server project, using Entity Framework 5 and WCF Data Services.
The second one is the client side, where I have already added the reference (using Service Reference add method)
Querying data is simple, if you don’t use the async / await method:
// Not funny ...
public List<Item> Items { get; set; }
public void GetItems0()
{
DataServiceCollection<Item> items = new DataServiceCollection<Item>(context);
// Définition de la requête
var query = (DataServiceQuery<Item>)(from item in context.Items select item);
//var query = context.Items
items.LoadCompleted += (sender, args) => Items = items.ToList();
items.LoadAsync(query);
}
If you want use async / await (you need to ) you can use a known method from TaskFactory class : Task.Factory.FromAsync() :
public async Task<IEnumerable<Item>> GetItems1()
{
// Définition de la requête
DataServiceQuery<Item> query = (DataServiceQuery<Item>)(from item in context.Items select item);
var q =Task.Factory.FromAsync(query.BeginExecute(null, null), iAsyncResult =>
{
var results = query.EndExecute(iAsyncResult);
return results;
});
var data = await q;
return new DataServiceCollection<Item>(data);
}
I added extensions methods in the project sample which will allow you to simplify the await / async pattern in WCF DS for WinRT. I have used all the extensions method founded here :
public async Task<IEnumerable<Item>> GetItems()
{
DataServiceQuery<Item> query = (DataServiceQuery<Item>)(from item in context.Items select item);
return await query.ExecuteAsync();
}
The data format used by default with WCF DS is ATOM XML.
XML
JSON
Generate a query to retrieve JSON data is simple. You just have to change the “Accept” header. You can do this like this:
context = new PayNotesEntities(new Uri(ServiceUri));
context.SendingRequest2 += (sender, args) =>
args.RequestMessage.SetHeader("Accept", "application/json;odata=verbose");
Here is the result, from fiddler :
BUT, the WCF DS for WinRT doesn’t handle correctly the Callback of a JSON query …
For your information : https://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/thread/85d99eb9-13ad-4f30-bb6f-966cb5e336f7/
Currently the Windows Store client is a little behind Desktop/Silverlight. You are correct that ATOM is the only format the client can handle currently. I'm not sure about using gzip... I think only the Windows Phone client gives such direct access to the stream.
We are looking at getting the Windows Store and Phone clients at party when Desktop/Silverlight a few rounds from now. In the meantime the only other option I can think of is to drop down a level and use ODataLib directly to parse a JSON verbose response... but then you lose everything else the client gives you
We have to wait for the next release of the WCF DS WinRT SDK (The version 5.1 has this feature enabled, see here for more détails : https://blogs.msdn.com/b/astoriateam/archive/2012/09/26/wcf-data-service-5-1-0-rc2-released.aspx. Currently, WCF Data Services WinRT is the 5.0 version)
JSON Workaround
You can use a workaround if you really want to make a REST request and get JSON data. You need to use an HttpClient request and with the JSON.Net SDK (which can work with dynamic) you can easily parse your JSON data !
// Generate uri
DataServiceQuery<Item> query = (DataServiceQuery<Item>)(from item in context.Items select item);
HttpClient webClient = new HttpClient();
webClient.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
HttpResponseMessage httpResponse = await webClient.GetAsync(query.RequestUri);
string response = await httpResponse.Content.ReadAsStringAsync();
var d = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(response);
Newtonsoft.Json.Linq.JArray jsonArrayOfItems = d.d;
return jsonArrayOfItems.ToObject<List<Item>>();
Adding, Editing, Deleting entities
Addind editing and deleting entities is quite easy :
public async Task SaveChangesAsync(Item item, EntityStates state)
{
switch (state)
{
case EntityStates.Added:
context.AddObject("Items", item);
break;
case EntityStates.Deleted:
context.DeleteObject(item);
break;
case EntityStates.Modified:
context.UpdateObject(item);
break;
}
await context.SaveChangesAsync(SaveChangesOptions.None);
}
Conclusion
JSON support with WCF Data Services for WinRT will be available … soon, as you can read here : https://blogs.msdn.com/b/astoriateam/archive/2012/09/26/wcf-data-service-5-1-0-rc2-released.aspx
context.UseJsonFormatWithDefaultServiceModel();
Here is an other thread (2013-03-15) on the subject : https://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/thread/7c9a5338-be38-443e-a520-e98f9902b4ea
We are currently working on it. Hopefully in the next month or so, you should hear something about this. Sorry, but i cannot provide more details at this point.
Thanks
Pratik
In the next part, we won’t use WCF Data Services, we will make our own methods to query (GET) and update (POST) entities, with XML or JSON format