在核心MVC ASP.NET 所有实现Controller
的类将自动解析并添加到MVC管道中。这些控制器也可以使用services.AddMvc().AddControllersAsServices();
注入到 DI 容器中
还有一个控制器,它也实现了特定的接口,我也可以将其添加到 DI 容器中:services.AddSingleton<IMyInterface, MyImpl>();
public class MyImpl : Controller, IMyInterface { }
但是,如果此控制器也实现了Controller
它已在 AddControllersAsServices()
中添加,因此再次将其添加到 DI 容器会导致此类有两个实例。
这种设计的原因是,我将有多个IMyInterface
实现,稍后需要决定使用哪一个,但每个实现也需要是一个控制器才能提供某些 API 端点(每个控制器将提供不同的端点,因此不会有冲突(。
如何确保只实例化我的类的一个实例,然后如何获取IMyInterface
的所有实现?
尽管 Im 关心控制器类在每个请求上都会实例化,所以即使您指定了这样的东西(Ninject 样式(:
services.Bind<IMyInterface, MyController>().To<MyController>().InSingletonScope();
这将是非常糟糕的。我的意思是,控制器是有状态的,你只是把所有东西混合起来,打破它的内部上下文。你可以做的是通过控制器进行装饰,而不是自己管理它的生存期:
public class MyImpl : IMyInterface
{
}
public class MyController : Controller
{
private readonly IMyInterface _inner; //delegate implementation to this one.
public MyController(IMyInterface inner)
{
_inner = inner;
}
}
和注射:
services.Bind<IMyInterface>().To<MyImpl>().InSingletonScope();//this is your logic.
sercices.Bind<MyController>().ToSomethingWhatever();//this line is managed by ASP .NET, mentioned this only to show the idea
您可能需要从控制器类中删除 MyImpl 继承。此外,您还需要将MyImpl视为服务而不是控制器。
另一种选择是,这可以通过Autofac或Ninject或Castle Windsor等IoC容器来实现。与Autofac一起使用时,它将如下所示
- 使用 NuGet 包添加 Autofac、Autofac ASP.Net MVC4 集成
- 打开 GLobal.asax.cs
-
在 Application_Start(( 中进行以下更改。3一.注释掉下面的代码作为
//WebApiConfig.Register(GlobalConfiguration.Configuration(;
3b. 创建一个新方法 RegisterAutofac((,将其作为 Application_Start(( 中的第一个方法调用3c.下面是 RegisterAutofac(( 方法的示例实现
private void RegisterAutofac()
{
var builder = new Autofac.ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterSource(new ViewRegistrationSource());
// The object to be injected in constructor etc.
builder.RegisterType<MyImpl>().As<IMyInterface>().SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}