ASP.NET Core MVC创建控制器与依赖注入讲解

2022-04-17 02:39:28

默认的vice testService) { _testService = testService; } public string Index() { return "TestService.Name: " + _testService.Name; }}

还有一块代码在Startup文件中。在这里我将TestService注册在 DI 容器中作为范围内服务,并设置 MVC 中间件和服务:

public class Startup  {    public void ConfigureServices(IServiceCollection services)    {        services.AddMvc();        services.AddScoped<TestService>();        services.AddTransient(ctx =>            new HomeController(new TestService("Non-default value")));    }    public void Configure(IApplicationBuilder app)    {        app.UseMvcWithDefaultRoute();    }}

您会注意到,我定义了一个工厂方法用于创建HomeController的实例。将HomeController类型注册到 DI 容器中,并且在TestService实例中传递自定义Name属性。

如果您运行应用程序,您会看到什么结果?

ASP.NETCoreMVC创建控制器与依赖注入讲解

您可以看到,该TestService.Name属性使用的是默认值,表示TestService实例是直接从 DI 容器中获取的,直接忽略了创建HomeController的工厂方法。

这很容易理解,当您通过DefaultControllerActivator创建控制器时,它不会从DI容器中创建HomeController实例,只会解析构造函数的依赖项。

大多数情况下,使用DefaultControllerActivator是一个不错的选择,但有时您可能希望直接通过 DI 容器来创建控制器,比如您希望使用具有拦截器或装饰器等功能的第三方容器。

幸运的是,MVC 框架包含了一个这样的IControllerActivator实现,并提供了一种非常方便的扩展方法来启用它。

ServiceBasedControllerActivator

如您所见,DefaultControllerActivator使用TypeActivatorCache来创建控制器,MVC还包括另一个实现,称为 ServiceBasedControllerActivator,它是直接从 DI 容器中获取控制器。它的实现非常简单:

public class ServiceBasedControllerActivator : IControllerActivator  {    public object Create(ControllerContext actionContext)    {        var controllerType = actionContext.ActionDescriptor.ControllerTypeInfo.AsType();        return actionContext.HttpContext.RequestServices.GetRequiredService(controllerType);    }    public virtual void Release(ControllerContext context, object controller)    {    }}

当您将 MVC 服务添加到应用程序时,可以使用AddControllersAsServices()扩展方法配置基于 DI 的激活器:

public class Startup  {    public void ConfigureServices(IServiceCollection services)    {        services.AddMvc()                .AddControllersAsServices();        services.AddScoped<TestService>();        services.AddTransient(ctx =>            new HomeController(new TestService("Non-default value")));    }    public void Configure(IApplicationBuilder app)    {        app.UseMvcWithDefaultRoute();    }}

通过上面的代码,点击主页将通过 DI 容器来创建一个控制器。由于我们已经注册了一个创建HomeController的工厂方法,我们自定义TestService配置将被保留,使用替换后的Name属性:

ASP.NETCoreMVC创建控制器与依赖注入讲解

AddControllersAsServices方法实现了两件事情 - 它将您应用程序中的所有控制器注册到 DI 容器(如果尚未注册),并将IControllerActivator注册为ServiceBasedControllerActivator

public static IMvcBuilder AddControllersAsServices(this IMvcBuilder builder)  {    var feature = new ControllerFeature();    builder.PartManager.PopulateFeature(feature);    foreach (var controller in feature.Controllers.Select(c => c.AsType()))    {        builder.Services.TryAddTransient(controller, controller);    }    builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());    return builder;}

如果需要做一些更复杂的事情,您可以随时实现自己IControllerActivator;不过我找不到任何理由,这两点实现还不能满足您的需求!

总结

默认情况下,在ASP.NET Core MVC 中IControllerActivator配置为DefaultControllerActivatorDeUhjrHfHNjYfaultControllerActivator使用TypeActivatorCache来创建控制器。它从 DI 容器加载构造函数所需参数来创建控制器的实例。您也可以使用ServiceBasedControllerActivator作替代方法,它直接从 DI 容器加载控制器。您可以在Startup.ConfigureServices方法中使用MvcBuilderAddControllersAsServices()扩展方法来配置此激活方式。

 到此这篇关于ASP.NET Core MVC创建控制器与依赖注入的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。