使用 Ninject,您如何根据绑定指定不同的生命周期?
With Ninject, how do you specify different lifetimes depending on the binding?
在我们的 MVC 应用程序中,我们主要使用 Ninject 将依赖项注入控制器。因此,我们的默认生命周期范围是 InRequestScope()。我们现在添加了一个 IHttpModule,它使用公共依赖项作为控制器(即 UserService)。问题是 HttpModules 可以由 ASP.NET 和 IIS 合并并在多个请求中重复使用。由于注入的依赖项设置为 InRequestScope,因此后续请求在 HttpModule 内部引用注入的依赖项时,通常会得到 ObjectDisposedException。如何在注入控制器时为 UserService 指定 InRequestScope() ,在注入 HttpModule 时如何指定 InScope() 。
这是我们注册的简化版本:
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start(){
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop(){
bootstrapper.ShutDown();
}
private static IKernel CreateKernel(){
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<IHttpModule>().To<CustomModule>(); // needs a UserService
kernel.Bind<IUserService>().To<UserService>().InRequestScope(); // injected into controllers and the CustomModule
DependencyResolver.SetResolver(new Services.NinjectDependencyResolver(kernel));
return kernel;
}
}
查看 .When()
绑定语法。您可以使用它来指定特定情况下服务的特定范围。这是一个例子:
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
var scope1 = new object();
var scope2 = new object();
kernel.Bind<IWidget>().To<WidgetA>().InScope(c => scope1);
kernel.Bind<IWidget>().To<WidgetA>().WhenInjectedInto<WidgetController>().InScope(c => scope2);
var service = kernel.Get<GeneralWidgetService>();
service.Print();
service = kernel.Get<GeneralWidgetService>();
service.Print();
var controller = kernel.Get<WidgetController>();
controller.Print();
controller = kernel.Get<WidgetController>();
controller.Print();
// when scope2 changes, WidgetController gets a new widget, while WidgetService continues getting the existing widget
scope2 = new object();
service = kernel.Get<GeneralWidgetService>();
service.Print();
controller = kernel.Get<WidgetController>();
controller.Print();
}
}
public class WidgetController
{
private readonly IWidget _widget;
public WidgetController(IWidget widget)
{
_widget = widget;
}
public void Print()
{
Console.WriteLine("WidgetController ID: " + _widget.ID);
}
}
public class GeneralWidgetService
{
private readonly IWidget _widget;
public GeneralWidgetService(IWidget widget)
{
_widget = widget;
}
public void Print()
{
Console.WriteLine("GeneralWidgetService ID: " + _widget.ID);
}
}
public interface IWidget
{
string ID { get; }
string Name { get; }
}
public class WidgetA : IWidget
{
private readonly string _id = Guid.NewGuid().ToString();
public string ID { get { return _id; } }
public string Name { get { return "AAAAAAAAAAAAAAAAA"; } }
}
输出:
GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
WidgetController ID: 2c2bf05f-d251-41be-b9e0-224f02839ead
WidgetController ID: 2c2bf05f-d251-41be-b9e0-224f02839ead
GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
WidgetController ID: 519a2930-5b71-4cbb-b84e-a1d712ec5398
在我们的 MVC 应用程序中,我们主要使用 Ninject 将依赖项注入控制器。因此,我们的默认生命周期范围是 InRequestScope()。我们现在添加了一个 IHttpModule,它使用公共依赖项作为控制器(即 UserService)。问题是 HttpModules 可以由 ASP.NET 和 IIS 合并并在多个请求中重复使用。由于注入的依赖项设置为 InRequestScope,因此后续请求在 HttpModule 内部引用注入的依赖项时,通常会得到 ObjectDisposedException。如何在注入控制器时为 UserService 指定 InRequestScope() ,在注入 HttpModule 时如何指定 InScope() 。
这是我们注册的简化版本:
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start(){
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop(){
bootstrapper.ShutDown();
}
private static IKernel CreateKernel(){
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<IHttpModule>().To<CustomModule>(); // needs a UserService
kernel.Bind<IUserService>().To<UserService>().InRequestScope(); // injected into controllers and the CustomModule
DependencyResolver.SetResolver(new Services.NinjectDependencyResolver(kernel));
return kernel;
}
}
查看 .When()
绑定语法。您可以使用它来指定特定情况下服务的特定范围。这是一个例子:
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
var scope1 = new object();
var scope2 = new object();
kernel.Bind<IWidget>().To<WidgetA>().InScope(c => scope1);
kernel.Bind<IWidget>().To<WidgetA>().WhenInjectedInto<WidgetController>().InScope(c => scope2);
var service = kernel.Get<GeneralWidgetService>();
service.Print();
service = kernel.Get<GeneralWidgetService>();
service.Print();
var controller = kernel.Get<WidgetController>();
controller.Print();
controller = kernel.Get<WidgetController>();
controller.Print();
// when scope2 changes, WidgetController gets a new widget, while WidgetService continues getting the existing widget
scope2 = new object();
service = kernel.Get<GeneralWidgetService>();
service.Print();
controller = kernel.Get<WidgetController>();
controller.Print();
}
}
public class WidgetController
{
private readonly IWidget _widget;
public WidgetController(IWidget widget)
{
_widget = widget;
}
public void Print()
{
Console.WriteLine("WidgetController ID: " + _widget.ID);
}
}
public class GeneralWidgetService
{
private readonly IWidget _widget;
public GeneralWidgetService(IWidget widget)
{
_widget = widget;
}
public void Print()
{
Console.WriteLine("GeneralWidgetService ID: " + _widget.ID);
}
}
public interface IWidget
{
string ID { get; }
string Name { get; }
}
public class WidgetA : IWidget
{
private readonly string _id = Guid.NewGuid().ToString();
public string ID { get { return _id; } }
public string Name { get { return "AAAAAAAAAAAAAAAAA"; } }
}
输出:
GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
WidgetController ID: 2c2bf05f-d251-41be-b9e0-224f02839ead
WidgetController ID: 2c2bf05f-d251-41be-b9e0-224f02839ead
GeneralWidgetService ID: 09f61af7-c70d-45fe-834a-6cc94e1e3c40
WidgetController ID: 519a2930-5b71-4cbb-b84e-a1d712ec5398