Injecting/Managing 在运行时使用 Entity Framework、依赖注入、工作单元和存储库模式更改连接字符串
Injecting/Managing at runtime changing connectionstrings using Entity Framework, Dependency Injection, Unit of Work and Repository Patterns
情况
我正在使用标题中提到的技术构建 Web 应用程序。该应用程序类似于用于多个客户端的 CMS 系统。客户必须使用他的公司名称和登录凭据登录到该系统。
使用提供的公司名称,我连接到存储所有客户数据库信息的数据库(静态 DbContext
,每次都使用相同的连接字符串)并搜索该客户特定的数据库(每个客户都有自己的数据库)具有完全相同的设计)登录信息。一切正常。
现在是棘手的部分。要继续登录过程,我需要使用另一个 DbContext
以某种方式注入或延迟加载存储库,连接字符串是从另一个数据库的结果构建的。
我有什么
2 DbContext
从现有数据库生成,一个是静态的,一个是动态的。
然后是通用存储库 classes/interfaces:
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);
}
}
工作单元class/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());
}
}
然后是 context/entity 特定的存储库
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));
}
我的想法是,在从存储信息的一个静态数据库中检索数据后,使用连接字符串设置一个 session 变量,并在工作单元中注入 session并以某种方式在那里使用它,但我无法理解它。
问题:
我是否正朝着正确的方向努力实现这一目标,甚至可能吗?如果不是,你会采取什么步骤来实现这个
我知道这是一篇很长的文章,我希望你们能帮助我,我对一起使用这些技术还很陌生。提前致谢 - 非常感谢!
你说的对,我用过
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();
您可以解析这些代码块中的内容。我可能会设置一个键控默认设置,然后当用户登录时,设置将切换到他们的设置,应用程序的其余部分应该可以工作。
情况
我正在使用标题中提到的技术构建 Web 应用程序。该应用程序类似于用于多个客户端的 CMS 系统。客户必须使用他的公司名称和登录凭据登录到该系统。
使用提供的公司名称,我连接到存储所有客户数据库信息的数据库(静态 DbContext
,每次都使用相同的连接字符串)并搜索该客户特定的数据库(每个客户都有自己的数据库)具有完全相同的设计)登录信息。一切正常。
现在是棘手的部分。要继续登录过程,我需要使用另一个 DbContext
以某种方式注入或延迟加载存储库,连接字符串是从另一个数据库的结果构建的。
我有什么
2 DbContext
从现有数据库生成,一个是静态的,一个是动态的。
然后是通用存储库 classes/interfaces:
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);
}
}
工作单元class/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());
}
}
然后是 context/entity 特定的存储库
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));
}
我的想法是,在从存储信息的一个静态数据库中检索数据后,使用连接字符串设置一个 session 变量,并在工作单元中注入 session并以某种方式在那里使用它,但我无法理解它。
问题:
我是否正朝着正确的方向努力实现这一目标,甚至可能吗?如果不是,你会采取什么步骤来实现这个
我知道这是一篇很长的文章,我希望你们能帮助我,我对一起使用这些技术还很陌生。提前致谢 - 非常感谢!
你说的对,我用过
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();
您可以解析这些代码块中的内容。我可能会设置一个键控默认设置,然后当用户登录时,设置将切换到他们的设置,应用程序的其余部分应该可以工作。