How to use the Sample Read-Only XML Membership and Role Providers with IIS 7.0

by Robert McMurray

Introduction

When ASP.NET 2.0 was released, the Microsoft Developer Network (MSDN) Web site provided two sample providers for ASP.NET Membership and Roles. These providers were read-only providers that used XML files for the list of users and roles, and were available at the following URLs:

These samples are excellent for use with IIS 7.0 and above for demonstration or test Web sites, but they don't work as-written with IIS because of the way that security is designed in IIS. The original instructions allowed you to deploy the sample membership/role providers into the App_Code folder of your Web site, but IIS requires that providers are registered in the Global Assembly Cache (GAC) before they can be deployed. With that in mind, the following steps will walk you through compiling and deploying the read-only XML providers on a development system.

Prerequisites

The following items are required to complete the procedures in this article:

  1. IIS 7.0 or above must be installed on your Windows Vista or Windows Server 2008 computer.
  2. ASP.NET must be installed for your version of IIS.
  3. The Internet Information Services Manager for IIS 7.0 and above must be installed.
  4. You will need Gacutil.exe on your IIS computer; this is required to add the assemblies to your Global Assembly Cache (GAC).

Step 1: Set up the XML provider projects

In this first step you will create a solution in Visual Studio that contains two projects: one for the XML-based membership provider and the other for the XML-based role provider.

  1. Open Microsoft Visual Studio 2008.

  2. Click the File menu, then New, then Project.

  3. In the New Project dialog:

    • Choose Visual C# as the project type.
    • Choose Class Library as the template.
    • Type ReadOnlyXmlMembershipProvider as the name of the project.
    • Type ReadOnlyXmlProviders as the name of the solution.
    • Click OK.
  4. Remove the Class1.cs file from the ReadOnlyXmlMembershipProvider project:

    • In the solution explorer, right-click the Class1.cs file in the ReadOnlyXmlMembershipProvider project, then Delete.
    • Click OK when prompted to permanently delete the class.
  5. Add a reference path to the System.Configuration library:

    • In the solution explorer, right-click the ReadOnlyXmlMembershipProvider project, then Add Reference...
    • Click the .NET tab.
    • Select "System.Configuration" in the list of assemblies.
    • Click OK.
  6. Add a reference path to the System.Web library:

    • In the solution explorer, right-click the ReadOnlyXmlMembershipProvider project, then Add Reference...
    • Click the .NET tab.
    • Select "System.Web" in the list of assemblies.
    • Click OK.
  7. Add a strong name key to the project:

    • In the solution explorer, right-click the ReadOnlyXmlRoleProvider project, then Properties.
    • Click the Signing tab.
    • Check the Sign the assembly check box.
    • Choose <New...> from the strong key name drop-down box.
    • Enter ReadOnlyXmlMembershipProviderKey for the key file name.
    • If desired, enter a password for the key file; otherwise, uncheck the Protect my key file with a password box.
    • Click OK.
  8. (Optional) Add a custom build event to automatically register the DLL in the GAC:

    • In the solution explorer, right-click the ReadOnlyXmlRoleProvider project, then Properties.

    • Click the Build Events tab.

    • Enter the following in the Post-build event command line box:

      call "%VS90COMNTOOLS%\vsvars32.bat">nul
      gacutil.exe /if "$(TargetPath)"
      
  9. Add a second project to the solution:

    • Click File, then Add, then New Project...
    • Choose Visual C# as the project type.
    • Choose Class Library as the template.
    • Type ReadOnlyXmlRoleProvider as the name of the project.
    • Click OK.
  10. Remove the Class1.cs file from the ReadOnlyXmlRoleProvider project:

    • In the solution explorer, right-click the Class1.cs file in the ReadOnlyXmlRoleProvider project, then Delete.
    • Click OK when prompted to permanently delete the class.
  11. Add a reference path to the System.Configuration library:

    • In the solution explorer, right-click the ReadOnlyXmlRoleProvider project, then Add Reference...
    • Click the .NET tab.
    • Select "System.Configuration" in the list of assemblies.
    • Click OK.
  12. Add a reference path to the System.Web library:

    • In the solution explorer, right-click the ReadOnlyXmlRoleProvider project, then Add Reference...
    • Click the .NET tab.
    • Select "System.Web" in the list of assemblies.
    • Click OK.
  13. Add a strong name key to the project:

    • In the solution explorer, right-click the ReadOnlyXmlRoleProvider project, then Properties.
    • Click the Signing tab.
    • Check the Sign the assembly check box.
    • Choose <New...> from the strong key name drop-down box.
    • Enter ReadOnlyXmlRoleProvider for the key file name.
    • If desired, enter a password for the key file; otherwise, uncheck the Protect my key file with a password box.
    • Click OK.
  14. (Optional) Add a custom build event to automatically register the DLL in the GAC:

    • In the solution explorer, right-click the ReadOnlyXmlRoleProvider project, then Properties.

    • Click the Build Events tab.

    • Enter the following in the Post-build event command line box:

      call "%VS90COMNTOOLS%\vsvars32.bat">nul
      gacutil.exe /if "$(TargetPath)"
      
  15. Save the solution.

Step 2: Add the provider classes for the projects

In this second step you will create the classes for the XML-based membership and role providers. The code for these classes is copied from the Membership Providers and Role Providers topics on MSDN.

  1. Add a new class to the ReadOnlyXmlMembershipProvider project:

    • In the solution explorer, right-click the ReadOnlyXmlMembershipProvider project, then Add, then Class...

    • Name the class ReadOnlyXmlMembershipProvider.cs.

    • Click Add.

    • Remove the existing code.

    • Paste the following sample code from the Membership Providers topic into the editor:

      using System;
      using System.Xml;
      using System.Collections.Generic;
      using System.Collections.Specialized;
      using System.Configuration.Provider;
      using System.Web.Security;
      using System.Web.Hosting;
      using System.Web.Management;
      using System.Security.Permissions;
      using System.Web;
      
      public class ReadOnlyXmlMembershipProvider : MembershipProvider
      {
         private Dictionary<string, MembershipUser> _Users;
         private string _XmlFileName;
      
         // MembershipProvider Properties
         public override string ApplicationName
         {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
         }
      
         public override bool EnablePasswordRetrieval
         {
            get { return false; }
         }
      
         public override bool EnablePasswordReset
         {
            get { return false; }
         }
      
         public override int MaxInvalidPasswordAttempts
         {
            get { throw new NotSupportedException(); }
         }
      
         public override int MinRequiredNonAlphanumericCharacters
         {
            get { throw new NotSupportedException(); }
         }
      
         public override int MinRequiredPasswordLength
         {
            get { throw new NotSupportedException(); }
         }
      
         public override int PasswordAttemptWindow
         {
            get { throw new NotSupportedException(); }
         }
      
         public override MembershipPasswordFormat PasswordFormat
         {
            get { throw new NotSupportedException(); }
         }
      
         public override string PasswordStrengthRegularExpression
         {
            get { throw new NotSupportedException(); }
         }
      
         public override bool RequiresQuestionAndAnswer
         {
            get { throw new NotSupportedException(); }
         }
      
         public override bool RequiresUniqueEmail
         {
            get { throw new NotSupportedException(); }
         }
      
         // MembershipProvider Methods
         public override void Initialize(string name,
            NameValueCollection config)
         {
            // Verify that config isn't null
            if (config == null)
               throw new ArgumentNullException("config");
            // Assign the provider a default name if it doesn't have one
            if (String.IsNullOrEmpty(name))
               name = "ReadOnlyXmlMembershipProvider";
            // Add a default "description" attribute to config if the
            // attribute doesn't exist or is empty
            if (string.IsNullOrEmpty(config["description"]))
            {
               config.Remove("description");
               config.Add("description",
                  "Read-only XML membership provider");
            }
            // Call the base class's Initialize method
            base.Initialize(name, config);
            // Initialize _XmlFileName and make sure the path
            // is app-relative
            string path = config["xmlFileName"];
            if (String.IsNullOrEmpty(path))
               path = "~/App_Data/Users.xml";
            if (!VirtualPathUtility.IsAppRelative(path))
               throw new ArgumentException
                  ("xmlFileName must be app-relative");
            string fullyQualifiedPath = VirtualPathUtility.Combine
               (VirtualPathUtility.AppendTrailingSlash
               (HttpRuntime.AppDomainAppVirtualPath), path);
            _XmlFileName = HostingEnvironment.MapPath(fullyQualifiedPath);
            config.Remove("xmlFileName");
            // Make sure we have permission to read the XML data source and
            // throw an exception if we don't
            FileIOPermission permission =
               new FileIOPermission(FileIOPermissionAccess.Read,
                  _XmlFileName);
            permission.Demand();
            // Throw an exception if unrecognized attributes remain
            if (config.Count > 0)
            {
               string attr = config.GetKey(0);
               if (!String.IsNullOrEmpty(attr))
                  throw new ProviderException
                      ("Unrecognized attribute: " + attr);
            }
         }
      
         public override bool ValidateUser(string username, string password)
         {
            // Validate input parameters
            if (String.IsNullOrEmpty(username) ||
               String.IsNullOrEmpty(password))
                  return false;
            try
            {
               // Make sure the data source has been loaded
               ReadMembershipDataStore();
               // Validate the user name and password
               MembershipUser user;
               if (_Users.TryGetValue(username, out user))
               {
                  if (user.Comment == password) // Case-sensitive
                  {
                     // NOTE: A read/write membership provider
                     // would update the user's LastLoginDate here.
                     // A fully featured provider would also fire
                     // an AuditMembershipAuthenticationSuccess
                     // Web event
                     return true;
                  }
               }
               // NOTE: A fully featured membership provider would
               // fire an AuditMembershipAuthenticationFailure
               // Web event here
               return false;
            }
            catch (Exception)
            {
               return false;
            }
         }
      
         public override MembershipUser GetUser(string username,
            bool userIsOnline)
         {
            // Note: This implementation ignores userIsOnline
            // Validate input parameters
               if (String.IsNullOrEmpty(username))
               return null;
            // Make sure the data source has been loaded
            ReadMembershipDataStore();
            // Retrieve the user from the data source
            MembershipUser user;
            if (_Users.TryGetValue(username, out user))
               return user;
            return null;
         }
      
         public override MembershipUserCollection GetAllUsers(int pageIndex,
            int pageSize, out int totalRecords)
         {
            // Note: This implementation ignores pageIndex and pageSize,
            // and it doesn't sort the MembershipUser objects returned
            // Make sure the data source has been loaded
            ReadMembershipDataStore();
            MembershipUserCollection users =
               new MembershipUserCollection();
            foreach (KeyValuePair<string, MembershipUser> pair in _Users)
               users.Add(pair.Value);
            totalRecords = users.Count;
            return users;
         }
      
         public override int GetNumberOfUsersOnline()
         {
            throw new NotSupportedException();
         }
      
         public override bool ChangePassword(string username,
            string oldPassword, string newPassword)
         {
            throw new NotSupportedException();
         }
      
         public override bool
            ChangePasswordQuestionAndAnswer(string username,
            string password, string newPasswordQuestion,
            string newPasswordAnswer)
         {
            throw new NotSupportedException();
         }
      
         public override MembershipUser CreateUser(string username,
            string password, string email, string passwordQuestion,
            string passwordAnswer, bool isApproved, object providerUserKey,
            out MembershipCreateStatus status)
         {
            throw new NotSupportedException();
         }
      
         public override bool DeleteUser(string username,
            bool deleteAllRelatedData)
         {
            throw new NotSupportedException();
         }
      
         public override MembershipUserCollection
            FindUsersByEmail(string emailToMatch, int pageIndex,
            int pageSize, out int totalRecords)
         {
            throw new NotSupportedException();
         }
      
         public override MembershipUserCollection
            FindUsersByName(string usernameToMatch, int pageIndex,
            int pageSize, out int totalRecords)
         {
            throw new NotSupportedException();
         }
      
         public override string GetPassword(string username, string answer)
         {
            throw new NotSupportedException();
         }
      
         public override MembershipUser GetUser(object providerUserKey,
            bool userIsOnline)
         {
            throw new NotSupportedException();
         }
      
         public override string GetUserNameByEmail(string email)
         {
            throw new NotSupportedException();
         }
      
         public override string ResetPassword(string username,
            string answer)
         {
            throw new NotSupportedException();
         }
      
         public override bool UnlockUser(string userName)
         {
            throw new NotSupportedException();
         }
      
         public override void UpdateUser(MembershipUser user)
         {
            throw new NotSupportedException();
         }
      
         // Helper method
         private void ReadMembershipDataStore()
         {
            lock (this)
            {
               if (_Users == null)
               {
                  _Users = new Dictionary<string, MembershipUser>
                     (16, StringComparer.InvariantCultureIgnoreCase);
                  XmlDocument doc = new XmlDocument();
                  doc.Load(_XmlFileName);
                  XmlNodeList nodes = doc.GetElementsByTagName("User");
                  foreach (XmlNode node in nodes)
                  {
                     MembershipUser user = new MembershipUser(
                        Name,                       // Provider name
                        node["UserName"].InnerText, // Username
                        null,                       // providerUserKey
                        node["EMail"].InnerText,    // Email
                        String.Empty,               // passwordQuestion
                        node["Password"].InnerText, // Comment
                        true,                       // isApproved
                        false,                      // isLockedOut
                        DateTime.Now,               // creationDate
                        DateTime.Now,               // lastLoginDate
                        DateTime.Now,               // lastActivityDate
                        DateTime.Now,               // lastPasswordChangedDate
                        new DateTime(1980, 1, 1)    // lastLockoutDate
                     );
                     _Users.Add(user.UserName, user);
                  }
               }
            }
         }
      }
      
  2. Add a new class to the ReadOnlyXmlRoleProvider project:

    • In the solution explorer, right-click the ReadOnlyXmlRoleProvider project, then Add, then Class...

    • Name the class ReadOnlyXmlRoleProvider.cs.

    • Click Add.

    • Remove the existing code.

    • Paste the following sample code from the Role Providers topic into the editor:

      using System;
      using System.Web.Security;
      using System.Collections.Generic;
      using System.Collections.Specialized;
      using System.Configuration.Provider;
      using System.Web.Hosting;
      using System.Xml;
      using System.Security.Permissions;
      using System.Web;
      
      public class ReadOnlyXmlRoleProvider : RoleProvider
      {
         private Dictionary<string, string[]> _UsersAndRoles =
         new Dictionary<string, string[]>(16,
         StringComparer.InvariantCultureIgnoreCase);
      
         private Dictionary<string, string[]> _RolesAndUsers =
            new Dictionary<string, string[]>(16,
            StringComparer.InvariantCultureIgnoreCase);
      
         private string _XmlFileName;
      
         // RoleProvider properties
         public override string ApplicationName
         {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
         }
      
         // RoleProvider methods
         public override void Initialize(string name,
         NameValueCollection config)
         {
            // Verify that config isn't null
            if (config == null)
               throw new ArgumentNullException("config");
            // Assign the provider a default name if it doesn't have one
            if (String.IsNullOrEmpty(name))
               name = "ReadOnlyXmlRoleProvider";
            // Add a default "description" attribute to config if the
            // attribute doesn't exist or is empty
            if (string.IsNullOrEmpty(config["description"]))
            {
               config.Remove("description");
               config.Add("description", "Read-only XML role provider");
            }
            // Call the base class's Initialize method
            base.Initialize(name, config);
            // Initialize _XmlFileName and make sure the path
            // is app-relative
            string path = config["xmlFileName"];
            if (String.IsNullOrEmpty(path))
               path = "~/App_Data/Users.xml";
            if (!VirtualPathUtility.IsAppRelative(path))
               throw new ArgumentException
                  ("xmlFileName must be app-relative");
            string fullyQualifiedPath = VirtualPathUtility.Combine
               (VirtualPathUtility.AppendTrailingSlash
               (HttpRuntime.AppDomainAppVirtualPath), path);
            _XmlFileName = HostingEnvironment.MapPath(fullyQualifiedPath);
            config.Remove("xmlFileName");
            // Make sure we have permission to read the XML data source and
            // throw an exception if we don't
            FileIOPermission permission =
               new FileIOPermission(FileIOPermissionAccess.Read,
                  _XmlFileName);
            permission.Demand();
            // Throw an exception if unrecognized attributes remain
            if (config.Count > 0)
            {
               string attr = config.GetKey(0);
               if (!String.IsNullOrEmpty(attr))
                  throw new ProviderException
                     ("Unrecognized attribute: " + attr);
            }
            // Read the role data source. NOTE: Unlike
            // ReadOnlyXmlMembershipProvider, this provider can
            // read the data source at this point because Read-
            // RoleDataStore doesn't call into the role manager
            ReadRoleDataStore();
         }
      
         public override bool IsUserInRole(string username, string roleName)
         {
            // Validate input parameters
            if (username == null || roleName == null)
               throw new ArgumentNullException();
            if (username == String.Empty || roleName == string.Empty)
               throw new ArgumentException();
            // Make sure the user name and role name are valid
            if (!_UsersAndRoles.ContainsKey(username))
               throw new ProviderException("Invalid user name");
            if (!_RolesAndUsers.ContainsKey(roleName))
               throw new ProviderException("Invalid role name");
            // Determine whether the user is in the specified role 
            string[] roles = _UsersAndRoles[username];
            foreach (string role in roles)
            {
               if (String.Compare(role, roleName, true) == 0)
                  return true;
            }
            return false;
         }
      
         public override string[] GetRolesForUser(string username)
         {
            // Validate input parameters
            if (username == null)
               throw new ArgumentNullException();
            if (username == string.Empty)
               throw new ArgumentException();
            // Make sure the user name is valid
            string[] roles;
            if (!_UsersAndRoles.TryGetValue(username, out roles))
               throw new ProviderException("Invalid user name");
            // Return role names
            return roles;
         }
      
         public override string[] GetUsersInRole(string roleName)
         {
            // Validate input parameters
            if (roleName == null)
               throw new ArgumentNullException();
            if (roleName == string.Empty)
            throw new ArgumentException();
            // Make sure the role name is valid
            string[] users;
            if (!_RolesAndUsers.TryGetValue(roleName, out users))
               throw new ProviderException("Invalid role name");
            // Return user names
            return users;
         }
      
         public override string[] GetAllRoles()
         {
            int i = 0;
            string[] roles = new string[_RolesAndUsers.Count];
            foreach (KeyValuePair<string, string[]> pair in _RolesAndUsers)
               roles[i++] = pair.Key;
            return roles;
         }
      
         public override bool RoleExists(string roleName)
         {
            // Validate input parameters
            if (roleName == null)
               throw new ArgumentNullException();
            if (roleName == string.Empty)
               throw new ArgumentException();
            // Determine whether the role exists
            return _RolesAndUsers.ContainsKey(roleName);
         }
      
         public override void CreateRole(string roleName)
         {
            throw new NotSupportedException();
         }
      
         public override bool DeleteRole(string roleName,
            bool throwOnPopulatedRole)
         {
            throw new NotSupportedException();
         }
      
         public override void AddUsersToRoles(string[] usernames,
            string[] roleNames)
         {
            throw new NotSupportedException();
         }
      
         public override string[] FindUsersInRole(string roleName,
            string usernameToMatch)
         {
            throw new NotSupportedException();
         }
      
         public override void RemoveUsersFromRoles(string[] usernames,
            string[] roleNames)
         {
            throw new NotSupportedException();
         }
      
         // Helper method
         private void ReadRoleDataStore()
         {
            XmlDocument doc = new XmlDocument();
            doc.Load(_XmlFileName);
            XmlNodeList nodes = doc.GetElementsByTagName("User");
            foreach (XmlNode node in nodes)
            {
               if (node["UserName"] == null)
                  throw new ProviderException
                     ("Missing UserName element");
               string user = node["UserName"].InnerText;
               if (String.IsNullOrEmpty(user))
                  throw new ProviderException("Empty UserName element");
               if (node["Roles"] == null ||
                  String.IsNullOrEmpty(node["Roles"].InnerText))
                     _UsersAndRoles.Add(user, new string[0]);
               else
               {
                  string[] roles = node["Roles"].InnerText.Split(',');
                  // Add the role names to _UsersAndRoles and
                  // key them by user name
                  _UsersAndRoles.Add(user, roles);
                  foreach (string role in roles)
                  {
                     // Add the user name to _RolesAndUsers and
                     // key it by role names
                     string[] users1;
                     if (_RolesAndUsers.TryGetValue(role, out users1))
                     {
                        string[] users2 =
                           new string[users1.Length + 1];
                        users1.CopyTo(users2, 0);
                        users2[users1.Length] = user;
                        _RolesAndUsers.Remove(role);
                        _RolesAndUsers.Add(role, users2);
                     }
                     else
                        _RolesAndUsers.Add(role,
                     new string[] { user });
                  }
               }
            }
         }
      }
      
  3. Save and compile both projects.

Note

If you did not use the optional steps to register the assemblies in the GAC, you will need to manually copy the assemblies to your IIS computer and add the assemblies to the GAC using the Gacutil.exe tool. For more information, see the following topic on Microsoft the MSDN Web site:

Step 3: Add the providers to IIS

In this third step you will determine the assembly information for the membership and role providers, and then add that information to the list of trusted providers for IIS.

  1. Determine the assembly information for both providers:

    • In Windows Explorer, open your C:\Windows\assembly path, where C: is your operating system drive.
    • Locate the ReadOnlyXmlMembershipProvider and ReadOnlyXmlRoleProvider assemblies.
    • Right-click each assembly and click Properties.
    • Copy the Culture values; for example: Neutral.
    • Copy the Version numbers; for example: 1.0.0.0.
    • Copy the Public Key Token values; for example: 426f62526f636b73.
    • Click Cancel.
  2. Add the XML providers to the list of trusted providers for IIS:

    • Open the Administration.config file for editing.

      Note

      This file is located in your %WinDir%\System32\Inetsrv\Config folder.

    • Add the providers with the assembly properties from the previous steps to the <trustedProviders> section using the following syntax:

      <add type="ReadOnlyXmlMembershipProvider, ReadOnlyXmlMembershipProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=426f62526f636b73" />
      
      <add type="ReadOnlyXmlRoleProvider, ReadOnlyXmlRoleProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=426f62526f636b73" />
      
    • Save and close the Administration.config file.

Step 4: Configure a site for Forms Authentication using the XML providers

In this fourth step you will configure a Web site to use forms authentication with the XML-based membership and role providers by manually creating a Web.config file for your Web site, adding an XML file with the list of users to the Web site's App_Data folder, and adding a Login.aspx page to the Web site that will process forms authentication requests.

  1. Create an XML file for the membership users and roles:

    • Paste the following code into a text editor:

      <Users>
         <User>
            <UserName>Bob</UserName>
            <Password>contoso!</Password>
            <EMail>bob@contoso.com</EMail>
            <Roles>Members</Roles>
         </User>
         <User>
            <UserName>Alice</UserName>
            <Password>contoso!</Password>
            <EMail>alice@contoso.com</EMail>
            <Roles>Members,Administrators</Roles>
         </User>
      </Users>
      
    • Save the code as "Users.xml" in the App_Data folder of your Web site.

  2. Create a Login.aspx file for your Web site:

    • Paste the following code into a text editor:

      <%@ Page Language="C#" %>
      <%@ Import Namespace="System.ComponentModel" %>
      <html>
      <head runat="server">
      <title>Login Page</title>
      </head>
      <body>
         <form id="form1" runat="server">
            <asp:Login id="Login1" runat="server"
                  BorderStyle="Solid"
                  BackColor="#ffffcc"
                  BorderWidth="1px"
                  BorderColor="#cccc99"
                  Font-Size="10pt"
                  Font-Names="Verdana">
               <TitleTextStyle Font-Bold="True"
                  ForeColor="#ffffff"
                  BackColor="#666666"/>
            </asp:Login>
         </form>
      </body>
      </html>
      
    • Save the code as "Login.aspx" in the root of your Web site.

  3. Create a Web.config file for your Web site:

    • Paste the following code into a text editor:

      <configuration>
         <system.web>
            <!-- Add the read-only XML membership provider and set it as the default. -->
            <membership defaultProvider="AspNetReadOnlyXmlMembershipProvider">
               <providers>
                  <add name="AspNetReadOnlyXmlMembershipProvider"
                     type="ReadOnlyXmlMembershipProvider, ReadOnlyXmlMembershipProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=91454274822e8111"
                     description="Read-only XML membership provider"
                     xmlFileName="~/App_Data/Users.xml" />
               </providers>
            </membership>
            <!-- Add the read-only XML role provider and set it as the default. -->
            <roleManager enabled="true" defaultProvider="AspNetReadOnlyXmlRoleProvider">
               <providers>
                  <add name="AspNetReadOnlyXmlRoleProvider"
                     type="ReadOnlyXmlRoleProvider, ReadOnlyXmlRoleProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a9c0f8ad39898a3c"
                     description="Read-only XML role provider"
                     xmlFileName="~/App_Data/Users.xml" />
               </providers>
            </roleManager>
            <!-- Set the authentication mode to forms authentication. -->
            <authentication mode="Forms" />
         </system.web>
         <system.webServer>
            <!-- Configure the authentication and roles modules for all content. -->
            <modules>
               <remove name="RoleManager" />
               <remove name="DefaultAuthentication" />
               <remove name="FormsAuthentication" />
               <add name="FormsAuthentication"
                  type="System.Web.Security.FormsAuthenticationModule"
                  preCondition="" />
               <add name="DefaultAuthentication"
                  type="System.Web.Security.DefaultAuthenticationModule"
                  preCondition="" />
               <add name="RoleManager"
                  type="System.Web.Security.RoleManagerModule"
                  preCondition="" />
            </modules>
            <!-- Add authorization rules for membership roles. -->
            <security>
               <authorization>
                  <clear />
                  <add accessType="Allow" roles="Administrators" />
                  <add accessType="Allow" roles="Members" />
               </authorization>
            </security>
         </system.webServer>
      </configuration>
      

      Note

      The PublicKeyToken values in the <providers> sections your web.config must match the PublicKeyToken values in the <trustedProviders> section of your Administration.config file.

    • Save the code as "Web.config" in the root of your Web site.

Summary

In this walkthrough, you completed the following:

  • Set up two class projects in Visual Studio 2008 for the read-only XML membership and role providers.
  • Compiled the projects and added them to the Global Assembly Cache.
  • Added the XML membership and role providers as trusted providers for IIS.
  • Configured a Web site for Forms Authentication using the XML providers.