Сделать структуру объектов соединения динамической

#c# #entity-framework

#c# #entity-framework

Вопрос:

У меня есть строка подключения, и я могу сделать это без проблем

 <connectionStrings>
    <add name="DbName" 
         connectionString="server=serverName;database=DbTest;user=x;pwd=xxx;"
         providerName="System.Data.SqlClient"  />
</connectionStrings>
  

и у меня есть соединение Entity Framework:

 public DbContext1() : base("DbName")
{
}
  

Но мне нужно сделать запрос DbContext1 , чтобы получить новое строковое соединение из таблицы для подключения к другой базе данных, но я не знаю, как использовать строковое соединение, которое я получаю из запроса.

Как я могу использовать строковое соединение из таблицы для создания нового DbContext ?

Ответ №1:

Сделайте что-то вроде этого:

 public DbContext1(string connString) : base(connString)
{
}
  

Конструктор, который требуется вызвать вашему производному классу, — это этот. Аргумент string обрабатывается либо как сама допустимая строка подключения, либо как имя строки подключения.

Ответ №2:

Это похоже на многопользовательский сценарий, в котором пользователи проходят аутентификацию в центральной базе данных, а затем направляются к определенному экземпляру базы данных, содержащему их собственные данные. В качестве простого примера во время аутентификации:

 using (var context = new AuthDbContext())
{ // Where AuthDbContext is the central DB containing authentication and the connection string to that user's home database..
     // ... On successful authentication...
     var connectionString = context.Tenants
         .Where(x => x.TenantId == authenticatedUser.TenantId)
         .Select(x => x.ConnectionString)
         .Single();
}
  

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

Затем создайте класс AppDbContextFactory или класс шаблона UnitOfWork для внедрения в ваши службы / контроллеры, чтобы предоставить DbContext на основе строки подключения текущего пользователя.

В качестве очень простого примера:

 public interface IUserStateFacade
{
    string CurrentUserConnectionString { get; }
}

public class UserSessionState : IUserStateFacade
{
   public const string UserStateSessionName = "UserState";
   public string CurrentUserConnectionString
   {
       get 
       {
           var userState = (UserSessionState)Session[UserStateSessionName] ?? throw new ApplicationException("Session state missing/expired.");
           return userState.ConnectionString;
       }
   }
}

public interface IAppContextFactory
{
    AppContext Create();
}

public class AppContextFactory
{
    private readonly IUserStateFacade _userState = null;
   
    public AppContextFactory(IUserStateFacade userState)
    {
        _userState = userState ?? throw new ArgumentNullException("userState");
    }
    
    /// <summary>
    /// Create a DbContext. Calling code is responsible for disposing.
    /// </summary>
    public AppContext Create()
    {
        return new AppContext(_userState.ConnectionString);
    }
}
  

Затем в ваших контроллерах и т. Д., Которые обычно хотели бы создать или внедрить DbContext с конструктором по умолчанию, вместо этого использовали бы что-то вроде:

 using (var context = AppContextFactory.Create())
{ }
  

или ввести значение, инициализированное через AppContextFactory.

Для ASP.Net apps, использующие сеанс, вам может потребоваться завершить Session , чтобы библиотека внедрения зависимостей могла разрешить строку подключения / структуру пользователя из текущего состояния сеанса.

Опять же, это лишь очень элементарный пример, описывающий вариант упрощения динамических строк подключения, предполагающий что-то вроде ASP.Сетевое веб-приложение. Следует рассмотреть дополнительные меры безопасности, но, надеюсь, это должно дать некоторые идеи о том, как это можно структурировать.