65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Membership 和 Profile API 的多个配置文件

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.68/5 (10投票s)

2008年3月10日

CPOL

6分钟阅读

viewsIcon

41219

downloadIcon

381

使用 Membership 和 Profile API 实现和维护用户的多个配置文件。

screen_shot_small.JPG

引言

ASP.NET 的 Membership 功能正是为此而生,使其更好、更容易。Membership 功能提供安全的凭据存储,并附带简单易用的 API。它现在是平台的一部分,无需您反复开发用于用户身份验证的基础设施功能。更重要的是,它是平台的可插拔部分,通过新的提供程序模式,您可以轻松扩展系统(例如,添加对 LDAP 或现有公司用户帐户系统的支持)。

Profile API 可以存储有关访问网站的已认证和匿名用户任意属性(例如,他们的邮政编码、性别、主题偏好等)。因此,在本文中,我将解释如何使用 Profile API 实现用户数据的多重配置文件。任何用户都可以通过此过程或系统以结构化的方式维护不同类型的配置文件和这些配置文件下的属性。还有各种检索这些配置文件信息的方式。这将有助于有效的搜索。

重要提示:在运行“演示项目”之前,请按照分步解决方案中的步骤设置 Membership 和 Profile API 的数据库架构,并在 web.config 文件中更改连接字符串的初始目录(“数据库名称”)。

背景

我曾在一个负责集中身份验证和配置文件保存的项目中工作。其中有一些需求是用户可以保存任意数量的属性,并将这些属性以结构化的方式保存,以便用户可以随时声明其任何配置文件属性。当时,我进行了一些研发,并使用 Membership 和 Profile API 找到了最佳解决方案。

Using the Code

以下是使用 Profile API 创建和维护用户多重配置文件的分步解决方案。

  1. 将 ASP.NET 2.0 应用程序服务配置为使用 SQL Server 2000 或 SQL Server 2005,这将有助于我们设置新的 ASP.NET Membership、角色管理、Profile 和 Personalization 服务。请遵循此处 URL 配置 ASP.NET 2.0 应用程序服务。ScottGu 提供了一篇非常好的文章
  2. 使用 Visual Studio 或任何其他 Visual IDE 创建一个空白网站。
  3. 现在,您需要在新打开的应用程序的 web.config 文件中的 <system.web> </system.web> 标记下添加/更改一些配置设置。Membership 和 Profile API 需要此配置。
  4. 配置 Membership

    <membership defaultProvider="MembershipTestSqlProvider" userIsOnlineTimeWindow="30">
        <providers>
            <add name="MembershipTestSqlProvider"
                 type="System.Web.Security.SqlMembershipProvider, System.Web,
                 Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                 connectionStringName="MembershipTestConnectionString" 
                 enablePasswordRetrieval="false" enablePasswordReset="true"
                 requiresQuestionAndAnswer="false" applicationName="/"
                 requiresUniqueEmail="false" passwordFormat="Hashed" 
                 minRequiredPasswordLength="6"
                 passwordStrengthRegularExpression="" 
                 minRequiredNonalphanumericCharacters="0"/>
        </providers>
    </membership>

    在上面的块中,您需要添加一个提供程序以在您的应用程序中启用 Membership API。我在示例中添加了一个默认提供程序,"System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",但如果您愿意,可以添加自己的或修改过的提供程序。另一个强制性参数是 connectionStringName。只需提供您的数据库连接字符串名称,它在您的 web.config 文件中可用。其他参数是可选的(根据您的需求使用)。

    配置 Profile

    <profile defaultProvider="ProfileTestSqlProvider" enabled="true">
        <providers>
            <add name="ProfileTestSqlProvider"
                 type="System.Web.Profile.SqlProfileProvider,System.Web,
                 Version=2.0.3600.0, Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" 
                 connectionStringName="MembershipTestConnectionString" applicationName="/"
                 description="Stores and retrieves personalization data from 
                 the local Microsoft SQL Server database"/>
        </providers>
            
        <properties>
            <group name="UsersPersonalInfo">
                <add name="properties_block" type=
                "System.Collections.Generic.Dictionary`2[System.string,System.object]" 
                serializeAs="Binary"/>
            </group>
            <group name="UsersOfficialInfo">
                <add name="properties_block" type=
                    "System.Collections.Generic.Dictionary`2[System.string,System.object]" 
                    serializeAs="Binary"/>
            </group>
        </properties>
    </profile>

    同样,对于 Profile API,您需要添加一个带有 connectionStringNameapplicationName 参数的提供程序。此外,您需要添加另一个名为 <properties> </properties> 的标记。此标记包含组,并在每个组下添加一个字典来保存配置文件的属性。您可以定义任意数量的组。在我的示例中有两个组,它们代表两种配置文件类型:UsersPersonalInfoUsersOfficialInfo。这意味着,在此示例中,每个用户最多可以保存两种类型的配置文件。但是,在每个组或配置文件类型下,您可以在 Dictionary 中定义任意数量的用户属性,以 ([key],[value]) 对的形式。

  5. 创建一个名为 ProfileManagementHelper.cs 的类文件,并在其中添加一些方法。方法如下:

设置配置文件的 G 方法

public string SetProfile(string groupName,string userName,
       Dictionary<string,object> userProfile)
{
    if(Membership.GetUser(userName) == null)
                Membership.CreateUser(userName,"1234567");
        try
        {
           ProfileCommon pc = new ProfileCommon();
           ProfileCommon existing_pc = pc.GetProfile(userName);
           existing_pc.GetProfileGroup(groupName).SetPropertyValue(
               "properties_block",userProfile);
                
           existing_pc.Save();
                
        }
        catch(Exception e)
        {
           return "error!!" + e;
        }
       
    return "success";
}

上述方法负责为特定用户和组/配置文件类型设置配置文件。还有一个类型为 Dictionary 的参数;此参数包含配置文件属性,格式为 ([key],[value]) 对。您必须在应用程序层填充此字典。此方法首先检查给定用户是否已存在。如果不存在,则首先使用 Membership.CreateUser(string UserName,string password) 创建用户。在这里,我为所有用户提供了一个虚拟密码。因为,对于这个特定的示例,密码并不是那么重要。之后,创建 ProfileCommon 类的实例(使用给定的 UserName),检索该用户的配置文件类型,然后通过调用 SetPropertyValue(string propertyName,object propertyValue) 来设置属性。最后,调用 Save() 方法将所有更改最终保存到数据库。

获取配置文件的 G 方法

public Dictionary<string,object> GetProfilesByUser(string userName)
{
    Dictionary<string, object> profileListDictionary = 
        new Dictionary<string, object>();
        
    ProfileCommon pc = new ProfileCommon();
    ProfileCommon existing_pc = pc.GetProfile(userName);

    string []groupNameArray = Enum.GetNames(typeof(ProfileTypeEnum));

    for(int i=0;i<groupNameArray.Length;i++)
    {
        Dictionary<string,object> profileDictionary =
            (Dictionary<string,object>)existing_pc.GetProfileGroup(groupNameArray[i]
            ).GetPropertyValue("properties_block");
            
        if(profileDictionary.Keys.Count > 0)
                profileListDictionary.Add(groupNameArray[i],profileDictionary);
    }

    return profileListDictionary;
}

此方法负责从数据库检索给定用户的所有配置文件,并将它们绑定到一个字典中以供返回。返回的字典以 GroupName/ProfileTypeName 作为键,并以包含相应 GroupName/ProfileTypeName 所有属性的字典作为值。

public Dictionary<string,object> GetProfilesByUser(string userName,
                                 ArrayList propertyNameList)
{
    Dictionary<string, object> profileListDictionary = 
                          new Dictionary<string, object>();
            
    ProfileCommon pc = new ProfileCommon();
    ProfileCommon existing_pc = pc.GetProfile(userName);
            
    string []groupNameArray = Enum.GetNames(typeof(ProfileTypeEnum));
   
    for(int i=0;i<groupNameArray.Length;i++)
    {
        Dictionary<string,object> profileDictionary = 
            (Dictionary<string,object>)existing_pc.GetProfileGroup(
            groupNameArray[i]).GetPropertyValue("properties_block");
                
        if(profileDictionary.Keys.Count > 0)
        {
              propertyDepth = "";
              Dictionary<string, object>       selectedPropertiesDictionary = 
                  new  Dictionary<string,object>();
                    
              selectedPropertiesDictionary = FindProperties(profileDictionary,
                  selectedPropertiesDictionary,propertyNameList);
             
              if(selectedPropertiesDictionary.Keys.Count > 0)
                      profileListDictionary.Add(groupNameArray[i],
                      selectedPropertiesDictionary);
         }
     }
            
     return profileListDictionary;
}

这是前一个方法的重载。它包含一个额外的参数,名为 propertyNameList,类型为 ArrayList。此方法负责仅检索给定用户中存在于 propertyNameList 中的属性。

public Dictionary<string,object> GetProfilesByGroup(string groupName)
{
    Dictionary<string, object> profileListDictionary = 
        new Dictionary<string, object>();
            
    ProfileCommon pc = new ProfileCommon();
           
    MembershipUserCollection userList = Membership.GetAllUsers();
        
    foreach(MembershipUser user in userList)
    {
        ProfileCommon existing_pc = pc.GetProfile(user.UserName);

        Dictionary<string,object> profileDictionary = 
            (Dictionary<string,object>)existing_pc.GetProfileGroup(groupName
            ).GetPropertyValue("properties_block");
                
        if(profileDictionary.Keys.Count > 0)
            profileListDictionary.Add(user.UserName,profileDictionary);
            
    }
            
    return profileListDictionary;
}

上述方法通过其参数 groupName 来帮助检索所有用户指定的配置文件。返回的字典以 UserName 作为键,并以包含相应 User 所有属性的字典作为值。

public Dictionary<string,object> GetProfilesByGroup(string groupName, 
                  ArrayList propertyNameList)
{
    Dictionary<string, object> profileListDictionary = new Dictionary<string, object>();
            
    ProfileCommon pc = new ProfileCommon();
           
    MembershipUserCollection userList = Membership.GetAllUsers();
            
    foreach(MembershipUser user in userList)
    {
        ProfileCommon existing_pc = pc.GetProfile(user.UserName);

        Dictionary<string,object> profileDictionary = 
            (Dictionary<string,object>)existing_pc.GetProfileGroup(
            groupName).GetPropertyValue("properties_block");
                
                if(profileDictionary.Keys.Count > 0)
                {
                propertyDepth = "";

            Dictionary<string, object>   selectedPropertiesDictionary = 
                new Dictionary<string,object>();

            selectedPropertiesDictionary = FindProperties(profileDictionary,
                selectedPropertiesDictionary,propertyNameList);
             
                      if(selectedPropertiesDictionary.Keys.Count > 0)
                            profileListDictionary.Add(user.UserName,
                            selectedPropertiesDictionary);
                }
            
     }
            
     return profileListDictionary;
}

这是前一个方法的重载。它包含一个额外的参数,名为 propertyNameList,类型为 ArrayList。此方法负责仅检索所有用户中指定 groupName 的、存在于 propertyNameList 中的属性。

public Dictionary<string,object> GetProfileByUserGroup(string userName,string groupName)
{
    ProfileCommon pc = new ProfileCommon();
        ProfileCommon existing_pc = pc.GetProfile(userName);
              
    Return (Dictionary<string,object>)existing_pc.GetProfileGroup(
        groupName).GetPropertyValue("properties_block");
}

此方法检索给定 userNamegroupName/profileType 的所有属性。返回的字典以属性名作为键,以属性值作为值。

public Dictionary<string,object> GetProfileByUserGroup(string  userName,
       string groupName,ArrayList propertyNameList)
{
    Dictionary<string, object> selectedPropertiesDictionary = 
        new Dictionary<string,object>();
            
    ProfileCommon pc = new ProfileCommon();
        ProfileCommon existing_pc = pc.GetProfile(userName);
            
    Dictionary<string,object> profileDictionary = 
        (Dictionary<string,object>)existing_pc.GetProfileGroup(groupName
        ).GetPropertyValue("properties_block");
                
    if(profileDictionary.Keys.Count > 0)
    {
        propertyDepth = "";
        selectedPropertiesDictionary =     
            FindProperties(profileDictionary,
            selectedPropertiesDictionary,propertyNameList);
    }
            
    return selectedPropertiesDictionary;
}

同样,上述方法是前一个方法的重载。它返回一个字典,其中仅包含特定用户和组/配置文件类型中存在于 propertyNameList 中的属性。

public Dictionary<string,object> GetTotalProfileCollection()
{
    Dictionary<string, object> profileListDictionary = new Dictionary<string, object>();
            
    MembershipUserCollection userList = Membership.GetAllUsers();
            
    foreach(MembershipUser user in userList)
    {
        ProfileCommon pc = new ProfileCommon();

        ProfileCommon existing_pc = pc.GetProfile(user.UserName);                
                
        string []groupNameArray = Enum.GetNames(typeof(ProfileTypeEnum));
       
        for(int i=0;i<groupNameArray.Length;i++)
        {
            Dictionary<string,object> profileDictionary = 
                (Dictionary<string,object>)existing_pc.GetProfileGroup(
                groupNameArray[i]).GetPropertyValue("properties_block");
                    
            if(profileDictionary.Keys.Count > 0)
                profileListDictionary.Add(user.UserName+"|"+groupNameArray[i],
                    profileDictionary);
        }
                
    }
            
    return profileListDictionary;
}

此方法负责检索所有用户和组/配置文件类型的所有配置文件。返回的字典以 user_name|merchant_Group_Name 作为键,并以包含所有属性的字典作为值。

public Dictionary<string,object> GetTotalProfileCollection(ArrayList propertyNameList)
{
    Dictionary<string, object> profileListDictionary = new Dictionary<string, object>();
            
    MembershipUserCollection userList = Membership.GetAllUsers();
            
    foreach(MembershipUser user in userList)
    {
        ProfileCommon pc = new ProfileCommon();
        ProfileCommon existing_pc = pc.GetProfile(user.UserName);
                
        string []groupNameArray = Enum.GetNames(typeof(ProfileTypeEnum));
       
        for(int i=0;i<groupNameArray.Length;i++)
        {
            Dictionary<string,object> profileDictionary = 
                (Dictionary<string,object>)existing_pc.GetProfileGroup(
                groupNameArray[i]).GetPropertyValue("properties_block");
                    
            if(profileDictionary.Keys.Count > 0)
            {
                propertyDepth = "";

                Dictionary<string, object> selectedPropertiesDictionary = 
                    new Dictionary<string,object>();
                        
                selectedPropertiesDictionary = FindProperties(
                    profileDictionary,selectedPropertiesDictionary,propertyNameList);
                 
                if(selectedPropertiesDictionary.Keys.Count > 0)
                        profileListDictionary.Add(
                        user.UserName+"|"+groupNameArray[i],
                        selectedPropertiesDictionary);
            }
        }
    }
            
    return profileListDictionary;
}

上述方法是前一个方法的重载。它检索并返回一个字典,其中仅包含 propertyNameList 参数中存在的属性。

public Dictionary<string,object> FindProperties(
       Dictionary<string,object> profileDictionary,Dictionary<string, 
       object> selectedPropertiesDictionary,ArrayList propertyNameList)
{
    foreach(object key in profileDictionary.Keys)
    {
        object value = profileDictionary[key.ToString()];
                
        if(value.GetType().Equals(typeof(
            System.Collections.Generic.Dictionary<string,object>)))
        {
            propertyDepth += key.ToString()+"|";

            FindProperties((Dictionary<string, object>)value,
                selectedPropertiesDictionary,propertyNameList);

            propertyDepth = propertyDepth.Substring(0,propertyDepth.LastIndexOf(
                key.ToString()+"|"));
        }
        else
        {
            if(propertyNameList.Contains(key.ToString()))
                   selectedPropertiesDictionary.Add(propertyDepth + 
                   key.ToString(),profileDictionary[key.ToString()]);
        }
     }
            
     return selectedPropertiesDictionary;
}

上述方法以递归方式查找字典中任何深度的指定属性,并将其添加到新的结果字典中。完成该过程后,返回结果字典。

G 方法用于删除/移除配置文件

public bool RemoveProfilesByUser(string userName)
{
    Return ProfileManager.DeleteProfile(userName);
}

负责从数据库完全移除/删除特定用户的所有类型的配置文件。

public bool RemoveProfileByUserGroup(string userName,string groupName)
{
    ProfileCommon pc = new ProfileCommon();
        ProfileCommon existing_pc = pc.GetProfile(userName);
        
    try{
        Dictionary<string,object> profile = 
            (Dictionary<string,object>)existing_pc.GetProfileGroup(
            groupName).GetPropertyValue("properties_block");  
        profile.Clear();
        if(!SetProfile(groupName,userName,profile).Equals("success"))
             return false;
    }
    catch(Exception e)
    {
        return false;
    }
            
    return true;
}

上述方法负责从特定用户配置文件类型中移除所有属性和值,但会保留一个空的实例。这意味着数据库中存在该特定用户的空配置文件。

public bool RemoveProfilePropertiesByUserGroup(string userName,
       string groupName,ArrayList propertyNameList)
{
    Dictionary<string, object> existPropertiesDictionary = 
        new Dictionary<string,object>();
            
    ProfileCommon pc = new ProfileCommon();
        ProfileCommon existing_pc = pc.GetProfile(userName);
            
    Dictionary<string,object> profileDictionary = 
        (Dictionary<string,object>)existing_pc.GetProfileGroup(
        groupName).GetPropertyValue("properties_block");
                
    if(profileDictionary.Keys.Count > 0)
    {
        propertyDepth = "";
        existPropertiesDictionary =DeleteProperties(profileDictionary,propertyNameList;
    }
            
    if(!SetProfile(groupName,userName,existPropertiesDictionary).Equals("success"))
        return false;

    return true;
}

上述方法仅移除特定用户配置文件类型中给定的属性。

public Dictionary<string,object> DeleteProperties(
       Dictionary<string,object> profileDictionary,ArrayList propertyNameList)
{
    string []keyCollection = new string[profileDictionary.Keys.Count];
    int j=0;
            
    foreach(object key in profileDictionary.Keys)
              keyCollection[j++] = key.ToString();

    for(int i=0;i<keyCollection.Length;i++)
    {
        string key = keyCollection[i];
        object value = profileDictionary[key];

        if(propertyNameList.Contains(key))
             profileDictionary.Remove(key);
        else if(value.GetType().Equals(typeof(
            System.Collections.Generic.Dictionary<string,object>)))
        {
             propertyDepth += key+"|";

             DeleteProperties((Dictionary<string, object>)value,propertyNameList);

             propertyDepth = propertyDepth.Substring(
                 0,propertyDepth.LastIndexOf(key.ToString()+"|"));
        }
     }
            
     return profileDictionary;
}

此方法通过递归方式查找 propertyNameList 中指定的属性,并删除这些属性。

关注点

在您为特定用户和组在数据库中设置了配置文件后,如果您愿意,可以手动观察 aspnet_Profile 表,以查看配置文件是否真的已插入。在这种情况下,您将看到行已成功插入,除了 PropertyValuesString 字段外,所有字段值都已填充。不用担心,该字段实际上包含值,但由于某些原因,SQL Server 图形界面无法显示该字符串。

© . All rights reserved.