The January 2007 CTP version of Visual Studio “Orcas” has .NET FX 3.5 version 3.5.11209. One of the assemblies is System.Web.Extensions and hosts some great new additions to the ASP.NET stack. It has new classes in the namespace System.Web.Security, two of which are LoginService and RolesService. In this post we will take a look at the LoginService.
The LoginService class allows you to perform ASP.NET 2.0 Membership validation through a WCF service. This way other applications can also benefit from your efforts of setting up the membership service and maintaining the member store behind it. Let’s see how you do that:
The LoginService has been decorated by the ServiceContract attribute. Four of its members are opted-in as operations via the OperationContract attribute: IsLoggedIn, Login, Logout and ValidateUser. A small fragment of the class:
Hosting the service
Both the LoginService and RolesService need the services of the ASP.NET pipeline. They indicate so by the AspNetCompatibilityRequirements attribute. This also means that this service must be hosted in IIS, instead of another type of host. Some easy steps are needed:
- Create an ASP.NET Web Site or Application and add a reference to System.ServiceModel.dll and to System.Web.Extensions.dll. You can try all of this in a VPC with the Janurary 2007 build of VS Orcas, or copy the System.Web.Extensions.dll file from the VPC to your .NET 3.0 machine and use Visual Studio 2005 SP1 (I did the latter).
- Add a .svc file (e.g. LoginService.svc) for the WCF service and change the ServiceHost directive to the following:
Note that no CodeBehindFile attribute is needed, since the service type is already compiled.
- Create a web.config (if necessary and add a <system.serviceModel> element:
The bolded part is perhaps the important bit here. This is where the ASP.NET compatibility is enabled. If you do not specify this, the service will not be available.
- Change the authentication mode of ASP.NET to Forms Authentication. You can do this by editing the web.config yourself or the ASP.NET Website Administration Tool, whichever you prefer best. While you’re at it, create one or more test accounts in the Membership store, if you do not have an existing one. Membership is enabled by default, and the AspNetDb.mdf SQL Server Express database should be created automatically in your App_Data folder.
- Save it all and visit the URL http://localhost:1337/ASPNETServicesViaWCF/LoginService.svc, subsituting your port number and site names if needed.
Creating a client
At this point you will have a working WCF service that allows clients to use the Membership services over WCF. Creating a client application is pretty straightforward, with one caveat. Just add a Service Reference and call the WCF service via the generated proxy like so:
The result of this bit of client code shows the following output:
You need to make sure that you allow and enable the client to accept cookies if you want to make use of a persistent login. The configuration is in your binding to the service. It should look like this:
There are also two extensibility points in the service, provided by the two static (!) events Authenticating and CreatingCookie on the LoginService class. Each of these can have a single (although you could attach more: not recommended) handler attached in the global.asax. The constructor of the HttpApplication derived class is a good place to attach the handler to each of the events.
Two possible scenarios are implemented in the code fragment above.
First off, you are able to use custom credentials for your login. These could be used instead of the username and password or complement it. The event arguments for Authenticating give you the user name, password and custom credentials as a set of string properties. The boolean Authenticated property indicates whether the login has succeeded. If you managed to perform authentication the AuthenticationIsComplete should be set to true, or the regular mechanism will kick in (which may be what you want).
The other extensibility point is in the creation of the cookie. The handler for the CreatingCookie event gets arguments of type CreatingCookieEventArgs, that disclose the user name, password, custom credential and whether a persistent cookie should be created. You are given the opportunity to set the cookie yourself. Depending on the circumstances you could decide to not issue a persistent cookie, or alter the username before the cookie is created. However, to do so, you must set the cookie yourself and indicate that you have done so by changing CookieIsSet to true. Also, the cookie that you issue must be a Forms Authentication cookie, containing a encrypted FormsAuthenticationTicket.
Some critical notes
Although the addition of a WCF service that offers Membership authentication is really nice, I do raise some eyebrows to the implementation of the service. As good practice dictates the service interface should be separated from the implementation. But, it is not. This makes the use of the service less flexible. You will not be able to substitute your own alternative implementation of the same interface. Then again, remember this is a CTP implementation, and the LoginService might or might not make it into the final release as it is now (or at all). Also, what will the plans be for the Login service that the Microsoft AJAX Library 1.0 makes use of? We’ll see. Time will tell.