(X) Hide this
    • Login
    • Join
      • Say No Bots Generate New Image
        By clicking 'Register' you accept the terms of use .
        Login with Facebook

Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight

(1 votes)
12 comments   /   aggregated from Brad Abrams on May 03, 2008   /   original article
Categories:   General

In ASP.NET 2.0, we introduced a very powerful set of application services in ASP.NET (Membership, Roles and profile).  In 3.5 we created a client library for accessing them from Ajax and .NET Clients and exposed them via WCF web services.    For more information on the base level ASP.NET appservices that this walk through is based on, please see Stefan Schackow excellent book Professional ASP.NET 2.0 Security, Membership, and Role Management.

In this tutorial I will walk you through how to access the WCF application services from a directly from the Silverlight client.  This works super well if you have a site that is already using the ASP.NET application services and you just need to access them from a Silverlight client.    (Special thanks to Helen for a good chunk of this implantation)

Here is what I plan to show:

1. Login\Logout
2. Save personalization settings
3. Enable custom UI based on a user's role (for example, manager or employee)
4. A custom log-in control to make the UI a bit cleaner

image

You can download the completed sample solution

 

 

Part I: Login\Logout

In VS, do File\New select the Silverlight solution.  Let's call it "ApplicationServicesDemo".

image

We will need both the client side Silverlight project and the ASP.NET serverside project. 

image

 

Let's configure our system with the test users.  To do this we will use the ASP.NET Configuration Manager.  In VS, under the Website menu, select "ASP.NET Configuration". Use this application to add a couple of users.  I created two employees:

ID:manager
password:manager!
and
ID:employee
password:employee!

image

 

To expose the ASP.NET Authentication system, let's add a new WCF service.  Because we are just going to point this at the default one that ships with ASP.NET, we don't need any code behind, so the easiest thing to do is to add a new Text File.  In the ASP.NET website, Add New Item, select Text File  and call it "AuthenticationService.svc"

image

Add this one line as the contents of the file.  This wires it up to the implementation that ships as part of ASP.NET.

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


Now in Web.config, we need to add the WCF magic to turn the service on.

  <system.serviceModel>
    <services>
      
      <service name="System.Web.ApplicationServices.AuthenticationService"
               behaviorConfiguration="AuthenticationServiceTypeBehaviors">
        <endpoint contract="System.Web.ApplicationServices.AuthenticationService"
                  binding="basicHttpBinding" bindingConfiguration="userHttp"
                  bindingNamespace="http://asp.net/ApplicationServices/v200"/>
      service>

    services>
    <bindings>
      <basicHttpBinding>
        <binding name="userHttp">
          
          <security mode="None"/>
        binding>
      basicHttpBinding>
    bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="AuthenticationServiceTypeBehaviors">
          <serviceMetadata httpGetEnabled="true"/>
        behavior>
      serviceBehaviors>
    behaviors>
    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
  system.serviceModel>

Now, still in Web.config, we need to enable forms authentication.  Under the change the authentication mode from "Windows" to "Forms".

<authentication mode="Forms" />

 

One last change to web.config, we need to enable authentication to be exposed via the web service.This is done by adding a System.Web.Extensions section.

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

 


Now, to consume this authentication service in Silverlight, let's open the page.xaml file and add some initial UI. Just buttons to log "employee" and "manager"  in and a textblock to show some status. 

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <Button x:Name="employeeLogIn" 
                    Width="100" Height="50" 
                    Content="Log In Employee" 
                    Click="employeeLogIn_Click">Button>
            <Button x:Name="managerLogIn" 
                    Width="100" Height="50" 
                    Content="Log In Manager" 
                    Click="managerLogIn_Click">Button>
            <TextBlock x:Name="statusText">TextBlock>
        StackPanel>
    Grid>


Now, let's add a reference to the service we just created

Right click on the Silverlight project and select Add Service Reference

image

Click Discover and set the namespace to "AuthenticationService"

image

If you get an error at this point, it is likely something wrong with your AuthenticationService.svc or the web config, go back and double check those. 

 

Now, let's write a little code to call that service to log us in.  First add the right using statement

using ApplicationServicesDemo.AuthenticationServices;

Then, in employeeLogIn_Click method write the code to call the service to log the employee in.  For now, we will hard code the name in password, but by the end we will be prompting the user to get this data.

First we create a the web services client class, then we call the login method asynchronously.  Remember all network calls in Silverlight are async, otherwise we'd lock up the whole browser.  Finally we sign up for the callback.

private void employeeLogIn_Click(object sender, RoutedEventArgs e)
{
    AuthenticationServiceClient client = new AuthenticationServiceClient();
    client.LoginAsync("employee", "employee!", "", true, "employee");
    client.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(client_LoginCompleted);
}

In the callback, for now, let's just set our status.

void client_LoginCompleted(object sender, LoginCompletedEventArgs e)
{
    if (e.Error != null) statusText.Text = e.Error.ToString();
    else statusText.Text = e.UserState + " logged In result:" + e.Result;
}

Run it!  You should see a good status.  Try changing the password and ID, and see the status change to false.  It is working.

image

Now do the same thing for manager and you are set!

 

private void managerLogIn_Click(object sender, RoutedEventArgs e)
{
    AuthenticationServiceClient client = new AuthenticationServiceClient();
    client.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(client_LoginCompleted);
    client.LoginAsync("manager", "manager!", "", true, "manager");
}

Part 2: Save Personalization Settings

In this part I will show how to leverage the ASP.NET profile system to store and retrieve data tied to a particular user.  The beautiful thing about this is there is no explicit database configuration required.

First, let's go back to the ASP.NET server project and add the ProfileService.svc.  The easiest way to do this might be to copy the AuthenticationService.svc change the file name and then change the contents as show below. 

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

Now, we need to enable the service via WCF configuration in web.config.  This looks just like the config for the prfofile service.  In the system.serviceModel\services section add a new node.

      
      <service name="System.Web.ApplicationServices.ProfileService"
               behaviorConfiguration="ProfileServiceTypeBehaviors">
        <endpoint contract="System.Web.ApplicationServices.ProfileService"
                  binding="basicHttpBinding" bindingConfiguration="userHttp"
                  bindingNamespace="http://asp.net/ApplicationServices/v200"/>
      service>

and in the system.serviceModel\behaviors\serviceBehaviors add a new node

        <behavior name="ProfileServiceTypeBehaviors">
          <serviceMetadata httpGetEnabled="true"/>
        behavior>


Now we need to configure the profile system.  Again, in web.config add a section listing all the profile properties.  In the System.web section, add the following node.

    <profile>
      <properties>
        <add name="Color" type="string" defaultValue="Red" />
      properties>
    profile>

 

Now we need to enable profile service to be accessed from the webservice. To do this, add the following node to the system.web.extensions\scripting\webservices section.

        <profileService enabled="true" 
                        readAccessProperties="Color" 
                        writeAccessProperties="Color"/>

Now, let's go to the Silverlight client and add a reference to this service.  This is the same as we did authentication service. Add Service Reference, Discover and select the profileService. 

image

Now, we need to add a little UI to the page.xaml in order to give us a way to view and edit the personalized setting.

            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                <TextBlock>Favorite Color: TextBlock>
                <TextBox x:Name="colorNameBox" Width="100" Height="25">TextBox>
                <Button x:Name="submitButton" Width="50" Height="25" 
                        Content="submit" Click="submitButton_Click">
Button> StackPanel>

Now, let's extend loginComplete to retrieve all the profile properties for the user that just logged in.   Again, we need to do that asynchronously so we don't block the browser.

void client_LoginCompleted(object sender, LoginCompletedEventArgs e)
{
    if (e.Error != null) statusText.Text = e.Error.ToString();
    else
    {
        statusText.Text = e.UserState + " logged In result:" + e.Result;
        ProfileServiceClient client = new ProfileServiceClient();
        client.GetAllPropertiesForCurrentUserAsync(false);
        client.GetAllPropertiesForCurrentUserCompleted += new EventHandler<GetAllPropertiesForCurrentUserCompletedEventArgs>(client_GetAllPropertiesForCurrentUserCompleted);
    }
}

When we get the property values back, we just set the LayoutRoot to have that background.

void client_GetAllPropertiesForCurrentUserCompleted(object sender, GetAllPropertiesForCurrentUserCompletedEventArgs e)
{
    if (e.Error == null)
    {
        colorNameBox.Text = e.Result["Color"];
        ChangeBackgroundColor(e.Result["Color"]);
    }
}

private void ChangeBackgroundColor(string colorName)
{
    SolidColorBrush brush = new SolidColorBrush();
    switch (colorName.ToLower())
    {
        case "black":
            brush.Color = Colors.Black;
            break;
        case "blue":
            brush.Color = Colors.Blue;
            break;
        case "brown":
            brush.Color = Colors.Brown;
            break;
        case "green":
            brush.Color = Colors.Green;
            break;
        case "orange":
            brush.Color = Colors.Orange;
            break;
        case "purple":
            brush.Color = Colors.Purple;
            break;
        case "yellow":
            brush.Color = Colors.Yellow;
            break;
        case "red":
            brush.Color = Colors.Red;
            break;
        case "white":
        default:
            brush.Color = Colors.White;
            break;
    }
    LayoutRoot.Background = brush;
}

Finally, when the submit button is pressed we need to set the value on the server.. for completeness, I show waiting until the result comes back from the server before setting the background locally. 

private void submitButton_Click(object sender, RoutedEventArgs e)
{
    ProfileServiceClient client = new ProfileServiceClient();
    Dictionary<string, object> properites = new Dictionary<string,object>();
    properites.Add("Color",colorNameBox.Text);
    client.SetPropertiesForCurrentUserAsync(properites, false, properites);
    client.SetPropertiesForCurrentUserCompleted += new EventHandler<SetPropertiesForCurrentUserCompletedEventArgs>(client_SetPropertiesForCurrentUserCompleted);
}

void client_SetPropertiesForCurrentUserCompleted(object sender, SetPropertiesForCurrentUserCompletedEventArgs e)
{
    Dictionary<string, object> properites = e.UserState as Dictionary<string, object>;
    ChangeBackgroundColor((string)properites["Color"]);
}

 

The end result looks good!  Notice the employee and the manager can each have different values for color. 

image

image

 

Part 3. Enable Custom UI Based on a User's Role

In this section, we want to customize the UI to display differently based on the users role. 

To start off, let's go back to the websites management tool (WebSite\ASP.NET Configuration) and setup a "Management" role and add our "manager" user in that role.

image

image

Now we follow the same three step pattern as all the other services. 

First, we add the service, this time called RoleService.svc with the following contents

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

Then add enable this service via WCF in web.config:

      
      <service name="System.Web.ApplicationServices.RoleService"
               behaviorConfiguration="RoleServiceTypeBehaviors">
        <endpoint contract="System.Web.ApplicationServices.RoleService"
                  binding="basicHttpBinding" bindingConfiguration="userHttp"
                  bindingNamespace="http://asp.net/ApplicationServices/v200"/>
      service>
and
        <behavior name="RoleServiceTypeBehaviors">
          <serviceMetadata httpGetEnabled="true"/>
        behavior>
      serviceBehaviors>

Then we need to enable the roles service for this site.  In web.config, under system.web add:

<roleManager enabled="true"/>

Final change to web.config, we expose it via web services in web.config under System.web.extensions\scripting\webServices add:

        <roleService enabled="true"/>

 

Now, we just need to consume this on the client.  Add Service Reference\Discover, select the role service

image

Now, let's add some UI tweaks.  In this case I am going to add an image that will change based on the role of the user logged in.   So to do that, I add a image tag to the page.xaml

            <Image x:Name="roleImage" Source="notLoggedIn.jpg" Width="200">Image>

Then, I need to go in and add to what happens with the user logs in... We need to go and see what roles they are in.  So we add the following code to client_LoginCompleted(). 

if (e.Result == true) { // if log in successful
    RoleServiceClient roleClient = new RoleServiceClient();
    roleClient.GetRolesForCurrentUserAsync();
    roleClient.GetRolesForCurrentUserCompleted += new EventHandler<GetRolesForCurrentUserCompletedEventArgs>(roleClient_GetRolesForCurrentUserCompleted);
}

and when the callback comes back, we chose the right image based on the roles of the user that logged in.

void roleClient_GetRolesForCurrentUserCompleted(object sender, GetRolesForCurrentUserCompletedEventArgs e)
{
    if (e.Result.Contains("Management"))
    {
        roleImage.Source = new BitmapImage(new Uri("bossRole.jpg", UriKind.Relative));
    }
    else
    {
        roleImage.Source = new BitmapImage(new Uri("employee.jpg", UriKind.Relative));
    }
}
 

Now you can run it and see the results!

 

Not logged in

image

Management role:

image

Logged in, but not in a management role:

image

 

Part 4. A Custom log-in control

A developer on my team built a very cool little log in control that makes it easier to log in.  So let's replace the lame test buttons we have been using with this new log-in control.

Add the LoginControl project to your solution

image

Add a project reference from the silverlight project to the LogIn controls project

image

Add the xmlns:my tag for the login control

image

Then, remove the manager login and employee login buttons and replace them with

            <my:Login x:Name="loginControl" 
                      LoginClick="loginControl_LoginClick"
                      LogoutClick="loginControl_LogoutClick"
                      >my:Login>

The implementing of loginClick is very easy.  It uses the login_Complete we have already written above.

private void loginControl_LoginClick(object sender, RoutedEventArgs e)
{
    AuthenticationServiceClient client = new AuthenticationServiceClient();
    client.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(client_LoginCompleted);
    client.LoginAsync(loginControl.UserName, loginControl.Password, "", true, loginControl.UserName);
}

Notice we also add logout for completion. 

private void Login_LogoutClick(object sender, RoutedEventArgs e)
{
    ServiceReference1.AuthenticationServiceClient client = new ServiceReference1.AuthenticationServiceClient();
    client.LogoutAsync();
    client.LogoutCompleted += new EventHandlerAsyncCompletedEventArgs>(client_LogoutCompleted);
}

void client_LogoutCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
    loginControl.IsLoggedIn = false;
    statusText.Text = "Logged out";
    ChangeBackgroundColor("white");
    roleImage.Source = new BitmapImage(new Uri("notLoggedIn.jpg", UriKind.Relative));
    colorNameBox.Text = "";
loginControl.ClearPassword(); }

 

Now we are done!  you can log in and out as any user.  have fun!

 

image

image

 

You can download the completed sample solution


Subscribe

Comments

  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by Karen on May 07, 2008 07:37
    Can I keep WCF service separately from Web and has autontication, profile and role access in WCF from web site's web config. I have written site with ASP.NET autontication, profile and role providers. Now I have added SilverLight which has to have access to loged in user's profile. I use WCF to get access to profile. But nothing happen because WCF and Web different projects and have different Web.config files. What can I do ?
  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by vitya on Jun 03, 2008 08:42

    Hi,

    I couldn't find any resources on how to do the authentication if the user accounts are not "hardcoded" on the server. I have my users' data stored in SQL and (I guess) I would like to use my own authentication (forms authentication, within Silverlight). Is this at all possible? Can you point me to the right direction?

    Thanks

  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by Asad on Jun 27, 2008 09:51

    The users login through a web form. How can you get the current user's ID in the silverlight application? The authentication service doesn't expose any methods that allow you to get the user's ID, it only tells you if a user is logged in or not. I am using silverlight 2 beta 2.

    Thanks!

  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by Hi on Sep 26, 2008 13:54

    how can I add new users from the web page? Surely, I don't want to go to WebSite\ASP.NET Configuration everytime to add new users. I am looking for a servie that allwes me to add a user from silverligth.

    Thanks!                     PS: Your turotial was very userful.

  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by Matti on Mar 31, 2009 13:22
    Hi,
    Thanks for the nice demo. It works perfectly as long as I'm using the VS Development server. However, if I try to change the server to my local IIS (5.1, on XP) it stops working. I have the clientaccesspolicy.xml in the web root and I can see that it gets read fine. I have changed the endpoint in the ServiceReferences.ClientConfig to point to the correct location. I am able to consume othe WCF services but have no luck with the AuthenticationService. Any suggestions? Thank you.
  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by Henry on Dec 30, 2009 17:16

    There seems to be an issue with the url specified in the endpoint (in the web.config) - http://asp.net/ApplicationServices/v200 results in a 404 error, and thus causes VS to generate warnings at compile time.

    Any ideas how to overcome this?

  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by Henry on Dec 30, 2009 17:16

    There seems to be an issue with the url specified in the endpoint (in the web.config) - it results in a 404 error, and thus causes VS to generate warnings at compile time.

    Any ideas how to overcome this?

  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by sauvesean on Feb 11, 2010 20:50

    "There seems to be an issue with the url specified in the endpoint (in the web.config) - http://asp.net/ApplicationServices/v200 results in a 404 error, and thus causes VS to generate warnings at compile time.

    Any ideas how to overcome this?"

    Are you using a non-default SQL database?  If so, you will get a NotFound error on EndLoggedIn.  To solve this, you must edit global.asax.  If you don't have global.asax on your web application, add a new item called "Global Application Class"

    <%@ Application Language="VB" %>
      
    <script runat="server">
      
        Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
            ' Code that runs on application startup
            AddHandler System.Web.ApplicationServices.AuthenticationService.Authenticating, _
                 AddressOf Me.AuthenticationService_Authenticating
        End Sub
          
        Public Sub AuthenticationService_Authenticating _
                (ByVal sender As Object, _
                 ByVal e As System.Web.ApplicationServices.AuthenticatingEventArgs)
            e.Authenticated = Membership.Provider.ValidateUser(e.UserName, e.Password)
            e.AuthenticationIsComplete = True
        End Sub
          
    </script>

    This code was taken in part from MSDN http://msdn.microsoft.com/en-us/library/bb386455.aspx

  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by sauvesean on Feb 11, 2010 20:52
    How to: Use Non-default Membership Provider for WCF Authentication Service
    http://msdn.microsoft.com/en-us/library/bb386455.aspx
    Add this to global.asax (add a "Global Application Class" to your web project if it doesn't exist)

    <%@ Application Language="VB" %>
      
    <script runat="server">
      
        Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
            ' Code that runs on application startup
            AddHandler System.Web.ApplicationServices.AuthenticationService.Authenticating, _
          AddressOf Me.AuthenticationService_Authenticating
        End Sub
          
        Public Sub AuthenticationService_Authenticating _
                (ByVal sender As Object, _
                 ByVal e As System.Web.ApplicationServices.AuthenticatingEventArgs)
            e.Authenticated = Membership.Provider.ValidateUser(e.UserName, e.Password)
            e.AuthenticationIsComplete = True
        End Sub
          
    </script>
  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by sauvesean on Feb 11, 2010 20:53

    There seems to be an issue with the url specified in the endpoint (in the web.config) - http://asp.net/ApplicationServices/v200 results in a 404 error, and thus causes VS to generate warnings at compile time.

    Any ideas how to overcome this?

    ttp://msdn.microsoft.com/en-us/library/bb386455.aspx

  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by rortega on Oct 20, 2010 13:55
    I havent tested this solution, but I suspect that this code provides only authentication without any encryption so the username and password would travel across the transport level in plain text. This could be a security issue in any case, but much important if the WCF service and the silverlight application are not in the same private network (LAN). So I would suggest in that cases to use SSL.
  • -_-

    RE: Accessing the ASP.NET Authentication, Profile and Role Service in Silverlight


    posted by rortega on Oct 20, 2010 13:55
    I havent tested this solution, but I suspect that this code provides only authentication without any encryption so the username and password would travel across the transport level in plain text. This could be a security issue in any case, but much important if the WCF service and the silverlight application are not in the same private network (LAN). So I would suggest in that cases to use SSL.

Add Comment

Login to comment:
  *      *       
Login with Facebook