Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

VS "Orcas": LoginService

ASP.NET 2.0 introduced Membership, Role and Profile providers for storing, validating and managing users' credentials and profiles to the web application development world. While these providers can quite easily be used in the same manner in a desktop application having the database store in the same domain, there is still a significant amount of code you have to write to make your application perform user credentials validation through a remote server (using, let's say, web services).

VS "Orcas" (or more precisely - .NET framework 3.5) brings us Client Application Services, which build up on existing functionality to allow us use these very same features (and more) in our desktop clients, and all communication between client and server would be provided by Windows Communication Foundation (WCF). There's a whole new assembly, dedicated to client services, called System.Web.Extensions, which we'll need when building our sample application. This sample will consist of a simple Login service, residing on a remote server and accessing it's local membership database, and a desktop client, connecting to this service through WCF.

Let's open Visual Studio "Orcas" and begin a new Web Site | WCF Service, called ClientService:

We're going to start with a Login service, which we're going to call whenever user attempts to log in our desktop client. First, we'll remove autogenerated App_Code\Service1.cs file from the project, rename Service1.svc to LoginService.cvs and add System.Web.Extensions.dll to this project's references [you'll find this dll in the c:\Windows\Microsoft.NET\Framework\v3.5.20209\ folder].

Next, edit LoginService.cvs file to make service reference a built-in LoginService class:

<%@ ServiceHost Language=C# Debug="true" Service="System.Web.ApplicationServices.LoginService" %>

We'll also edit your web.config to describe our service and enable ASP.NET compatibility:

<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <services>
        <service name="System.Web.ApplicationServices.LoginService" 
behaviorConfiguration="LoginServiceBehavior"> <endpoint binding="basicHttpBinding" bindingConfiguration=""
name="LoginServiceEndPoint"
contract="System.Web.ApplicationServices.LoginService"/> <endpoint address="MEX" binding="mexHttpBinding"
bindingConfiguration="" name="MEX" bindingName="MEX"
contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="LoginServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> <system.web> <authentication mode="Forms" /> <compilation debug="true"> <assemblies> <add assembly="System.Core, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=B77A5C561934E089"
/> <add assembly="System.Web.Extensions, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"
/> </assemblies> </compilation> </system.web> <system.codedom> <compilers> <compiler language="c#;cs;csharp" extension=".cs"
type="Microsoft.CSharp.CSharpCodeProvider,System, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"
> </compiler> <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
type="Microsoft.VisualBasic.VBCodeProvider, System,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

compilerOptions="/optioninfer+"> </compiler> </compilers> </system.codedom> </configuration>

[just a quick note here: using wsHttpBinding instead of basicHttpBinding would make your WCF channel more secure]

The Login service is now complete, we're ready create our user/Membership database. Choose Website | ASP.NET configuration from the menu to invoke ASP.Net Web Application Administration tool, the same we're used to from building ASP.NET web sites in VS2005:

Click Security and wait a few seconds for membership database file to be created in your web project's App_Data folder. Then switch authentication type from Windows to Forms authentication and create a user or two:

OK, we're done with the server part; we're continuing with a simple test client...

We'll Add a new Windows Forms project to the solution, setting it as the StartUp project and reference our Login Service [Project | Add Service Reference]; in the "Add Service Reference" dialog, clicking on Find button will make our LoginService appear in the list of services:

After confirming service selection, a proxy class will be generated and we can start using our service.

To keep this sample simple, we'll use a simple form button to check our user's credentials, and here's the code:  

LoginServiceClient client = new LoginServiceClient();
if (client.ValidateUser("andrej", "p@ssw0rd", string.Empty))
{
    MessageBox.Show("Validated");
}
if (client.Login("andrej", "p@ssw0rd", string.Empty, true))
{
    MessageBox.Show("Login successful");
}
if (client.IsLoggedIn())
{
    MessageBox.Show("Logged in");
}

We're making three consecutive calls to our LoginService. With the first call, we're just validating users credentials. The second call tries to log in the application and the third call checks if the user is logged in. Note that when using persisting logins you'll have to allow cookies on your client side by modifying a part of your app.config:

...
<
binding name="LoginServiceEndPoint"
...
allowCookies="true"
...
>
...
</binding>
...

We've just set up a simple remote Login service, which allows our desktop client to use the same membership database we could already be using in our web applications. Coming up next: building up a login form, membership and role providers...