*Moved to: http://fluentbytes.com/using-authenticated-ria-services-on-your-wp7-phone/
Currently I am working with some colleagues to build a demo application that consists out of a back office application and a mobile application that runs
on IPhone, IPad, Android and Windows Phone 7. We decided to build the simulation of the back office using RIA services since that gives the fastest results
if it comes to building CRUD like services and exposing them in a easy and authenticated way. Since all Phone platforms can be targeted using C# with the
Novel Mono development environments, we thought it would be nice to show how we can use the RIA services exposed as a SOAP endpoint.
since we want to simulate a real life scenario where you always need to authenticate the end-user before you serve him with some data, we also wanted to
enable authentication on the services.
So we build an easy data model using the Entity Framework that represents the notion of a Asset Tracking system, where users can register assets and
share them amongst their peers. when you wan to know where your assets are, you can access them on your mobile device and query there whereabouts.
Also when you acquire an asset, you can register it at the service and provide location information using longitude and latitude using a Map control and
leveraging phone location awareness.
The data model looks like follows:
I Created two simple domain service classes. One to manage the authentication using the ASP.NET membership API and on that contains the three entities.
To manage authentication I provided a database with the ASP.NET schema in it and configured it in the web.config file.
My system.web part of the configuration file looks as follows to enable the authenticated service calls:
1: <system.web>
2: <authentication mode="Forms" >
3: <forms loginUrl="~/WebForm1.aspx"/>
4: </authentication>
5: <membership defaultProvider="MySqlMembershipProvider" >
6: <providers>
7: <clear/>
8: <add name="MySqlMembershipProvider"
9: connectionStringName="WaarIsIConnection"
10: applicationName="MyAppName"
11: type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" />
12: </providers>
13: </membership>
14:  
15: <httpModules>
16: <add name="DomainServiceModule" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule,
System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
17: </httpModules>
18: </system.web>
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
 
And I added the SOAP endpoint, so I could query my domain service for it’s service contract.
1: <system.serviceModel>
2: <domainServices>
3: <endpoints>
4: <add name="Soap" type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory,
Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
5: </endpoints>
6: </domainServices>
7: <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
8: </system.serviceModel>
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
 
In order to be able to filter the requested entities for a specific user, I added the UserName property to each entity. While not an ideal solution, this suffices for this demo.
Next is to make sure the service operations are only returning data for the current authenticated user. this is shown in the below code sample:
1: [RequiresAuthentication]
2: [EnableClientAccess()]
3: public class WaarIsIDomainService : LinqToEntitiesDomainService<WaarIsIContainer>
4: {
5: [Query(IsDefault = true)]
6: public IQueryable<Asset> GetAssets()
7: {
8: return this.ObjectContext.Assets.Where(asset => asset.UserName == ServiceContext.User.Identity.Name) ;
9: }
10: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
So now I have my domain service I can create my Phone application, and I will show you how you can call the RIA services in an authenticated way.
First you add a service reference to the domain service that provides you the entities you are intereseted in. In this example that results in a service reference
that generates a proxy that contains all the operations I can use at the client. Because I Use Ria Services, all service calls follow the async pattern. So my
GetAssets operation is available in the generated proxy as GetAssetsAsync() and you set up an event handler for the GetAssetsCompleted event.
This looks like follows in code:
1: WaarIsIDomainServiceSoapClient proxy = new WaarIsIDomainServiceSoapClient();
2: proxy.GetAssetsCompleted += new EventHandler<GetAssetsCompletedEventArgs>(proxy_GetAssetsCompleted);
3: proxy.GetAssetsAsync();
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
 
The only problem with this code is that it will generate an exception, since I did not authenticate myself to the service.
to solve this problem, you also need a service reference to the AuthenticationDomain service. So next you generate a proxy for that SOAP endpoint as well
and that will result in a generated proxy you can call to login. Now when you search on this topic, you will find all kinds of posts telling that RIA services is not
supported on the phone, but the fact is that it is nothing more then a WCF service and we know it uses a cookie to authenticate each next request after you log in.
So with that knowledge you can configure the binding you need with just WCF configuration. Since we use the ASP.NET forms authentication protocol behind the scenes,
the only thing you need to do is enable the CookieContainers on the bindings of the services that got generated. This looks as follows for your phone client.config file
1: <system.serviceModel>
2: <bindings>
3: <basicHttpBinding>
4: <binding name="BasicHttpBinding_WaarIsIDomainServiceSoap" maxBufferSize="2147483647"
5: maxReceivedMessageSize="2147483647" enableHttpCookieContainer="true">
6: <security mode="None" />
7: </binding>
8: <binding name="BasicHttpBinding_AuthenticationDomainServiceSoap"
9: maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" enableHttpCookieContainer="true">
10: <security mode="None" />
11: </binding>
12: </basicHttpBinding>
13: </bindings>
14: <client>
15: <endpoint address="http://localhost:1082/Services/MobileBackoffice-Web-Services-WaarIsIDomainService.svc/Soap"
16: binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_WaarIsIDomainServiceSoap"
17: contract="ServiceReference1.WaarIsIDomainServiceSoap" name="BasicHttpBinding_WaarIsIDomainServiceSoap" />
18: <endpoint address="http://localhost:1082/Services/MobileBackofficeApplication-Web-AuthenticationDomainService.svc/Soap"
19: binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_AuthenticationDomainServiceSoap"
20: contract="Authenticationservice.AuthenticationDomainServiceSoap"
21: name="BasicHttpBinding_AuthenticationDomainServiceSoap" />
22: </client>
23: </system.serviceModel>
 
Now that we have enabled the authentication protocol we need to first call the AuthenticationDomain proxy and authenticate the user. Next wait for the asynchronous response and then when the logon was successful add the cookies from the proxy that got returned to the proxy that is going to make then next call.
This looks as follows in code:
1: public void LoadData()
2: {
3: AuthenticationDomainServiceSoapClient authenticationProxy = new AuthenticationDomainServiceSoapClient();
4: authenticationProxy.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(authenticationProxy_LoginCompleted);
5: authenticationProxy.LoginAsync("marcelv", "*********", false, null);
6: }
7:  
8: void authenticationProxy_LoginCompleted(object sender, LoginCompletedEventArgs e)
9: {
10: if (e.Error == null)
11: {
12: AuthenticationDomainServiceSoapClient authproxy = sender as AuthenticationDomainServiceSoapClient;
13: // copy the response auth coockie and add save it for subsequent calls
14: authenticationCookie = authproxy.CookieContainer;
15:  
16: WaarIsIDomainServiceSoapClient proxy = new WaarIsIDomainServiceSoapClient();
17: // add the coockie container to the new request proxy for the actual GetAssets call
18: proxy.CookieContainer = authenticationCookie;
19: proxy.GetAssetsCompleted += new EventHandler<GetAssetsCompletedEventArgs>(proxy_GetAssetsCompleted);
20: proxy.GetAssetsAsync();
21: }
22: }
23:  
24: void proxy_GetAssetsCompleted(object sender, GetAssetsCompletedEventArgs e)
25: {
26: if (e.Error == null)
27: {
28: // RIA services return an observable collection of entities, but my grid is already bound to an
29: // observable collection. So I just add the returned items to the existing container.
30: foreach (var item in e.Result.RootResults)
31: {
32: this.Items.Add(item);
33: }
34: this.IsDataLoaded = true;
35: }
36: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
 
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
And this all results in the final proof of concept that I can use authenticated RIA services on my Window Phone 7 Device. Result is shown below:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Hope this helps,
cheers,
Marcel
Follow my new blog on http://fluentbytes.com