5

Ситуацияинъекционное/Управление во время выполнения меняющихся ConnectionStrings с использованием Entity Framework, Dependency Injection, единица работы и Repository Модели

Я строю веб-приложение, используя в названии упоминается методы. Это приложение будет похоже на систему CMS для нескольких клиентов. Клиент должен войти в эту систему, используя свои имя компании и учетные данные для входа. С предоставленным фирменным именем я подключаюсь к базе данных (статический DbContext, такая же строка соединения каждый раз), где хранятся все данные базы данных клиентов и поиск этой конкретной базы данных клиентов (каждый клиент имеет свою собственную с точно такой же конструкцией) информацию для входа. Все работает отлично. Теперь вот сложная часть. Чтобы продолжить процедуру входа в систему, мне нужно как-то вставить или ленить загрузить репозиторий, используя другой DbContext, с строкой соединения, которая создается из результата другой базы данных.

То, что я

2 БД Контексты генерируется из существующей БД, один статический и один динамический, если это возможно.

Затем занятия. Общие Repository классов/интерфейсы

public interface IRepository 
{ 
    void Submit(); 
} 

public interface IRepository<TEntity, TContext> : IRepository 
    where TEntity : class 
    where TContext : DbContext 
{ 
    //crud stuff 
} 
public abstract class GenericRepository<TEntity, TContext> : IRepository<TEntity, TContext> 
    where TEntity : class 
    where TContext : DbContext 
{ 
    private TContext _dataContext; 
    private IUnitOfWork _unitOfWork; 
    private readonly IDbSet<TEntity> dbset; 

    protected GenericRepository(IUnitOfWork unitOfWork) 
    { 
     _unitOfWork = unitOfWork; 
     _unitOfWork.Register(this); 
    } 
} 

единица работа класс/интерфейс

public interface IUnitOfWork 
{ 
    void Register(IRepository repository); 
    void Commit(); 
} 
public class UnitOfWork : IUnitOfWork 
{ 
    private readonly Dictionary<string, IRepository> _repositories; 
    private HttpContextBase _httpContext; 


    public UnitOfWork(HttpContextBase httpContext)   
    {    
     _httpContext = httpContext; 
    } 

    public void Register(IRepository repository) 
    { 
     _repositories.Add(repository.GetType().Name, repository); 
    }   

    public void Commit() 
    { 
     _repositories.ToList().ForEach(x => x.Value.Submit()); 
    } 
} 

Затем контекст/объект конкретного репозиторий

public class EmployeeRepository : GenericRepository<tbl_Medewerker, CustomerDbEntities>, IEmployeeRepository 
{ 
    public EmployeeRepository(IUnitOfWork unitOfWork) 
     : base(unitOfWork) 
    { 
    } 
} 

public interface IEmployeeRepository : IRepository<tbl_Medewerker, CustomerDbEntities> 
{ 

} 

Тогда сервис, который реализует хранилище

public interface IEmployeeLoginService 
{ 
    tbl_Medewerker GetEmployeeByLogin(string username, string password); 
    tbl_Medewerker GetEmployeeByID(Guid id); 
} 

public class EmployeeLoginService : IEmployeeLoginService 
{ 
    private readonly IEmployeeRepository _employeeRepository; 

    public EmployeeLoginService(IEmployeeRepository employeeRepository) 
    { 
     _employeeRepository = employeeRepository; 
    } 

    public tbl_Medewerker GetEmployeeByLogin(string username, string password) 
    { 
     return _employeeRepository.Get(e => e.MedewerkerNaam.ToLower() == username.ToLower() && e.Password == password); 
    } 

    public tbl_Medewerker GetEmployeeByID(Guid id) 
    { 
     return _employeeRepository.GetById(id); 
    } 
} 

, наконец, контроллер, который реализует эту услугу и использует его при входе в систему действия

public class AccountController : BaseController 
{ 
    IConnectionService _connectionService; 
    IEmployeeLoginService _employeeService; 

    public AccountController(IConnectionService connectionService, IEmployeeLoginService employeeService) 
    { 
     _connectionService = connectionService; 
     _employeeService = employeeService; 
    } 



    [AllowAnonymous, HttpPost] 
    public ActionResult Login(LoginModel login) 
    { 
     if ((Settings)Session["Settings"] == null) 
     { 
      Settings settings = new Settings(); 

      settings.company = _connectionService.GetCompanyName(login.CompanyName); 
      if (settings.company != null) 
      { 
       settings.licence = _connectionService.GetLicenceByCompanyID(settings.company.Company_id); 
       if (settings.licence != null) 
       { 
        settings.connectionStringOrName = string.Format(@"Data Source={0};Initial Catalog={1};User ID={2};Password={3};Application Name=EntityFrameworkMUE", settings.licence.WS_DatabaseServer, settings.licence.WS_DatabaseName, settings.licence.WS_DatabaseUID, settings.licence.WS_DatabasePWD);       
        Session["Settings"] = settings; 

        settings.user = _employeeService.GetEmployeeByLogin(login.UserName, login.Password); 
        if (settings.user != null) 
        { 
         FormsAuthentication.SetAuthCookie(string.Format("{0},{1}", settings.company.Company_id.ToString(), settings.user.Medewerker_ID.ToString()) , login.RememberMe); 
         return RedirectToAction("index", "home");        
        } 
       } 
      } 
     } 
     else 
     { 
      return RedirectToAction("index", "home"); 
     } 
     return View(); 
    } 


} 

И конечно же в autofac загрузчике

private static void SetAutoFacContainer() 
    { 
     var builder = new ContainerBuilder(); 
     builder.RegisterControllers(Assembly.GetExecutingAssembly()); 
     builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerHttpRequest();   
     builder.RegisterAssemblyTypes(typeof(UserRepository).Assembly) 
      .Where(t => t.Name.EndsWith("Repository")) 
      .AsImplementedInterfaces().InstancePerHttpRequest(); 
     builder.RegisterAssemblyTypes(typeof(ConnectionService).Assembly) 
      .Where(t => t.Name.EndsWith("Service")) 
      .AsImplementedInterfaces().InstancePerHttpRequest(); 

     builder.Register(c => new HttpContextWrapper(HttpContext.Current)).As<HttpContextBase>().InstancePerLifetimeScope(); 
     builder.RegisterModule(new AutofacWebTypesModule()); 

     builder.Register(att => new AuthorizeFilter(att.Resolve<IConnectionService>(), att.Resolve<IEmployeeLoginService>())).AsAuthorizationFilterFor<Controller>().InstancePerHttpRequest(); 
     builder.RegisterFilterProvider(); 

     IContainer container = builder.Build(); 
     DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 
    } 

Моя идея, как сделать это, устанавливает переменную сеанса со строкой подключения после восстановления данных из одного статического db, где информация хранится, и вводить сеанс в единицу работы и как-то использовать его там, но я наклоняю голову вокруг него.

вопрос (ы)

Am я движется в правильном направлении, пытаясь достичь этого, или даже возможно ли это? Если нет, то какие шаги вы предпримете для достижения этого.

Я знаю его долгое чтение. Надеюсь, вы, ребята, можете мне помочь, им совершенно не нужно использовать эти методы вместе. Спасибо заранее, я очень ценю это!

ответ

4

Ваш на правильном пути, я использовал

var mtc = new MultitenantContainer(container.Resolve<ITenantIdentificationStrategy>(), container); 
DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc)); 

Стратегия идентификации будет основываться на вошедшего пользователя. С настройками по умолчанию, когда они не вошли в систему.

public class CompanyNameIdentificationStrategy : ITenantIdentificationStrategy 
    { 

     public bool TryIdentifyTenant(out object tenantId) 
     { 
      var context = HttpContext.Current; 
      if(context != null) 
      { 
       var myUser = context.User as MyUserObject; 
       if(myUser != null) 
       { 
        tenantId = myUser.CompanyName; 
        return true; 
       } 
      } 
      return false; 
     } 
} 

Затем добавьте к вашей установке autofact:

var s = c.Resolve<ITenantIdentificationStrategy>(); 
        object id; 
        if (s.TryIdentifyTenant(out id) && id != null) 
        { 
         return id; 
        } 
        return "default"; 
       }).Keyed<string>("CompanyName"); 



builder.Register<Settings>(c => 
       { 
        var companyName = c.ResolveKeyed<string>("companyName"); 
        if (companyName == "default") 
        { 
         return new DefaultSettings(); 
        } 
        var settings = new Settings(); 
        return settings; 

       }).InstancePerLifetimeScope(); 

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

+0

Последние документы. [link] (http://autofac.readthedocs.org/ru/latest/advanced/multitenant.html?highlight=multitenantcontainer) – user3420988

+0

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