Die*_*337 4 azure sqlmembershipprovider multi-tenant asp.net-mvc-3 azure-sql-database
我正在尝试使用多租户的ASP.NET MVC应用程序迁移到Azure(包括SQL Azure).每个客户都拥有自己的数据库,这些数据库是独立的,包括所有会员资格.
我们可以在初始化SqlMembershipProvider对象时将连接字符串设置为SqlMembershipProvider.但是,对不同子域(在同一会话中)的后续请求不会更改连接字符串.我找到了一个示例,其中实现重写了SqlMembershipProviders ConnectionString,但这在System.Web dll的4.0版本中是不可能的.
我们可以实现单个成员资格数据库并对其进行身份验证......但我们希望在此SAAS模型中保留客户凭据.
那么问题是如何为每个请求动态更改SQLMembershipProviders连接字符串?
Web.config文件
<membership defaultProvider="TenantMembershipProvider">
<providers>
<clear/>
<add name="TenantMembershipProvider" type="ABC.Infrastructure.MultiTenancy.TenantMembershipProvider, ABC"
connectionStringName="ApplicationServices" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false"
requiresUniqueEmail="false" passwordFormat="Clear" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/"/>
</providers>
</membership>
Run Code Online (Sandbox Code Playgroud)
TenantMembershipProvider.cs处理初始化
public class TenantMembershipProvider : SqlMembershipProvider
{
private SiteLinqSession _session;
private MasterSession _masterSession;
private static readonly Dictionary<string, Customer> _customers = new Dictionary<string, Customer>();
private static string _host;
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
string connectionString = GetConnectionString();
FieldInfo connectionStringField = GetType().BaseType.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
connectionStringField.SetValue(this, connectionString);
}
private string GetConnectionString()
{
var headers = HttpContext.Current.Request.Headers["Host"];
string[] host = headers.Split('.');
_host = host[0];
if (_host == "127") _host = "demo";
var customer = GetSite(_host);
return BuildTenantConnectionString(customer.ConnectionSetting);
}
private Customer GetSite(string host)
{
Customer customer;
//check dictionary if customer exists for the subdomain
_customers.TryGetValue(host, out customer);
if (customer != null)
return customer;
//if not get the customer record and add it to the dictionary
_masterSession = new MasterSession();
var customers = _masterSession.All<Customer>();
customer = customers.SingleOrDefault(x => x.SubDomain == _host);
if (customer != null)
_customers.Add(host, customer);
return customer;
}
private string BuildTenantConnectionString(ConnectionSetting setting)
{
return string.Format("Data Source={0};Initial Catalog={1};User Id={2};Password={3};", setting.DataSource, setting.Catalog, setting.Username, setting.Password);
}
}
Run Code Online (Sandbox Code Playgroud)
从Adam发布的链接中节省一些时间.
在Application_PreRequestHandlerExecute事件的Global.asax文件中
protected void Application_PreRequestHandlerExecute()
{
SetProviderConnectionString(GetConnectionString());
}
private void SetProviderConnectionString(string connectionString)
{
// Set private property of Membership, Role and Profile providers. Do not try this at home!!
var connectionStringField = Membership.Provider.GetType().GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
if (connectionStringField != null)
connectionStringField.SetValue(Membership.Provider, connectionString);
var roleField = Roles.Provider.GetType().GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
if (roleField != null)
roleField.SetValue(Roles.Provider, connectionString);
var profileField = ProfileManager.Provider.GetType().GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
if (profileField != null)
profileField.SetValue(ProfileManager.Provider, connectionString);
}
private string GetConnectionString()
{
return string.Format("Data Source={0};", @".\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|demo.mdf;User Instance=true");
}
Run Code Online (Sandbox Code Playgroud)
如果您创建了自定义membershipProvider,那么您将获得BaseType
var connectionStringField = Membership.Provider.GetType().BaseType.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
Run Code Online (Sandbox Code Playgroud)
我不确定这是否是最合适的解决方案,但它似乎已完成工作,以便为membershipProvider启用动态connectionString而无需自行滚动.虽然觉得有点hackish.
| 归档时间: |
|
| 查看次数: |
1761 次 |
| 最近记录: |