entity-framework - 使用 Entity Framework 、依赖注入(inject)、工作单元和存储库模式在运行时注入(inject)/管理更改连接字符串

标签 entity-framework dependency-injection repository-pattern autofac unit-of-work

情况
我正在使用标题中提到的技术构建一个 Web 应用程序。此应用程序类似于用于多个客户端的 CMS 系统。客户必须使用他的公司名称和登录凭据登录到该系统。
使用提供的公司名称,我连接到存储所有客户数据库信息的数据库(静态 DbContext,每次相同的连接字符串)并搜索此客户特定数据库(每个客户都有自己的完全相同的设计)登录信息.这一切都很好。
现在这是棘手的部分。要继续登录过程,我需要使用另一个 DbContext 以某种方式注入(inject)或延迟加载存储库。使用从另一个数据库的结果构建的连接字符串。
我有什么
2 DbContext s 从现有数据库生成,一种是静态的,另一种是动态的。
然后是通用存储库类/接口(interface):

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);
    }
}
工作单元类/接口(interface)
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);
    }
}
最后是实现该服务并在登录操作中使用它的 Controller
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 Bootstrap :
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));
}
我的想法是如何做到这一点,是在从存储信息的一个静态数据库中检索数据后使用连接字符串设置 session 变量,并将 session 注入(inject)工作单元并以某种方式在那里使用它,但我无法包装我的绕过它。
问题:
我是否朝着正确的方向努力实现这一目标,甚至有可能吗?如果不是,您将采取哪些步骤来实现这一目标
我知道这是一本很长的书,希望你们能帮助我,我对一起使用这些技术很陌生。在此先感谢 - 我真的很感激!

最佳答案

你在正确的轨道上,我用过

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

然后你添加到你的自动事实设置:
 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();

您可以解决这些代码块中的内容。我可能会设置一个键控默认设置,然后当用户登录时,设置将切换到他们的设置,应用程序的其余部分应该可以工作。

关于entity-framework - 使用 Entity Framework 、依赖注入(inject)、工作单元和存储库模式在运行时注入(inject)/管理更改连接字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28090460/

相关文章:

c# - 尝试播种数据库时出现 EF 异常

php - Laravel 5 目标不可实例化

entity-framework - Entity Framework 5 工作单元模式——我应该在哪里调用 SaveChanges?

asp.net - 使用 Asp.Net MVC 和 Web Api 配置 Ninject

c# - scafford 自动生成 crud 仓库 asp.net5

c# - 在运行时验证 EF 数据模型(列出 EDMX 和 SQL 数据库架构之间的差异)

c# - 序列化“System.Data.Entity.DynamicProxies”类型的对象时检测到循环引用

c# - 需要 self 跟踪实体和 POCO 解释

java - 如何仅使用 Core Java 将键值对映射注入(inject)到对象中?

c# - Unity 3,RegisterTypes方法在哪里?