4

Я пытаюсь перейти на Azure (включая SQL Azure) с многопользовательским приложением ASP.NET MVC. Каждый клиент получает свою собственную базу данных, которая является автономной, включая все их учетные данные.Multi Tenant SQLMembershipProvider ASP.NET MVC

Мы можем установить строку подключения для SqlMembershipProvider при инициализации объекта SqlMembershipProvider. Однако последующие запросы к различным поддоменам (в том же сеансе) не меняют строку подключения. Я нашел пример, где реализация переопределяет SqlMembershipProviders ConnectionString, но это невозможно в версии 4.0 из dll System.Web.

Мы могли бы реализовать единую базу данных членства и пройти аутентификацию против этого ......, но мы хотели бы оставить учетные данные клиентов изолированными в этой модели 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> 

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); 

    } 
} 

ответ

1

Вы должны получить это в начале цикла обработки запроса в Application_PreRequestHandlerExecute

Примечание код из http://forums.asp.net/p/997608/2209437.aspx

Есть несколько способов, один, чтобы проверить код поставщика образец и использовать (я не думаю, что это то, что вы упомянули выше?) SqlConnectionHelper (Фрон по ссылке выше)

 
internal static string GetConnectionString(string specifiedConnectionString, bool lookupConnectionString, bool appLevel) 
{ 
    //Your Conn String goes here!! 
    return Factory.ConnectionString; 
} 

другой включает prerequestauthenticate. Вы могли бы сохранить строку в сеансе (установить ее при первом входе в систему) и указать ее в провайдере или использовать код, основанный на отражении, если все остальное не удается, хотя оно не выглядит чистым. Если это не сработает, вам нужно будет свернуть собственного провайдера.

+0

Спасибо. Я проверил образцы SQL-запросов инструментария asp.net в ссылке, которую вы указали выше. – Diesel337

+0

ok Инструментарий использует версию 2.0 .NET Framework, и похоже, что могут возникнуть некоторые проблемы с доступом к некоторым из лазурных библиотек. [Является ли Windows Azure совместимым с платформой .NET 2.0?] (Http://stackoverflow.com/questions/6442443/is-windows-azure-compatible-with-the-net-2-0-framework) – Diesel337

5

Чтобы сохранить людей в течение некоторого времени из ссылки, которую написал Adam.

В файле Global.asax для события Application_PreRequestHandlerExecute

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"); 
    } 

если вы создали пользовательский MembershipProvider тогда вы получите BaseType вместо

var connectionStringField = Membership.Provider.GetType().BaseType.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic); 

Я не уверен, если это наиболее подходящее решение, но, похоже, эта работа выполнена, чтобы получить динамическое соединение connectionString для членстваProvider, не сворачивая свои собственные. Чувствует себя немного хакерским.

+0

Я реализовал вышеуказанный код в своем проекте, но всегда получаю значения null для переменных connectionStringField, roleField, profileField. Любые идеи почему? Не могли бы вы поделиться своим сайтом.config, чтобы узнать, не пропал ли у меня что-нибудь в моем? ty – Todd

+0

Вы реализовали/распространили любые провайдеры? Если это так, вам может понадобиться получить базовый тип ex: connectionStringField = Membership.Provider.GetType(). BaseType.GetField ("_ sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic); –

 Смежные вопросы

  • Нет связанных вопросов^_^