在我的ASP.Net Framework 4 Web应用程序项目(VS 2010)中,我使用的是SqlTableProfileProvider(http://www.asp.net/downloads/sandbox/table-profile-provider-samples)。我让它与一组自定义属性(如FirstName,LastName,FavoritePizzaTopping等)非常合作。
但是,我想实现ArrayList,List,Dictionary或Collection类型的多值profile属性(无论哪个推荐)。
该属性将存储与用户关联的品牌列表。我在数据库中有一个存储UserId和BrandId的表,但我不确定如何实现这个概念。
我查看了http://msdn.microsoft.com/en-us/library/d8b58y5d(v=vs.100).aspx但我的属性未在web.config中定义,它们在ProfileCommon中定义:ProfileBase 。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Profile;
using System.Web.Security;
using AbcProfileProvider;
namespace Abc.Profiles
{
public class ProfileCommon : ProfileBase
{
public static ProfileCommon GetProfile()
{
return Create(HttpContext.Current.Request.IsAuthenticated ?
HttpContext.Current.User.Identity.Name : HttpContext.Current.Request.AnonymousID,
HttpContext.Current.Request.IsAuthenticated) as ProfileCommon;
}
public static ProfileCommon GetUserProfile(string username)
{
return Create(username) as ProfileCommon;
}
public static ProfileCommon GetUserProfile()
{
return Create(Membership.GetUser().UserName) as ProfileCommon;
}
[CustomProviderData("FirstName;nvarchar")]
public string FirstName
{
get { return ((string)(base["FirstName"])); }
set { base["FirstName"] = value; Save(); }
}
[CustomProviderData("LastName;nvarchar")]
public string LastName
{
get { return ((string)(base["LastName"])); }
set { base["LastName"] = value; Save(); }
}
[CustomProviderData("Address1;nvarchar")]
public string Address1
{
get { return ((string)(base["Address1"])); }
set { base["Address1"] = value; Save(); }
}
[CustomProviderData("Address2;nvarchar")]
public string Address2
{
get { return ((string)(base["Address2"])); }
set { base["Address2"] = value; Save(); }
}
[CustomProviderData("City;nvarchar")]
public string City
{
get { return ((string)(base["City"])); }
set { base["City"] = value; Save(); }
}
[CustomProviderData("State;nvarchar")]
public string State
{
get { return ((string)(base["State"])); }
set { base["State"] = value; Save(); }
}
[CustomProviderData("ZipCode;nvarchar")]
public string ZipCode
{
get { return ((string)(base["ZipCode"])); }
set { base["ZipCode"] = value; Save(); }
}
[CustomProviderData("Phone;nvarchar")]
public string Phone
{
get { return ((string)(base["Phone"])); }
set { base["Phone"] = value; Save(); }
}
[CustomProviderData("Fax;nvarchar")]
public string Fax
{
get { return ((string)(base["Fax"])); }
set { base["Fax"] = value; Save(); }
}
[CustomProviderData("Email;nvarchar")]
public string Email
{
get { return ((string)(base["Email"])); }
set { base["Email"] = value; Save(); }
}
[CustomProviderData("Brands")]
public List<Brand> Brands
{
get { return ((List<Brand>)(base["Brands"])); }
set { base["Brands"] = value; Save(); }
}
[CustomProviderData("Territories")]
public List<Territory> Territories
{
get { return ((List<Territory>)(base["Territories"])); }
set { base["Territories"] = value; Save(); }
}
}
}
我相信解决方案位于SqlProfileProvider.cs中,但我不确定如何实现它,以下是该文件中的两个方法(我会发布整个文件但有限制):
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection) {
SettingsPropertyValueCollection svc = new SettingsPropertyValueCollection();
if (collection == null || collection.Count < 1 || context == null)
return svc;
string username = (string)context["UserName"];
if (String.IsNullOrEmpty(username))
return svc;
SqlConnection conn = null;
try {
conn = new SqlConnection(_sqlConnectionString);
conn.Open();
GetProfileDataFromTable(collection, svc, username, conn);
}
finally {
if (conn != null) {
conn.Close();
}
}
return svc;
}
private void GetProfileDataFromTable(SettingsPropertyCollection properties, SettingsPropertyValueCollection svc, string username, SqlConnection conn) {
List<ProfileColumnData> columnData = new List<ProfileColumnData>(properties.Count);
StringBuilder commandText = new StringBuilder("SELECT u.UserID");
SqlCommand cmd = new SqlCommand(String.Empty, conn);
int columnCount = 0;
foreach (SettingsProperty prop in properties) {
SettingsPropertyValue value = new SettingsPropertyValue(prop);
svc.Add(value);
string persistenceData = prop.Attributes["CustomProviderData"] as string;
// If we can't find the table/column info we will ignore this data
if (String.IsNullOrEmpty(persistenceData)) {
// REVIEW: Perhaps we should throw instead?
continue;
}
string[] chunk = persistenceData.Split(new char[] { ';' });
if (chunk.Length != 2) {
// REVIEW: Perhaps we should throw instead?
continue;
}
string columnName = chunk[0];
string columnType = chunk[1];
if (columnType == "Table")
{
continue;
}
// REVIEW: Should we ignore case?
SqlDbType datatype = (SqlDbType)Enum.Parse(typeof(SqlDbType), chunk[1], true);
columnData.Add(new ProfileColumnData(columnName, value, null /* not needed for get */, datatype));
commandText.Append(", ");
commandText.Append("t."+columnName);
++columnCount;
}
commandText.Append(" FROM "+_table+" t, vw_aspnet_Users u WHERE u.ApplicationId = '").Append(AppId);
commandText.Append("' AND u.UserName = LOWER(@Username) AND t.UserID = u.UserID");
cmd.CommandText = commandText.ToString();
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("@Username", username);
SqlDataReader reader = null;
try {
reader = cmd.ExecuteReader();
//If no row exists in the database, then the default Profile values
//from configuration are used.
if (reader.Read()) {
Guid userId = reader.GetGuid(0);
for (int i = 0; i < columnData.Count; ++i) {
object val = reader.GetValue(i+1);
ProfileColumnData colData = columnData[i];
SettingsPropertyValue propValue = colData.PropertyValue;
//Only initialize a SettingsPropertyValue for non-null values
if (!(val is DBNull || val == null))
{
propValue.PropertyValue = val;
propValue.IsDirty = false;
propValue.Deserialized = true;
}
}
// need to close reader before we try to update the user
if (reader != null) {
reader.Close();
reader = null;
}
UpdateLastActivityDate(conn, userId);
}
}
finally {
if (reader != null) {
reader.Close();
}
}
}
以下是web.config的相关部分:
<membership>
<providers>
<clear />
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
<profile enabled="true" defaultProvider="TableProfileProvider" inherits="Abc.Profiles.ProfileCommon, AbcProfileProvider">
<providers>
<clear />
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="TableProfileProvider" type="Abc.ProfileProviders.SqlTableProfileProvider, AbcProfileProvider" connectionStringName="ApplicationServices" table="MembershipProfiles" applicationName="/" />
<add name="StoredProcedureProfileProvider" type="Abc.ProfileProviders.SqlStoredProcedureProfileProvider, AbcProfileProvider" connectionStringName="ApplicationServices" setProcedure="setCustomProfileData" readProcedure="getCustomProfileData" applicationName="/" />
</providers>
</profile>
<roleManager defaultProvider="NetSqlAzManRoleProvider" enabled="true" cacheRolesInCookie="false" cookieName=".ASPROLES" cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="All">
<providers>
<clear />
<add connectionStringName="ApplicationServices" applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" />
<add applicationName="/" name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" />
<add name="NetSqlAzManRoleProvider" type="NetSqlAzMan.Providers.NetSqlAzManRoleProvider" connectionStringName="NetSqlAzManConnectionString" storeName="Abc Authorization Store" applicationName="The App" userLookupType="DB" defaultDomain="" UseWCFCacheService="False" />
</providers>
</roleManager>
我希望StackOverflow上有人已经实现了这样的东西,或者能指出我正确的方向。
谢谢!