Skip to content

Using the ASP.NET Membership Provider and Authentication Service from Windows Phone 7

by Kevin Hoffman on August 6th, 2010

Those of you who have been building ASP.NET applications for a while now are no doubt familiar with the provider model, which includes provider abstractions for membership (authentication), roles (authorization), profiles (user data), and session state. These providers make it incredibly easy to provide a secure framework for your application. In fact, with an ASP.NET application template right out of the box, you can have a fully functioning authenticated, secure website in minutes.

What a lot of people have less familiarity with is the notion of provider services. You can actually create a WCF service head that sits on top of the ASP.NET membership system. This allows client applications to authenticate against your ASP.NET website using exactly the same authentication scheme that your users use. This means that a user who has access to your website should also be able to have access to the client application seamlessly.

To see how this works, create yourself a new ASP.NET MVC app (you can do this with a regular ASP.NET app, but I just happened to use MVC). Before doing anything, run the app, go to the “Log On” area, register yourself as a user and then quit the app. If you’ve got SQL Express installed properly and everything else is in order, your app now knows who you are.

Next, add a new WCF service to this application (call it Authentication.svc). Delete the files Authentication.svc.cs and the IAuthentication.cs. Open up the Authentication.svc file and replace it’s contents entirely with the following:

<%@ ServiceHost Language="C#"
    Service="System.Web.ApplicationServices.AuthenticationService" %>

Note here that there’s no code-behind. All we’re doing is exposing a service that is already part of the ASP.NET framework at a specific endpoint. You’re not quite ready yet – we have to make this service ASP.NET compatible, so open up your Web.config file and make sure that your system.servicemodel section looks like this:

<system.serviceModel>
 <services>
 <service name="System.Web.ApplicationServices.AuthenticationService"
behaviorConfiguration="AuthenticationServiceBehaviors">
 <endpoint contract="System.Web.ApplicationServices.AuthenticationService"
     binding="basicHttpBinding" />
 </service>
 <service name="Wp7AspNetMembership.HelloService"
     behaviorConfiguration="AuthenticationServiceBehaviors">
 <endpoint
     contract="Wp7AspNetMembership.IHelloService"
     binding="basicHttpBinding"/>
 </service>
 </services>
 <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
     multipleSiteBindingsEnabled="true" />
 <behaviors>
 <serviceBehaviors>
 <behavior name="AuthenticationServiceBehaviors">
 <serviceMetadata httpGetEnabled="true" />
 </behavior>
 <behavior name="">
 <serviceMetadata httpGetEnabled="true" />
 <serviceDebug includeExceptionDetailInFaults="false" />
 </behavior>
 </serviceBehaviors>
 </behaviors>
 </system.serviceModel>

 <system.web.extensions>
 <scripting>
 <webServices>
 <authenticationService enabled="true" requireSSL="false"/>
 </webServices>
 </scripting>
 </system.web.extensions>

What’s going on in this Web.config file is pretty interesting. First, we’re exposing Authentication.svc and HelloService.svc (not yet created) over HTTP, with metadata allowed, with ASP.NET compatibility enabled. We’ve also used the system.web.extensions element to indicate that the authentication service is being enabled. In a production environment, you would set requireSSL to true.

At this point, you should be able to hit the URL /Authentication.svc and see the standard metadata page. Now let’s create HelloService.svc by creating a standard WCF service. Change the interface so it only has a single method called HelloWorld() that returns a string. The following is the implementation of HelloService.svc.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Web;
using System.ServiceModel.Activation;

namespace MvcApplication1
{
 [AspNetCompatibilityRequirements(
    RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
 public class HelloService : IHelloService
 {
  public string HelloWorld()
  {
   if (HttpContext.Current.User.Identity.IsAuthenticated)
     return HttpContext.Current.User.Identity.Name;
   else
     return "Unauthenticated Person";
  }
 }
}

This is a pretty simple service. Just pretend that instead of returning the name of the authenticated user, we’re actually performing some vital business function that requires a valid user context.

Now, we can get to the good stuff : the WP7 application :) In this WP7 application we’re going to create a login form, submit user credentials over the wire, get validation results and, if the user was authenticated, we’re going to call the HelloWorld() method with a validated, secure context – all of this with an incredibly small amount of work on the part of the WP7 client.

Add a new WP7 application (just the stock one, not the list view) to the solution, I called mine TestMembershipClient but you can pick whatever you like. Add service references to Authentication.svc and to HelloWorld.svc (I named the reference namespaces MvcWebAppReference for authentication and AspNetMvcRealReference for the service that simulates doing real work).

On your main page, drop a couple text block labels, two text boxes, and a submit button. When you run the app at this point, it should look like this screenshot:

WP7 Login Form

WP7 Login Form

Now rig up a click handler for the submit button with code that looks like this:

private void LoginButton_Click(object sender, RoutedEventArgs e)
{
 MvcWebAppReference.AuthenticationServiceClient authService =
   new MvcWebAppReference.AuthenticationServiceClient();
 cc = new CookieContainer();
 authService.CookieContainer = cc;
 authService.LoginCompleted +=
   new EventHandler<MvcWebAppReference.LoginCompletedEventArgs>(
 authService_LoginCompleted);
 authService.LoginAsync(UsernameBox.Text, PasswordBox.Text, "", true);
}

void authService_LoginCompleted(object sender,
 MvcWebAppReference.LoginCompletedEventArgs e)
{
 if (e.Error != null)
 {
 MessageBox.Show("Login failed, you Jackwagon.");
 }
 else
 {
   AspNetMvcRealReference.HelloServiceClient helloService =
    new AspNetMvcRealReference.HelloServiceClient();
   helloService.CookieContainer = cc;
   helloService.HelloWorldCompleted +=
   new EventHandler<AspNetMvcRealReference.HelloWorldCompletedEventArgs>(
     helloService_HelloWorldCompleted);
   helloService.HelloWorldAsync();
 }
}

void helloService_HelloWorldCompleted(object sender,
 AspNetMvcRealReference.HelloWorldCompletedEventArgs e)
{
 MessageBox.Show("You're logged in, results from svc: " + e.Result);
}

Most of this is pretty straightforward. When the user clicks the submit button, it calls the LoginAsync method on the membership service (remember that all service calls in Silverlight are asynchronous). When we get the results of that call, we either tell the user that their login has failed, or we invoke the HelloWorld method (also asynchronously). When the hello world method comes back from the server, we display the results of the execution in a message box that looks like the one in the screenshot below:

Results of Calling a Secured Service from WP7

Results of Calling a Secured Service from WP7

One thing to take very careful note of is the CookieContainer. Because we’re using two different proxies: 1 to talk to the authentication service and 1 to talk to the hello world service, we have to ensure that these two proxies are using the same cookie container so that the auth cookie can be used by subsequent method calls on other services. You can do this for an unlimited number of services that are on the same DNS domain, so long as they all share the same cookie container. To enable the use of cookie containers in WCF services in Silverlight (it’s disabled by default), you have to set the enableHttpCookieContainer property to true. in the binding element in the ServiceReferences.ClientConfig file.

On the surface you might not think this is all that big of a deal. You might also think this is difficult but, keep in mind that I provided a pretty detailed walkthrough. This whole thing only took me about 15 minutes to set up from start to finish once I’d figured out how the CookieContainer thing worked. So why bother with this?

Consider this: If you already have an ASP.NET application that is using the membership provider, role provider, and profile provider you can quickly, easily, and securely expose services to a mobile (WP7) client that allow that client to have secured, remote access to services exposed by that site. In short, any user of your existing web application can use their existing credentials to log in from their WP7 device and access any services you decide to make available.

ASP.NET provider services, coupled with WP7 and the fact that Silverlight has access to WCF client proxy generation, means you can very easily prep your site for a rich WP7 experience.

From → Mobile

  • Pingback: Tweets that mention Using the ASP.NET Membership Provider and Authentication Service from Windows Phone 7 | Kotan Code 枯淡コード -- Topsy.com

  • mikehole

    One thing I found missing here is that you will have to enable the cookie container for the web reference in the ServiceReferences.ClientConfig file:

    I added in enableHttpCookieContainer=”true” as you see above!

    • mikehole

      doh it’s removed the xml!

      <binding name=”BasicHttpBinding_AuthenticationService” maxBufferSize=”2147483647″ enableHttpCookieContainer=”true”
      maxReceivedMessageSize=”2147483647″>
      <security mode=”None” />
      </binding>

  • Kevin Hoffman

    Yes I could’ve sworn I included that in the original post. the enableHttpCookieContainer is absolutely required.

    • mikehole

      Oh thanks for the post by the way sure has helped me out!

  • Kevin Hoffman

    Here it is, from the post above:


    To enable the use of cookie containers in WCF services in Silverlight (it’s disabled by default), you have to set the enableHttpCookieContainer property to true. in the binding element in the ServiceReferences.ClientConfig file.

    I guess I just didn’t make that paragraph stand out as much as I should’ve.

  • http://DNAfor.NET chauey

    Great article!

    I was wondering if we can just use the same WCF service from creating a Silverlight Business application that I think already has a WCF login service? Can we use the same without any config changes?

    2nd question is does your example force the user to log in again each time the app is launched; does the app have a way to remember the user so that they don’t need to login the next time?

    Thanks.

  • http://DNAfor.NET chauey

    BTW, also, to log out, do we call the WCF to logout or do we just remove the cookie on the wp7 app, or both? can you provide your thoughts on this. Thanks ;)

    • Kevin Hoffman

      If you call the WCF service to log out, it will destroy the cookie. If you remove the cookie, the server will think you’re logged out. Either way, I think it’s fine so it’s up to you.

  • Pingback: Дайджест технических материалов #5 (Windows Phone 7) - Oleksandr Krakovetskiy blog - Microsoft User Group Винница

  • Pingback: Using the ASP.NET Membership Provider and Authentication Service from Windows Phone 7 « Vincent Leung .NET Tech Clips

  • Depechie

    Nice post and good example… but when I try it out, it works fine in the emulator, but not on the phone.
    Any ideas? I get Not authenticated exception on the phone ( with the same code )

  • Kevin Hoffman

    One thing that comes to mind is that your browser settings on the phone are set to prevent cookie storage.

    • Depechie

      Thanks for the quick response ;)
      But I don’t think that is the case… IE settings are:

      * Allow cookies on my phone : true
      * Website preference : Mobile version

      Any other suggestions? Maybe try it out on your phone or something?

    • Depechie

      By the way, the authService_LoginCompleted returns true without error, it are the other calls to the other services that are failing…
      But I’m using the same cookiecontainer. And on the emulator everything works just fine :(

    • Depechie

      Or do you have a test webservice somewhere ( with a demo wp7 app ), so I could try that?

      • Kevin Hoffman

        I know this has already been mentioned but, have you set enableCookieContainer to true in the client reference configuration file? If not, then I will try and dig up the code I wrote for this and verify that it works on my phone. Stand by.

      • Kevin Hoffman

        I found -a- problem, I don’t know if its yours. When you follow the instructions I gave you, the ServiceReferences.ClientConfig file refers to the remote service via URL on localhost. This works fine in the simulator because the simulator is on the same box as the MVC application hosting the services. I modified the ServiceReferences.ClientConfig file to point at the host name of my computer and was able to do this demo over WiFi from my phone.

        • Depechie

          Kevin, again thanks for the effort, but again twice a negative response…

          I did have the binding enableHttpCookieContainer=”true”
          And the URL’s of the service are pointing to my online hosting site.

          Any chance for exchanging more details?
          Could you mail me at contact.depsoft@gmail.com ?

          I would love to test my wp7 app against your service and maybe you could test your wp7 test app against my service?
          Would this be possible?
          I’m also on twitter as @Depechie

        • Depechie

          Ok… I don’t know why, but I removed all config settings and service references, set everything back and now it works…………. No idea why!

          Thanks for the help and tips!

  • Pingback: 超快递 beta版 » Windows Phone 7 资源汇总(超全)

  • Pingback: Is it possible to use encrypted webservices in WP7, that do not rely on HTTPS for encryption? | Technical support, Computer, programming issue, issue tracking, quality assurance

  • Błażej Wdowikowski

    Hello I’m trying to follow by yours tutorial, but I stuck at HelloService I get error ” Error 1 ‘HelloService.HelloService’ does not implement interface member ‘HelloService.IHelloService.GetDataUsingDataContract(HelloService.CompositeType)’”

    What you can tell about it?

  • Gert

    Thanks for the article! Works like a charm! :-)

  • Pingback: Windows Phone 7 资源汇总 | DanceCoder

  • Rene_titulaer

    I can’t get it to work. I don’t get the authentication cookie. After calling the authentication service the cookie container should be filled I assume bit it isn’t (cc, should have 1 item I assume but it’s 0).
    According to the following article it isn’t possible: http://social.msdn.microsoft.com/Forums/is/wcf/thread/09e95c12-ffc2-48ce-99ce-e4181d6c6156
    Within SDK 7.1. Can it be that it worked before but that it doesn’t anymore?

    Note: I did set enableHttpCookieContainer=”true”

    • Rohith

      Hi.. I am encountering the same problem. I did follow the entire step, but still I couldnt get the cookie. Did you solve this?