将 DbContext 切换为使用每个用户会话的 Ninject 依赖注入
Switching a DbContext to using Ninject Dependency injection per user session
我有一个应用程序用于 2 个不同的站点。每个站点都有自己的数据库。
有 2 个 DbContext,每个站点 1 个。当用户打开我的应用程序时,会出现一个启动页面,他们可以在其中选择自己的站点。选择站点后,内核将重新绑定以使用所选站点的 DbContext。
private void RebindDbContext(string site)
{
switch (site)
{
case "Site1":
_kernel.Rebind<DbContext>().To<DbContext1>().InRequestScope();
break;
case "Site2":
_kernel.Rebind<DbContext>().To<DbContext2>().InRequestScope();
break;
}
}
现在是 Bob & Mary 的解释:
这在 Bob 选择站点 1 时工作正常。但是当 Mary 选择站点 2 时。Bob 的 dbContext 重新绑定到站点 2。我想要的是 Bob 和 Mary 能够同时使用该应用程序而不影响彼此。
我尝试过使用 TransientScope、ThreadScope 和 InRequest Scope,但其中 none 有效。
应用程序正在 运行 IIS 服务器上
感谢您的帮助
绑定旨在为每个应用程序完成一次,不依赖于状态。在这种情况下,您有几个选择:
1) A Ninject.Activation.IProvider
public class DbContextProvider : Ninject.Activation.IProvider
{
public Type Type
{
get { return typeof(DbContext); }
}
public object Create(IContext context)
{
var siteProvider = context.Kernel.Get<ISiteProvider>(); // use a provider to find which site is being used
switch (siteProvider.Current)
{
case "Site1":
return new DbContext1(); // or use a factory to create
case "Site2":
return new DbContext2();
}
}
}
然后:
Bind<DbContext>().ToProvider<DbContextProvider>().InRequestScope();
2) 条件绑定
When()
修饰符有一堆针对不同状态的重载,或者如果你经常使用一种类型,你可以创建一个扩展方法。
Bind<DbContext>().To<DbContext1>()
.When(request => request.ParentContext.Kernel.Get<ISiteProvider>().Current == "Site1")
.InRequestScope();
Bind<DbContext>().To<DbContext2>()
.When(request => request.ParentContext.Kernel.Get<ISiteProvider>().Current == "Site2")
.InRequestScope();
如果您只有几个条件可以应用此绑定,那么这是一个不错的选择。如果您的逻辑比这更复杂,请去找提供商。另请注意,条件绑定会导致性能下降。
3)一个ToMethod()
绑定
对于最简单的绑定逻辑,您可以在每次解析绑定时使用 Ninject 运行 一些代码:
Bind<DbContext>().ToMethod(context =>
context.Kernel.Get<ISiteProvider>().GetSite());
基本上,您选择哪个 select 取决于在决定激活哪个实例时涉及多少逻辑。在每个实例中,您都可以 new()
启动一个实例,或者您可以访问可以在其中解析实例的 IKernel:
context.Kernel.Get<DbContext2>();
这里有一些激活过程的官方文档:
https://github.com/ninject/Ninject/wiki/Providers%2C-Factory-Methods-and-the-Activation-Context
我有一个应用程序用于 2 个不同的站点。每个站点都有自己的数据库。
有 2 个 DbContext,每个站点 1 个。当用户打开我的应用程序时,会出现一个启动页面,他们可以在其中选择自己的站点。选择站点后,内核将重新绑定以使用所选站点的 DbContext。
private void RebindDbContext(string site)
{
switch (site)
{
case "Site1":
_kernel.Rebind<DbContext>().To<DbContext1>().InRequestScope();
break;
case "Site2":
_kernel.Rebind<DbContext>().To<DbContext2>().InRequestScope();
break;
}
}
现在是 Bob & Mary 的解释: 这在 Bob 选择站点 1 时工作正常。但是当 Mary 选择站点 2 时。Bob 的 dbContext 重新绑定到站点 2。我想要的是 Bob 和 Mary 能够同时使用该应用程序而不影响彼此。
我尝试过使用 TransientScope、ThreadScope 和 InRequest Scope,但其中 none 有效。
应用程序正在 运行 IIS 服务器上
感谢您的帮助
绑定旨在为每个应用程序完成一次,不依赖于状态。在这种情况下,您有几个选择:
1) A Ninject.Activation.IProvider
public class DbContextProvider : Ninject.Activation.IProvider
{
public Type Type
{
get { return typeof(DbContext); }
}
public object Create(IContext context)
{
var siteProvider = context.Kernel.Get<ISiteProvider>(); // use a provider to find which site is being used
switch (siteProvider.Current)
{
case "Site1":
return new DbContext1(); // or use a factory to create
case "Site2":
return new DbContext2();
}
}
}
然后:
Bind<DbContext>().ToProvider<DbContextProvider>().InRequestScope();
2) 条件绑定
When()
修饰符有一堆针对不同状态的重载,或者如果你经常使用一种类型,你可以创建一个扩展方法。
Bind<DbContext>().To<DbContext1>()
.When(request => request.ParentContext.Kernel.Get<ISiteProvider>().Current == "Site1")
.InRequestScope();
Bind<DbContext>().To<DbContext2>()
.When(request => request.ParentContext.Kernel.Get<ISiteProvider>().Current == "Site2")
.InRequestScope();
如果您只有几个条件可以应用此绑定,那么这是一个不错的选择。如果您的逻辑比这更复杂,请去找提供商。另请注意,条件绑定会导致性能下降。
3)一个ToMethod()
绑定
对于最简单的绑定逻辑,您可以在每次解析绑定时使用 Ninject 运行 一些代码:
Bind<DbContext>().ToMethod(context =>
context.Kernel.Get<ISiteProvider>().GetSite());
基本上,您选择哪个 select 取决于在决定激活哪个实例时涉及多少逻辑。在每个实例中,您都可以 new()
启动一个实例,或者您可以访问可以在其中解析实例的 IKernel:
context.Kernel.Get<DbContext2>();
这里有一些激活过程的官方文档:
https://github.com/ninject/Ninject/wiki/Providers%2C-Factory-Methods-and-the-Activation-Context