Walkthrough: Using ASP.NET Application Services

ASP.NET provides application services that can be accessed over the Web that enable client applications to use user authentication, role, and profile information. The services can be accessed by client applications that are written in different languages and that run on different operating systems. The only requirement is that these clients must be able to communicate by using SOAP 1.1 protocol.

This walkthrough shows how to configure and use ASP.NET application services. The walkthrough is divided into the following parts:

  • The first part shows how to configure an ASP.NET Web site to expose the application services.

  • The second part shows how to build a Windows console application that accesses a user's authentication, role, and profile information. In this walkthrough you will build a Windows console application, but the ASP.NET application services are available to any client applications that can send and receive messages in SOAP format.

  • The final part describes how to deploy the application services Web site on Windows Server 2008 and IIS 7.0.

Prerequisites

In order to complete this walkthrough, you will need:

  • Visual Studio 2010 or later. You cannot use Visual Web Developer Express for this walkthrough, because you will create a Windows console application, which is not supported in Visual Web Developer Express.

  • Microsoft SQL Server or SQL Server Express installed on your computer.

Exposing the Application Services

This section describes how to expose the application services as part of an ASP.NET Web site so that they can be accessed by any client on the network. The steps described here apply only to the server.

Note

You must use a file system Web site or a Web application project for this walkthrough. For information about the difference between the project types, see Web Application Projects versus Web Site Projects in Visual Studio. The walkthrough assumes that you are using the Visual Studio Development Server instead of IIS to run the examples. For more information, see Web Servers in Visual Studio for ASP.NET Web Projects. For information about how to deploy the application on Windows Server 2008, see Deploying the Application Services Web Site on Windows Server 2008 later in this walkthrough.

To create the application services Web site

  1. Open Visual Studio.

  2. On the File menu, click New Web Site.

    The New Web Site dialog box is displayed.

  3. Under Visual Studio installed templates, select ASP.NET Web Site.

  4. In the Location list, select File System.

  5. In the Folder text box, name the Web site WcfApplicationServices.

    Note

    You can use any name. If you use a different name, note the name so that you can substitute it when it is required later in this walkthrough.

  6. ClickOK.

    Visual Studio creates a new ASP.NET Web site and opens the Default.aspx page.

  7. In the View menu, clickOther Windows, and then clickProperties Window.

  8. In Solution Explorer, click the name of the Web site.

  9. In the Properties window, set Use dynamic ports to False.

    This instructs Visual Studio to specify a fixed port instead of a randomly selected port when it starts the ASP.NET Development Server. For this walkthrough, you must have a fixed port number that you can use when you generate the client proxy classes and configuration files. For more information, see How to: Specify a Port for the ASP.NET Development Server.

    Note

    You cannot access the Web Site Properties window from the Properties Pages window.

  10. Set Port number to 8080.

    Note

    You can use any available port. If you use a different port, note the port number so that you can substitute that number for 8080 later in this walkthrough.

ASP.NET membership, role, and profile information is stored in a database. This database is created automatically when it is first accessed. In the next procedure, you will write the code that creates users and roles for the Web site. The first time that the Web site is accessed, the database is automatically created. In addition, two roles (Managers and Friends) are added to it.

To create users and role information

  1. Add a Global.asax file to the Web site.

  2. Open the Global.asax file and replace the existing Application_Start method with the following code:

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        If Not Roles.RoleExists("Managers") Then
            Roles.CreateRole("Managers")
        End If
        If Not Roles.RoleExists("Friends") Then
            Roles.CreateRole("Friends")
        End If
    End Sub
    
        void Application_Start(object sender, EventArgs e) {
    
            if (!Roles.RoleExists("Managers")) {
                Roles.CreateRole("Managers");
            }
            if (!Roles.RoleExists("Friends")) {
                Roles.CreateRole("Friends");
            }
        }
    

    The first time that the Web site is accessed, the code creates the Aspnetdb.mdf database in the App_Data folder and adds the roles Managers and Friends to it. This database is used to store user credentials, roles, and profile information.

  3. Open the Default.aspx page and replace the markup that is in the page with the following markup.

    <%@ Page Language="VB" AutoEventWireup="true" CodeFile="Default.aspx.vb" Inherits="_Default" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="https://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Application Services Home Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h2>Enter Users' Information</h2>
    
            The following selections enable you to create users, and assign them roles and
            profile information.
    
            <p>
                <asp:Label ID="LoggedId"  Font-Bold="true" ForeColor="red" runat="server"/>
            </p>
    
            <table border="1">
                <tr>
                    <td align="left">Login to change profile</td>
                    <td align="left"><asp:LoginStatus ID="LoginStatus1" runat="server" /></td>
                </tr>
                <tr>
                    <td align="left">Define profile information (you must login first)</td>
                    <td align="left"><a href="ProfileInfo.aspx" target="_self">Profile Information</a></td>
                </tr>
                <tr>
                    <td align="left">Create user and assign role</td>
                    <td align="left"><a href="CreateUser.aspx"target="_self">New User</a></td>
                </tr>
    
             </table>
    
        </div>
    
        </form>
    </body>
    </html>
    
    <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="https://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Application Services Home Page</title>
    <style type="text/css">
    td{padding:6px; vertical-align:top;border:solid 1px #eeeeee;}
    </style>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h1>Application Services Home Page</h1>
    
            The following selections let you create users, assign them to roles, and
            set their profile information.
    
            <p>
                <asp:Label ID="LoggedId"  Font-Bold="true" ForeColor="red" runat="server"/>
            </p>
    
            <table>
                <tr>
                    <td align="right" >Log in:</td>
                    <td align="left"><asp:LoginStatus ID="LoginStatus1" runat="server" /></td>
                </tr>
                <tr>
                    <td align="right" >Set profile information:<br/>(You must be logged in.)</td>
                    <td align="left"><a href="ProfileInfo.aspx" target="_self">Profile Information</a></td>
                </tr>
                <tr>
                    <td align="right" >Create user and assign role:</td>
                    <td align="left"><a href="CreateUser.aspx"target="_self">New User</a></td>
                </tr>
    
             </table>
    
        </div>
    
        </form>
    </body>
    </html>
    

    This markup creates links for the login page, the profile information page, and the new user page. You will add these pages later in the walkthrough.

  4. In the Default.aspx code-behind file, add the following code in the Page_Load method.

    Imports System
    Imports System.Web
    
    Partial Public Class _Default
        Inherits System.Web.UI.Page
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
            If HttpContext.Current.User.Identity.IsAuthenticated Then
                LoggedId.Text = HttpContext.Current.User.Identity.Name + " you are logged in" 
            End If 
    
        End Sub 
    End Class
    
    using System;
    using System.Web;
    
    public partial class _Default : System.Web.UI.Page {
        protected void Page_Load(object sender, EventArgs e) {
    
            if (HttpContext.Current.User.Identity.IsAuthenticated) {
                LoggedId.Text = HttpContext.Current.User.Identity.Name +
                    " you are logged in.";
            } else
                LoggedId.Text = "You are not logged in.";
    
        }
    }
    

    The code checks whether the user is authenticated.

  5. Add a page named Login.aspx.

  6. Add a Login control to the Login.aspx file.

    The following example shows the markup for the Login.aspx file:

    <%@ Page Language="VB" AutoEventWireup="true" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="https://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Login Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:Login ID="Login1"   runat="server" />
        </div>
        </form>
    </body>
    </html>
    
    <%@ Page AutoEventWireup="true" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="https://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>User Login Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <h1>
            Log In</h1>
        <div>
            <%--    The Login control does all the work.  --%>
            <asp:Login ID="Login1" runat="server">
            </asp:Login>
        </div>
        </form>
    </body>
    </html>
    
  7. Add a page named ProfileInfo.aspx, and make sure that Place code in separate file is selected.

  8. Add the following markup to the ProfileInfo.aspx page:

    <%@ Page Language="VB" AutoEventWireup="false" CodeFile="ProfileInfo.aspx.vb" Inherits="ProfileInfo" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="https://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Profile Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h3>Current Authenticated User Profile Information</h3> 
    
            <a href="Default.aspx">back to default page</a>
    
            <h4>Read Profile Information</h4>
            <table>
                <tr>
                    <td align="left">User Name</td>
                    <td align="left">
                        <asp:Label ID="Label1" runat="server" Text="Label"/>
                    </td>
                </tr>
                <tr>
                    <td align="left">User Roles</td>
                    <td align="left">
                        <asp:Label ID="Label2" runat="server" Text="Label"/>
                    </td>
                </tr>
                <tr>
                    <td align="left">First Name</td>
                    <td>
                        <asp:Label ID="Label3" runat="server" Text="Label"/>
                    </td>
                </tr>
                <tr>
                    <td align="left">Last Name</td>
                    <td>    
                        <asp:Label ID="Label4" runat="server" Text="Label"/>
                    </td>
                </tr>
                <tr>
                    <td align="left">Phone #</td>
                    <td>    
                        <asp:Label ID="Label5" runat="server" Text="Label"/>
                    </td>
                </tr>
    
            </table>
    
            <asp:Button ID="Button2" runat="server" onclick="Button2_Click" 
                Text="Read Profile Information" />
    
            <hr />
    
            <h3>Update Profile Information </h3>
    
            <table>
                <tr>
                    <td align="left">First Name</td>
                    <td align="left"><asp:TextBox ID="TextBox1" runat="server"/></td>
                </tr>
                <tr>
                    <td align="left">Last Name</td>
                    <td align="left"><asp:TextBox ID="TextBox2" runat="server"/></td>
                </tr>
                <tr>
                    <td align="left">Phone Number</td>
                    <td align="left"><asp:TextBox ID="TextBox3" runat="server"/></td>
                </tr>
    
            </table>
    
            <asp:Button ID="Button1" runat="server" onclick="Button1_Click" 
            Text="Update Profile Data" />
    
        </div>
        </form>
    </body>
    </html>
    
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ProfileInfo.aspx.cs" Inherits="ProfileInfo" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="https://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>User Profile Information Page</title>
        <style type="text/css">
            td
            {
                padding: 6px;
                vertical-align: top;
                border: solid 1px #eeeeee;
            }
        </style>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h1>
                View and Update User Profile Information</h1>
            <p>
                This page lets you view and set profile information for the currently logged-in
                user.</p>
            <p>
                <a href="Default.aspx">Back to default page</a></p>
            <h2>
                View Profile Information</h2>
            &nbsp;<table>
                <tr>
                    <td align="right">
                        User name:
                    </td>
                    <td align="left">
                        <asp:Label ID="Lbl_UserName" runat="server" Font-Bold="true" />
                    </td>
                </tr>
                <tr>
                    <td align="right">
                        User roles:
                    </td>
                    <td align="left">
                        <asp:Label ID="Lbl_Roles" runat="server" Font-Bold="true" />
                    </td>
                </tr>
                <tr>
                    <td align="right">
                        First name:
                    </td>
                    <td>
                        <asp:Label ID="Lbl_FirstName" runat="server" Font-Bold="true" />
                    </td>
                </tr>
                <tr>
                    <td align="right">
                        Last name:
                    </td>
                    <td>
                        <asp:Label ID="Lbl_LastName" runat="server" Font-Bold="true" />
                    </td>
                </tr>
                <tr>
                    <td align="right">
                        Phone number:
                    </td>
                    <td>
                        <asp:Label ID="Lbl_Phone" runat="server" Font-Bold="true" />
                    </td>
                </tr>
            </table>
    
            <br />
            <asp:Button ID="But_ReadProfile" runat="server" OnClick="But_ReadProfile_Click" Text="Read Profile Information" />
            <br />
            <hr />
            <h2>
                Update Profile Information
            </h2>
            <table>
                <tr>
                    <td align="right">
                        First name:
                    </td>
                    <td align="left">
                        <asp:TextBox ID="TB_FirstName" runat="server" />
                    </td>
                </tr>
                <tr>
                    <td align="right">
                        Last name:
                    </td>
                    <td align="left">
                        <asp:TextBox ID="TB_LastName" runat="server" />
                    </td>
                </tr>
                <tr>
                    <td align="right">
                        Phone number:
                    </td>
                    <td align="left">
                        <asp:TextBox ID="TB_phoneNumber" runat="server" />
                    </td>
                </tr>
            </table>
    
            <br />
            <asp:Button ID="But_UpdateProfile" runat="server" OnClick="But_UpdateProfile_Click"
                Text="Update Profile Data" />
        </div>
        </form>
    </body>
    </html>
    

    The Profile page contains Label controls that are used to display the user name and role, and TextBox controls that are used to change the user name and phone number.

  9. In the code-behind file for the ProfileInfo.aspx page, add the following code:

    Imports System
    Imports System.Web
    Imports System.Web.Security
    
    
    Partial Class ProfileInfo
        Inherits System.Web.UI.Page
    
        Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
    
            Dim Profile As ProfileCommon = TryCast(HttpContext.Current.Profile, ProfileCommon)
    
            If HttpContext.Current.User.Identity.IsAuthenticated Then
    
                Label1.Text = HttpContext.Current.User.Identity.Name
                Dim roles As String() = _
                    System.Web.Security.Roles.GetRolesForUser()
    
                Label2.Text = "" 
                For Each r As String In roles
                    Label2.Text += r + " " 
                Next
    
                Label3.Text = Profile.FirstName()
                Label4.Text = Profile.LastName
    
                Label5.Text = Profile.PhoneNumber
            Else
                Label1.Text = "User is not Authenticated"
                Label1.ForeColor = System.Drawing.Color.Red
            End If 
        End Sub 
    
        Protected Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs)
            If HttpContext.Current.User.Identity.IsAuthenticated Then
                Label1.Text = HttpContext.Current.User.Identity.Name
                Dim roles As String() = _
                    System.Web.Security.Roles.GetRolesForUser()
                Label2.Text = "" 
                For Each r As String In roles
                    Label2.Text += r + " " 
                Next
                Label3.Text = Profile.FirstName
                Label4.Text = Profile.LastName
                Label5.Text = Profile.PhoneNumber
            Else
                Label1.Text = "User is not Authenticated"
                Label1.ForeColor = System.Drawing.Color.Red
            End If 
        End Sub 
    
        Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
            If HttpContext.Current.User.Identity.IsAuthenticated Then
                Profile.FirstName = TextBox1.Text
                Profile.LastName = TextBox2.Text
                Profile.PhoneNumber = TextBox3.Text
            End If 
        End Sub 
    End Class
    
    public partial class ProfileInfo : System.Web.UI.Page {
        protected void Page_Load(object sender, EventArgs e) {
            ProfileCommon Profile = HttpContext.Current.Profile as ProfileCommon;
    
            if (HttpContext.Current.User.Identity.IsAuthenticated) {
                Lbl_UserName.Text = HttpContext.Current.User.Identity.Name;
                string[] roles = Roles.GetRolesForUser();
                Lbl_Roles.Text = "";
                foreach (string r in roles) {
                    Lbl_Roles.Text += r + " ";
                }
    
                Lbl_FirstName.Text = Profile.FirstName;
                Lbl_LastName.Text = Profile.LastName;
                Lbl_Phone.Text = Profile.PhoneNumber;
    
            } else {
                Lbl_UserName.Text = "User is not logged in.";
                Lbl_UserName.ForeColor = System.Drawing.Color.Red;
            }
        }
    
        protected void But_ReadProfile_Click(object sender, EventArgs e) {
            if (HttpContext.Current.User.Identity.IsAuthenticated) {
                Lbl_UserName.Text = HttpContext.Current.User.Identity.Name;
                string[] roles = Roles.GetRolesForUser();
                Lbl_Roles.Text = "";
                foreach (string r in roles) {
                    Lbl_Roles.Text += r + " ";
                }
    
                Lbl_FirstName.Text = Profile.FirstName;
                Lbl_LastName.Text = Profile.LastName;
                Lbl_Phone.Text = Profile.PhoneNumber;
    
            } else {
                Lbl_UserName.Text = "User is not logged in.";
                Lbl_UserName.ForeColor = System.Drawing.Color.Red;
            }
        }
    
        protected void But_UpdateProfile_Click(object sender, EventArgs e) {
            if (HttpContext.Current.User.Identity.IsAuthenticated) {
                Profile.FirstName = TB_FirstName.Text;
                Profile.LastName = TB_LastName.Text;
                Profile.PhoneNumber = TB_phoneNumber.Text;
            }
        }
    }
    

    The code in this page enables you to obtain and change user profile information.

    Note

    The project will not compile until you enable profile properties for the Web site. You will do this in the next procedure.

  10. Add a page named CreateUser.aspx and add the following markup to it:

    <%@ Page Language="VB" AutoEventWireup="true" CodeFile="CreateUser.aspx.vb" Inherits="CreateUser" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="https://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Add New User</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
    
            <h2>Add New User</h2>
    
            <a href="Default.aspx">back to default page</a>
    
            <asp:CreateUserWizard ID="CreateUserWizard1" runat="server"
              OnCreatedUser="On_CreatedUser">
                <wizardsteps>
                    <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server"  />
                    <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server"  />
                </wizardsteps>
            </asp:CreateUserWizard>
    
            <span style="font-weight:bold; color:Red">Security Group</span> <br />
            <asp:RadioButton ID="RDO_Friends"  Text="Friends" runat="server" Checked="true"  GroupName="GP1"/>
            <asp:RadioButton ID="RDO_Manager" Text="Managers" runat="server" GroupName="GP1" />
        </div>
        </form>
    </body>
    </html>
    Imports System
    Imports System.Web
    Imports System.Web.Security
    
    Partial Public Class CreateUser
        Inherits System.Web.UI.Page
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
    
        End Sub 
    
        Protected Sub On_CreatedUser(ByVal sender As Object, ByVal e As EventArgs)
            Dim userName As String = CreateUserWizard1.UserName
            If RDO_Manager.Checked Then
                HttpContext.Current.Response.Write(userName)
                Roles.AddUserToRole(userName, "Managers")
            Else
                Roles.AddUserToRole(userName, "Friends")
            End If
    
    
            HttpContext.Current.Response.Redirect("~/default.aspx")
        End Sub 
    End Class
    
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="CreateUser.aspx.cs" Inherits="CreateUser" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="https://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Add User Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <h1>Add User</h1>
            <a href="Default.aspx">Back to default page</a><br />
            &nbsp;<asp:CreateUserWizard ID="CreateUserWizard1" runat="server" OnCreatedUser="On_CreatedUser">
                <WizardSteps>
                    <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server" />
                    <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server" />
                </WizardSteps>
            </asp:CreateUserWizard>
            <span style="font-weight: bold; color: Red">Security Group</span>
            <br />
            <asp:RadioButton ID="RDO_Friends" Text="Friends" runat="server" Checked="true" GroupName="GP1" />
            &nbsp;
            <asp:RadioButton ID="RDO_Manager" Text="Managers" runat="server" GroupName="GP1" />
        </div>
        </form>
    </body>
    </html>
    
    using System;
    using System.Web;
    using System.Web.Security;
    
    public partial class CreateUser : System.Web.UI.Page {
        protected void Page_Load(object sender, EventArgs e) {
    
        }
        protected void On_CreatedUser(object sender, EventArgs e) {
            string userName = CreateUserWizard1.UserName;
            if (RDO_Manager.Checked){
                HttpContext.Current.Response.Write(userName);
                Roles.AddUserToRole(userName, "Managers");
            } else
                Roles.AddUserToRole(userName, "Friends");
    
            HttpContext.Current.Response.Redirect("~/default.aspx");
        }
    }
    
  11. In the code-behind file for the CreateUser.aspx page, add the following code:

    This page enables you to create users and assign them to a role.

The next step is to enable forms authentication, roles, and profile properties in the Web site. You do this with configuration settings in the Web.config file.

To configure authentication, roles, and profile properties

  1. Open the Web site's Web.config file.

  2. In the authentication element in the system.web section, change the default windows authentication to use forms, as shown in the following example:

    <authentication mode="Forms" />
    
  3. In the system.web section, configure the roles service by adding the roleManager element, as shown in the following example:

    <roleManager enabled="true"/>
    
  4. In the system.web section, configure the profile service through the profile section and its properties element as shown in the following example:

    <profile enabled="true">
      <properties>
        <add name="FirstName"    type="String"/>
        <add name="LastName"     type="String"/>
        <add name="PhoneNumber"  type="String"/>
      </properties>
    </profile>
    

    This profile setting defines three properties (FirstName, LastName, and PhoneNumber) that will be managed by the ASP.NET profile service. At run time, ASP.NET will dynamically create a class of type ProfileCommon that contains these properties.

    The following example shows a part of the Web.config file that has all the required changes.

    <system.web>
    <!-- Other settings. -->
    <authentication mode="Forms" />
    <roleManager enabled="true"/>
    <profile enabled="true">
      <properties>
        <add name="FirstName"    type="String"/>
        <add name="LastName"     type="String"/>
        <add name="PhoneNumber"  type="String"/>
      </properties>
    </profile>
    <!-- Other settings. -->
    </system.web>
    

You can now create user information that you will use later to log in.

To create users and assign profile information

  1. In Solution Explorer, select the Default.aspx page then press CTRL+F5 to run the page.

    The page is displayed in the browser with the following URL:

    https://localhost:8080/WcfApplicationServices/Default.aspx
    
  2. Click New User.

    The CreateUser.aspx page is displayed.

  3. Create some users and assign them to the predefined roles. To do this, enter the user's credentials then click Create User.

    Record the user names and passwords that you have created. You will need them to assign or change the users' profile information.

    For example, create a user that has a user name "joeM" and select the Managers radio button so that joeM is a member of the Managers role. Create a second user that has a user name "joeNA", and select the Friends radio button. The user joeNA will be a member of the Friends role but not of the Managers role. The Friends and Managers roles are created by code that you added earlier to the Application_Start method in the Global.asax file.

    After a user is created, you are redirected to the Default.aspx page.

  4. In the Default.aspx page, click Login.

    The Login.aspx page is displayed.

  5. Log in using the credentials of one of the users that you created earlier.

    If your login is successful, you are redirected to the Default.aspx page.

  6. Click Profile Information.

    The Profile.aspx page is displayed.

  7. Enter or update the profile information for the logged-in user by entering the first name, last name, and phone number.

  8. Click Update Profile Data.

  9. Click Read Profile Information.

    The information that you just entered is displayed. This step lets you make sure that profile properties are working.

  10. Return to the Default.aspx page.

  11. Log out from the user account for the user in the manager role.

  12. Log in as a user in the Friends role.

    For example, log in as joeNA.

  13. Enter profile information for the logged-in user.

You are finished creating users, roles, and profile information. You will now make this information available to client applications.

Mapping and Configuring the Application Services

You can now expose the user information that you have created by using ASP.NET application services. Before you can access the user's credential and profile information from the client, you must create mapping files (.svc) that point to the application services. This makes the services available to any application that is running on a platform that can send and receive SOAP messages. You must also configure the Web site so the application services are exposed on the network.

To create application services mapping files

  1. Add a WCF service file (.svc) to the Web site and name it MyAuthenticationSvcWrap.svc.

  2. Open the MyAuthenticationSvcWrap.svc file and replace the existing @ ServiceHost directive with the following directive, which references the System.Web.ApplicationServices.AuthenticationService class:

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

    This example service does not implement a custom authentication service. Instead, it calls (wraps) the built-in System.Web.ApplicationServices.AuthenticationService class.

  3. Delete the interface and class files for the MyAuthenticationSvcWrap service in the App_Code directory (App_Code\MyAuthenticationSvcWrap and App_Code\IMyAuthenticationSvcWrap).

    The interface and class files were created when the .svc file was added to the project. You do not need these files, because you are using the System.Web.ApplicationServices.AuthenticationService service and are not implementing a custom service.

  4. Add another WCF service file (.svc) to the Web site and name it MyRoleSvcWrap.svc.

  5. Open the MyRoleSvcWrap.svc file and replace its contents with the following @ ServiceHost directive, which creates a reference to the System.Web.ApplicationServices.RoleService class:

    <%@ ServiceHost Language="VB" 
       Service="System.Web.ApplicationServices.RoleService"    %>
    
    <%@ ServiceHost Language="C#" 
      Service="System.Web.ApplicationServices.RoleService"   %>
    
  6. In the App_Code directory, delete the interface and class files for the MyRoleSvcWrap service.

  7. Add another WCF service file (.svc) to the Web site and name it MyProfileSvcWrap.svc.

  8. Open the MyProfileSvcWrap.svc file and replace its contents with the following directive, which creates a reference to the System.Web.ApplicationServices.ProfileService class:

    <%@ ServiceHost Language="VB"
      Service="System.Web.ApplicationServices.ProfileService" 
      %>
    
    <%@ ServiceHost Language="C#"
    Service="System.Web.ApplicationServices.ProfileService" 
    %>
    
  9. In the App_Code directory, delete the interface and class files for the MyProfileSvcWrap service.

  10. Save and close all .svc files

  11. Build the WcfApplicationServices project to make sure that the markup, code, and configuration settings compile.

You can now configure the Web application to expose the application services.

To configure the application services

  1. Open or switch to the Web.config file.

  2. Between the configSections element and appSettings element, add a new system.web.extensions element.

  3. Add a scripting element to the system.web.extensions element.

  4. In the scripting element, enable the authentication, profile, and roles services through the webServices section.

    The following example shows the finished system.web.extensions element.

    <configSections>
      ...
    </configSections>
    
    <system.web.extensions><scripting><webServices><authenticationService enabled="true"requireSSL = "false"/><profileServiceenabled="true"readAccessProperties="FirstName,LastName,PhoneNumber"/><roleService enabled="true"/></webServices></scripting></system.web.extensions>
    <appSettings/>
    

    Note

    In a live Web site, you should set the requireSSL attribute to true.

  5. As a child of the system.serviceModel section, add a serviceHostingEnvironment element and set its aspNetCompatibilityEnabled attribute to true.

    The following example shows the finished serviceHostingEnvironment element.

    <runtime>
      ...
    </runtime>
    
    <system.serviceModel><serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <behaviors>
      ...
    </behaviors>
    
  6. In the system.serviceModel group, configure the application services so that they can be accessed by client applications by using the SOAP protocol. To do this, follow these steps:

    1. In the system.serviceModel element, find the <behaviors><serviceBehaviors><behavior> element whose name attribute is MyAuthenticationSvcWrapBehavior.

    2. Change the behavior element's name attribute value from MyAuthenticationSvcWrapBehavior to AppServiceBehaviors. In this walkthrough, you configure the application to use the AppServiceBehaviors behavior for the all three services.

    3. Delete the behavior elements whose names are MyRoleSvcWrapBehavior and MyProfileSvcWrapBehavior from the <system.serviceModel><behaviors><serviceBehaviors> element.

  7. In the <system.serviceModel><services><service> element that has a behaviorConfiguration attribute whose value is MyAuthenticationSvcWrapBehavior, do the following:

    1. Change the behaviorConfiguration attribute value from MyAuthenticationSvcWrapBehavior to AppServiceBehaviors.

    2. Change the name attribute value from MyAuthenticationSvcWrap to System.Web.ApplicationServices.AuthenticationService.

  8. Configure the <service><endpoint> element by doing the following:

    1. Delete the address attribute.

    2. Change the value of the binding attribute value from wsHttpBinding to basicHttpBinding.

    3. Change the value of the contract attribute from IMyAuthenticationSvcWrap to System.Web.ApplicationServices.AuthenticationService.

    4. Add the bindingNamespace attribute and set it to https://asp.net/ApplicationServices/v200.

    5. Delete the child identity element.

    6. Delete the endpoint element whose address attribute is set to mex.

    The following example shows the markup for the authentication service element.

    <service behaviorConfiguration="AppServiceBehaviors" 
        name="System.Web.ApplicationServices.AuthenticationService">
      <endpoint binding="basicHttpBinding"  
        bindingNamespace="https://asp.net/ApplicationServices/v200"  
        contract="System.Web.ApplicationServices.AuthenticationService"/>
      </endpoint>
    </service>
    

    For more information, see <service> element and <endpoint> element.

  9. Repeat step 7 for the service elements that have a behaviorConfiguration attribute whose values are MyRoleSvcWrapBehavior and MyProfileSvcWrapBehavior. Substitute the following values for the name and contract attributes:

    • System.Web.ApplicationServices.RoleService

    • System.Web.ApplicationServices.ProfileService

    The following example shows the complete system.serviceModel element.

    <configuration>
      ...
    
      <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        <services>
          <!-- this enables the WCF AuthenticationService endpoint -->
          <service behaviorConfiguration="AppServiceBehaviors"
              name="System.Web.ApplicationServices.AuthenticationService">
            <endpoint binding="basicHttpBinding"
                bindingNamespace="https://asp.net/ApplicationServices/v200"
                contract="System.Web.ApplicationServices.AuthenticationService"/>
          </service>
          <!-- this enables the WCF RoleService endpoint -->
          <service behaviorConfiguration="AppServiceBehaviors"
              name="System.Web.ApplicationServices.RoleService">
            <endpoint binding="basicHttpBinding"
                bindingNamespace="https://asp.net/ApplicationServices/v200"
                contract="System.Web.ApplicationServices.RoleService"/>
          </service>
          <!-- this enables the WCF ProfileService endpoint -->
          <service behaviorConfiguration="AppServiceBehaviors"
              name="System.Web.ApplicationServices.ProfileService">
            <endpoint binding="basicHttpBinding"
                bindingNamespace="https://asp.net/ApplicationServices/v200"
                contract="System.Web.ApplicationServices.ProfileService"/>
          </service>
        </services>
    
        <behaviors>
          <serviceBehaviors>
            <behavior name="AppServiceBehaviors">
              <serviceMetadata httpGetEnabled="true"/>
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
      ...
    </configuration>
    

You can now run the Web service in order to activate the authentication, profile, and roles services that will be used by the client application. This also enables you to verify that the application service is working correctly.

To activate the Web site to expose the application services

  • In Solution Explorer, right-click the MyAuthenticationSvcWrap.svc file and then click View in Browser.

    The Web service is invoked and a page is displayed in the browser that gives you instructions for testing the service. Make a note of the service URL (the URL that ends with "?wsdl"), because you will need it in the next steps to access the service from the client application. Repeat the process for the other two service files.

You have finished configuring the application services so that they are available on the Web. The next step is to invoke these services from a client application.

Using the Application Services in a Client Application

This section shows how to create a client application in the form of a Windows console application to access the application services. The application services can be accessed by any client that can send and receive messages in SOAP format.

To create the client console application, you follow these general steps:

  • Create the client application.

  • Generate application services proxy-class files and a related app.config configuration file.

  • Add the generated proxy-class and configuration files to the client application and compile the application.

  • Call application service operations through the generated proxy classes.

    Note

    If you pass sensitive user data to the service such as authentication credentials, use the secure sockets layer (SSL, by using HTTPS protocol). For example, in the sample later in this document, you would change the value of the authenticationService element's requireSSL attribute from false to true. (However, do not do this for the walkthrough, which does not provide instructions for configuring the site to use SSL.) For more information, see Transport Security and HTTP Security and ASP.NET Web Services on the MSDN Web site, and Configuring Secure Sockets Layer in IIS 7.0 on the IIS Web site.

To create a Windows console application

  1. In Visual Studio, on the File menu, click Add and then click New Project.

  2. Select your preferred language, and then under Visual Studio installed templates, select Console Application.

  3. Name the application AppSvcClient, enter a location for the application, and then click OK.

    Visual Studio adds the project to the current solution and opens the default class file.

  4. Right-click the name of the console application and click Add Reference.

  5. In the Add Reference dialog box, click the .NET tab, select System.ServiceModel and System.Runtime.Serialization, and then click OK. If you are using Visual Basic, you must also add System.Web.Extensions.

    This adds assemblies to the project that are required in order to use the proxy classes that you will add in the next section.

Generating Proxy Classes and Configuration Information for Application Services

You can now generate proxy classes and configuration information that will enable the console application to access the application services from the AppSvcClient console application. You generate a proxy class and configuration separately for each application service.

To generate proxy classes for the application services

  1. In the Windows Start menu, click All Programs, click Microsoft Visual Studio 2008, click Visual Studio Tools, and then click Visual Studio 2008 Command Prompt.

    Note

    If you are running Windows Vista®, run this command as an Administrator.

    This opens a Windows Command window whose environment settings include the path for the .NET Framework tools.

  2. At the Windows command line, change to the directory that contains the Program.cs or Module1.vb file for the AppSvcClient project.

  3. Generate the authentication service proxy class by using the service utility tool (Svcutil.exe). Follow these steps:

    1. In Solution Explorer, right-click the MyAuthenticationSvcWrap.svc file and then click View in Browser.

    2. Copy the svcutil.exe command from the browser window.

    3. At the Windows command window that you opened in step 1, paste the command from the browser window.

    4. If you are working in Visual Basic, append /language:"VB" to the command.

    The following example shows the command.

    svcutil https://localhost:8080/WcfApplicationServices/MyAuthenticationSvcWrap.svc?wsdl /language:"VB"
    
    svcutil.exe https://localhost:8080/WcfApplicationServices/MyAuthenticationSvcWrap.svc?wsdl
    

    Note

    The default language output is C#. The flag /language:"VB" is required only for Visual Basic. The svcutil command is displayed in the browser when you view the MyAuthenticationSvcWrap.svc file.

    The value "localhost:8080" must match the URL that you use when you run the Web site from this walkthrough. If you used a different port number for the ASP.NET Development Server, or if you are using a dynamic port assignment, substitute the appropriate value. If the port number changes, you must update the .config file that is generated by the Svcutil.exe tool to match the new port number.

    The name of the .svc file in the command must match the name that you used to create the .svc file earlier in this walkthrough. Because you are not explicitly specifying a name for the generated proxy class, the name of the generated proxy class is based on the service name that is assigned in the .svc file in the Web site (AuthenticationServices).

  4. Rename the output.config configuration file that was generated by the service utility tool to App.config.

    Note

       Do not close the Windows Command window; you will generate additional proxy classes later in this walkthrough.

  5. In Solution Explorer, right-click the name of the console application, click Add, click Existing Item, select the AuthenticationService proxy class file that you generated, and then click Add.

  6. Using the same procedure as in the previous step, add the App.config file to the console application project.

  7. In the console application's main class file, add the following code to create a test.

    Imports System.ServiceModel
    
    Module Module1
    
        Sub Main(ByVal args As String())
    
    
            Dim username As String = "joeM" 
            Dim password As String = "*(IU89iu" 
            Dim result As Boolean = False 
            Dim customCredential As String = "Not used by the default membership provider." 
            Dim isPersistent As Boolean = True ' authentication ticket remains valid across sessions.
    
            'BasicHttpBinding and endpoint are provided in app.config file. 
            Dim authService As New AuthenticationServiceClient()
    
            result = authService.Login(username, password, customCredential, isPersistent)
    
            If result Then
                Console.WriteLine("Welcome, " & username & ". You are logged in.")
            Else
                Console.WriteLine("We could not validate your credentials.")
            End If
    
            Console.WriteLine("Press any key to quit.")
            Console.Read()
    
        End Sub 
    
    End Module
    
    using System;
    using System.Text;
    using System.ServiceModel;
    
    class Program {
    
        static void Main(string[] args) {
    
            string username = "joeNA";
            string password = "*(IU89iu";
            bool bLogin = false;
    
            // BasicHttpBinding and endpoint are provided in app.config file.
            AuthenticationServiceClient authService = new AuthenticationServiceClient();
            string customCredential = "Not used by the default membership provider.";
    
            // Authentication ticket remains valid across sessions. 
            bool isPersistent = true;
    
            bLogin = authService.Login(username, password, customCredential, isPersistent);
    
            if (bLogin == true)
                Console.WriteLine("Welcome " + username + ". You have logged in.");
            else
                Console.WriteLine("Unable to login!");
        }
    }
    

    The code enables you to pass a user name and password to the service when you run it from the console application. You can use values from the users and passwords that you created earlier in the walkthrough.

    The test application gets the binding and endpoint information from the App.config file.

  8. Test the project by doing the following:

    1. Change the user name and password to values that you used earlier in the walkthrough.

    2. In Solution Explorer, right-click the name of the console application (AppSvcClient) and then click Set as Startup Project.

    3. In Visual Studio, press CTRL+F5 to build and run the solution.

    The console application displays a message that states that you have logged in.

  9. Generate the profile service proxy class by doing the following:

    1. In Solution Explorer, right-click the MyProfileSvcWrap.svc file and then click View in Browser.

    2. Copy the svcutil.exe command from the browser window.

    3. At the Windows command window that you opened in step 1, paste the command from the browser window.

    4. If you are working in Visual Basic, append /language:"VB" to the command.

    5. Append the merge configuration (/mergeConfig) parameter.

    The following example shows the command.

    svcutil.exe https://localhost:8080/WcfApplicationServices/MyProfileSvcWrap.svc?wsdl /language:"VB" /config:app.config /mergeConfig
    
    svcutil.exe https://localhost:8080/WcfApplicationServices/MyProfileSvcWrap.svc?wsdl /language:"C#" /config:app.config /mergeConfig
    

    The /config:app.config option designates the App.config file as the configuration file instead of the output.config file, which is the default. The /mergeConfig option specifies that the configuration information that is generated in this step should be merged with the information that is already in the App.config file from previous steps.

  10. Generate the role service proxy class by doing the following:

    1. In Solution Explorer, right-click the MyRoleSvcWrap.svc file and then click View in Browser.

    2. Copy the svcutil.exe command from the browser window.

    3. At the Windows command window that you opened in step 1, paste the command from the browser window.

    4. If you are working in Visual Basic, append /language:"VB" to the command.

    5. Append the merge configuration (/mergeConfig) parameter.

    The following example shows the command.

    svcutil.exe https://localhost:8080/WcfApplicationServices/MyRoleSvcWrap.svc?wsdl /language:"VB" /config:app.config /mergeConfig
    
    svcutil.exe https://localhost:8080/WcfApplicationServices/MyRoleSvcWrap.svc?wsdl  /language:"C#" /config:app.config /mergeConfig
    
  11. In Solution Explorer, right-click the name of the console application, click Add, click Existing Item, select the proxy class files that you generated, and then click Add.

    The proxy classes are in the same folder as the App.config file, and are named AuthenticationService, ProfileService, and RoleService.

  12. Replace the code in the Program class with the following code:

    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.ServiceModel
    Imports System.ServiceModel.Activation
    Imports System.ServiceModel.Channels
    Imports System.ComponentModel
    Imports System.Web
    Imports System.Net
    
    'Imports System.Web.ApplicationServices 
    
    Module Module1
    
        Class MyServiceTst
    
            Dim _host As String 
    
            Public Property Host() As String 
                Get 
                    Return _host
                End Get 
                Set(ByVal value As String)
                    _host = value
                End Set 
            End Property 
    
            Function GetCookies(ByVal oc As OperationContext) As CookieContainer
                Dim httpResponseProperty As HttpResponseMessageProperty = DirectCast(oc.IncomingMessageProperties(HttpResponseMessageProperty.Name), HttpResponseMessageProperty)
                If (httpResponseProperty.Equals(Nothing) = False) Then 
                    Dim cookieContainer As New CookieContainer()
                    Dim header As String = httpResponseProperty.Headers(HttpResponseHeader.SetCookie)
    
                    If header <> Nothing Then
                        cookieContainer.SetCookies(New Uri("https://someuri.tld"), header)
                    End If 
                    Return cookieContainer
                End If 
                Return Nothing 
            End Function 
    
            Sub SetCookies(ByVal oc As OperationContext, ByVal cookieContainer As CookieContainer)
                Dim httpRequestProperty = New HttpRequestMessageProperty()
                httpRequestProperty = Nothing 
                If oc.OutgoingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name) Then
                    httpRequestProperty = TryCast(oc.OutgoingMessageProperties(HttpRequestMessageProperty.Name), HttpRequestMessageProperty)
                End If 
                If httpRequestProperty Is Nothing Then
                    httpRequestProperty = New HttpRequestMessageProperty()
                    oc.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequestProperty)
                End If
                httpRequestProperty.Headers.Add(HttpRequestHeader.Cookie, cookieContainer.GetCookieHeader(New Uri("https://someuri.tld")))
            End Sub 
    
            Sub GetUserRoles(ByVal cookieContainer As CookieContainer)
    
                Dim endPtAddr As String = strEndPtAddr("MyRoleSvcWrap")
                Dim roleSvc As New RoleServiceClient(New BasicHttpBinding(), New EndpointAddress(endPtAddr))
    
                Using New OperationContextScope(DirectCast(roleSvc.InnerChannel, IContextChannel))
                    SetCookies(OperationContext.Current, cookieContainer)
                    Dim roles As String() = roleSvc.GetRolesForCurrentUser()
                    If roles.Length = 0 Then
                        Console.WriteLine("User does not belong to any role.")
                    Else 
                        Dim userRoles As String = "" 
                        Dim i As Integer = 0
                        While i < roles.Length
                            userRoles &= roles(i) & " " 
                            Global.System.Math.Max(Global.System.Threading.Interlocked.Increment(i), i - 1)
                        End While
                        Console.WriteLine("User's roles: " & userRoles)
    
                    End If 
                End Using 
            End Sub 
    
            Sub GetProfileInfo(ByVal cookieContainer As CookieContainer)
    
                Dim endPtAddr As String = strEndPtAddr("MyProfileSvcWrap")
                Dim profileSvc As New ProfileServiceClient(New BasicHttpBinding(), New EndpointAddress(endPtAddr))
    
                Using New OperationContextScope(DirectCast(profileSvc.InnerChannel, IContextChannel))
                    SetCookies(OperationContext.Current, cookieContainer)
                    Dim profileData As Dictionary(Of String, Object) = _
                    profileSvc.GetPropertiesForCurrentUser(New String() _
                       {"FirstName", "LastName", "PhoneNumber"}, True)
    
                    Console.WriteLine("FirstName: " & profileData("FirstName"))
                    Console.WriteLine("LastName: " & profileData("LastName"))
                    Console.WriteLine("PhoneNumber: " & profileData("PhoneNumber"))
                End Using 
            End Sub 
    
            Public Function strEndPtAddr(ByVal service As String) As String 
                Dim endPtAddr As String = "https://" & Host & "/WcfApplicationServices/" & service & ".svc?wsdl" 
    
                Return endPtAddr
            End Function 
    
            Sub Init(ByVal args As String())
    
                If (args.Length = 3) Then  
                    ' The host address was passed in, so that is used.
                    Host = args(2)
                Else
                    Host = "localhost:8080" 
                End If 
    
                Dim username As String = args(0)
                Dim password As String = args(1)
                Dim result As Boolean 
                Dim binding As BasicHttpBinding = New BasicHttpBinding()
                Dim endPtAddr As String = strEndPtAddr("MyAuthenticationSvcWrap")
    
                Console.WriteLine("Attempting to connect as username = " & username & vbNewLine _
                  & "password length = " & password.Length.ToString() & vbNewLine _
                  & " on server " & Host & vbNewLine _
                  &  vbNewLine & "End point address: " & endPtAddr _
                  )
    
                ' BasicHttpBinding and endpoint are explicitly passed and ignored 
                ' in the app.config file. 
                Dim authService As AuthenticationServiceClient = New AuthenticationServiceClient(binding, _
                                                      New EndpointAddress(endPtAddr))
    
                Dim cookieContainer As CookieContainer = Nothing 
                Dim customCredential As String = "Not used by the default membership provider." 
    
                ' Authentication ticket remains valid across sessions. 
                Dim isPersistent As Boolean = True    
    
                Using New OperationContextScope(authService.InnerChannel)
                    Try
                        result = authService.Login(username, password, customCredential, isPersistent)
                        cookieContainer = GetCookies(OperationContext.Current)
                    Catch enf As EndpointNotFoundException
                        Console.WriteLine(enf.Message)
                        Return 
                    End Try 
                End Using 
    
                If result Then
                    Console.WriteLine("Welcome, " & username & ". You are logged in.")
                    GetUserRoles(cookieContainer)
    
                    GetProfileInfo(cookieContainer)
                Else
                    Console.WriteLine("Credentials could not be validated.")
                End If 
    
    
            End Sub 
        End Class 
    
    
    
        Sub Main(ByVal args As String())
    
            If (args.Length < 1) Then
                Console.WriteLine("Missing command-line arguments: username password [host]")
                Return 
            End If 
    
            Dim mst As MyServiceTst = New MyServiceTst()
            mst.Init(args)
    
    
            Console.WriteLine("Press any key to quit.")
            Console.Read()
    
        End Sub 
    
    End Module
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Channels;
    using System.ComponentModel;
    using System.Web;
    using System.Net;
    
    
    class MyServiceTst {
    
        string _Host { get; set; }
    
        CookieContainer GetCookies(OperationContext oc) {
            HttpResponseMessageProperty httpResponseProperty =
                (HttpResponseMessageProperty)oc.IncomingMessageProperties[HttpResponseMessageProperty.Name];
            if (httpResponseProperty != null) {
                CookieContainer cookieContainer = new CookieContainer();
                string header = httpResponseProperty.Headers[HttpResponseHeader.SetCookie];
    
                if (header != null) {
                    cookieContainer.SetCookies(new Uri(@"https://someuri.tld"), header);
                }
                return cookieContainer;
            }
            return null;
        }
    
        void SetCookies(OperationContext oc, CookieContainer cookieContainer) {
    
            HttpRequestMessageProperty httpRequestProperty = null;
            if (oc.OutgoingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name)) {
                httpRequestProperty =
                    oc.OutgoingMessageProperties[HttpRequestMessageProperty.Name]
                    as HttpRequestMessageProperty;
            }
    
            if (httpRequestProperty == null) {
                httpRequestProperty = new HttpRequestMessageProperty();
                oc.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name,
                    httpRequestProperty);
            }
            httpRequestProperty.Headers.Add(HttpRequestHeader.Cookie,
                cookieContainer.GetCookieHeader(new Uri(@"https://someuri.tld")));
        }
    
    
        void GetUserRoles(CookieContainer cookieContainer) {
    
            string endPtAddr = strEndPtAddr("MyRoleSvcWrap");
    
            RoleServiceClient roleSvc = new RoleServiceClient(new BasicHttpBinding(),
                 new EndpointAddress(endPtAddr));
    
            using (new OperationContextScope(roleSvc.InnerChannel)) {
                // CookieContainer must be set in order to call GetRolesForCurrentUser(). 
                // 1638
                SetCookies(OperationContext.Current, cookieContainer);
                string[] roles = roleSvc.GetRolesForCurrentUser();
                if (roles.Length == 0) {
                    Console.WriteLine("User does not belong to any role.");
                } else {
                    string userRoles = "";
                    for (int i = 0; i < roles.Length; i++) {
                        userRoles += roles[i] + " ";
                    }
                    Console.WriteLine("User's roles: " + userRoles);
                }
            }
        }
    
        void GetProfileInfo(CookieContainer cookieContainer) {
    
            string endPtAddr = strEndPtAddr("MyProfileSvcWrap");
    
            ProfileServiceClient profileSvc = new ProfileServiceClient(new BasicHttpBinding(),
                 new EndpointAddress(endPtAddr));
    
            string[] strProfileProps = new string[] { "FirstName", "LastName", "PhoneNumber" };
    
            using (new OperationContextScope(profileSvc.InnerChannel)) {
                SetCookies(OperationContext.Current, cookieContainer);
                Dictionary<string, object> profileData =
                    profileSvc.GetPropertiesForCurrentUser(strProfileProps, true);
    
                foreach (string sProp in strProfileProps)
                    Console.WriteLine(sProp + ": " + profileData[sProp]);
    
            }
        }
    
        public string strEndPtAddr(string service) {
    
            string endPtAddr = @"https://" + _Host + "/WcfApplicationServices/"
                + service + ".svc?wsdl";
    
            return endPtAddr;
        }
    
        public MyServiceTst(string[] args) {
    
            if (args.Length == 3)
                // The host address was passed in, so that is used.
                _Host = args[2];
            else
                _Host = "localhost:8080";
    
            string username = args[0];
            string password = args[1];
            string endPtAddr = strEndPtAddr("MyAuthenticationSvcWrap");
    
            Console.WriteLine("Attempting to connect as username = " + username
                + "\n password length = " + password.Length.ToString()
                + "\n on server " + _Host + "\n"
                + "\n" + "End point address: "  + endPtAddr
            );
    
            // BasicHttpBinding and endpoint are explicitly passed and ignored 
            // in th app.config file.
            BasicHttpBinding binding = new BasicHttpBinding();
            AuthenticationServiceClient authService = new AuthenticationServiceClient(binding,
                                                         new EndpointAddress(endPtAddr));
    
            CookieContainer cookieContainer;
            string customCredential = "Not used by the default membership provider.";
    
            // Authentication ticket remains valid across sessions. 
            bool isPersistent = true;
            bool bLogin = false;
    
            using (new OperationContextScope(authService.InnerChannel)) {
                try {
                    bLogin = authService.Login(username, password,
                                                 customCredential, isPersistent);
                    cookieContainer = GetCookies(OperationContext.Current);
                } catch (EndpointNotFoundException enfe) {
                    Console.WriteLine(enfe.Message);
                    if (enfe.InnerException != null && enfe.InnerException.Message != null)
                        Console.WriteLine(enfe.InnerException.Message);
                    return;
                }
            }
    
            if (bLogin) {
                Console.WriteLine("Welcome, " + username + ". You are now logged in.");
    
                GetUserRoles(cookieContainer);
                GetProfileInfo(cookieContainer);
            } else {
                Console.WriteLine("Credentials could not be validated.");
            }
    
        }
    }
    
    class Program {
    
        static void Main(string[] args) {
    
            if (args.Length < 1) {
                Console.WriteLine("Missing command-line arguments: username password [host]");
                return;
            }
            MyServiceTst mst = new MyServiceTst(args);
    
            Console.WriteLine("Press any key to quit.");
            Console.Read();
        }
    
    }
    
  13. Build the project.

Accessing the Application Services

You can now run the client application and use the application services that you have exposed as part of the Web site.

To run the Windows application

  1. At the Windows command prompt, change to the console application directory.

  2. Enter the following command, using the user name and password of one of the users that you created earlier in the walkthrough:

    AppSvcClient.exe <userName> <password>

    If you entered the correct credentials, you will be authenticated and will be able to obtain roles and profile information that is associated with the logged-in user.

Deploying the Application Services Web Site on Windows Server 2008

In order to run the application in a production environment, you can copy the Web site to a computer that is running Windows Server 2008 and then access the Web service from a client.

Note

This procedure assumes that you are familiar with Windows 2008 server administration tasks and with using IIS Manager to manage Web applications.

To run the Web application on Windows Server 2008

  1. On the computer that is running Windows Server 2008, verify that the Web Server Role is installed on the server and the ASP.NET Role Service.

  2. Verify that Microsoft SQL Server Express is installed.

    Note

    SQL Server Express is not recommended for production systems.

  3. Copy the WcfApplicationServices directory and its subdirectories to the server.

  4. Using IIS Manager, add a virtual directory at the root of the Web site and give it the alias WcfApplicationServices. 

  5. Set the WcfApplicationServices physical path to the path of the WcfApplicationServices directory from the previous step.

  6. Convert the WcfApplicationServices virtual directory into an application.

  7. In Windows Explorer, open the WcfApplicationServices directory.

  8. Delete the SQL Server Express log file (aspnetdb_log.ldf), which is in the App_Data folder of the Web site.

  9. Right-click the WcfApplicationServices\App_Data directory, click Properties, and then click the Security tab.

  10. Click Edit.

    The Permissions dialog box for the App_Data folder is displayed.

  11. Click Add.

    The Select Users, Computers, or Groups dialog box is displayed

  12. Verify that the local server computer is listed under From this location type. If the server is not listed, click Location and then select the local server.

  13. In the text box, enter NETWORK SERVICE.

  14. Close the dialog boxes that you have opened.

    The default application pool runs under the NETWORK SERVICE account. This account needs permission to create the SQL log file and to make changes to the aspnetdb.mdf file.

  15. On a different computer that has access to the server, open a browser and request the Default.aspx page in the Web application.

  16. Log in to one of the accounts that you created earlier in the walkthrough to verify that the application is working.

  17. On the server computer, run the ServiceModel registration tool (ServiceModelReg.exe) to register the service. From an elevated command prompt, enter the following command:

    ServiceModelReg.exe -i

    This registers the service model and updates the scriptmaps on IIS to expose the service.

  18. On the client computer, run the following AppSvcClient.exe command, passing a user name and password, and passing the server as the third argument:

    AppSvcClient.exe <userName> <password> <server>

    You see the same output from AppSvcClient.exe as in the previous step.

    If the AppSvcClient program returns an error, compare the URL parameter passed to AppSvcClient with the URL that is displayed by Svcutil.exe when you browse to WcfApplicationServices/MyAuthenticationSvcWrap.svc. For example, if the server computer name is bp0, enter the following URL in the browser:

    https://bp0/WcfApplicationServices/MyAuthenticationSvcWrap.svc

    The instructions to test the service include the URL that is required by the client application.

Next Steps

This walkthrough has illustrated the basic principles of accessing the ASP.NET application services from a client application that can send and receive messages in SOAP format.

You might want to experiment with additional application service features. Suggestions for additional exploration include the following:

  • Learn more about how to use application services from .NET Framework clients. For more information, see Client Application Services Overview.

  • Learn more about the Windows Communication Foundation (WCF) and about data exchange with the client in SOAP format. For more information, see XML Web Services Infrastructure on the MSDN Web site.

For general information about Web services, you might want to do following:

  • Understand how to use Web services. For more information, see XML Web Service Scenarios.

  • Learn more about ASP.NET application services. For more information, see AuthenticationService.Login.

  • Understand the processing that occurs when you make a Web service call. For more information, see Anatomy of an XML Web Service Lifetime.

See Also

Tasks

Walkthrough: Creating a Web Site with Membership and User Login

How to: Enable the WCF Authentication Service

How to: Enable the WCF Role Service

How to: Enable the WCF Profile Service

Reference

How to: Enable the WCF Role Serviced

Concepts

Defining ASP.NET Profile Properties

ASP.NET Application Services Overview

Bindings and Security