注入实现接口的控制器



在核心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一起使用时,它将如下所示

  1. 使用 NuGet 包添加 Autofac、Autofac ASP.Net MVC4 集成
  2. 打开 GLobal.asax.cs
  3. 在 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));
}

最新更新