ASP.NET Core MVC如何创建控制器与依赖注入
这篇文章主要介绍“ASP.NETCoreMVC如何创建控制器与依赖注入”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“ASP.NETCoreMVC如何创建控制器与依赖注入”文章能帮助大家解决问题。
默认的IControllerActivator在 ASP.NET Core 中,当 MVC 中间件接收到请求时,通过路由选择要执行的控制器和操作方法。为了实际的执行操作, MVC 中间件必须创建所选控制器的实例。
创建控制器的过程依赖众多不同的提供者和工厂类,但最终是由实现IControllerActivator
接口的实例来决定的。实现类只需要实现两个方法:
publicinterfaceIControllerActivator{objectCreate(ControllerContextcontext);voidRelease(ControllerContextcontext,objectcontroller);}
如您所见,该IControllerActivator.Create
方法传递了用于创建控制器的ControllerContext
实例。控制器的创建方式取决于具体的实现。
众所周知,ASP.NET Core 使用的是DefaultControllerActivator
,它通过TypeActivatorCache来创建控制器。TypeActivatorCache
通过调用类的构造函数,并试图从 DI 容器中解析构造函数所需参数的实例。
有一点很重要,DefaultControllerActivator
不会试图从 DI 容器中解析控制器的实例,只会解析控制器的依赖项。
为了演示这个行为,我创建了一个简单的 MVC 应用程序,包括一个单一的服务和一个控制器。服务实例有一个name属性,它通过构造函数来设置。默认情况下,它使用"default"
作为默认值。
publicclassTestService{publicTestService(stringname="default"){Name=name;}publicstringName{get;}}
在应用程序中HomeController
依赖于TestService
,并返回Name
属性的值:
publicclassHomeController:Controller{privatereadonlyTestService_testService;publicHomeController(TestServicetestService){_testService=testService;}publicstringIndex(){return"TestService.Name:"+_testService.Name;}}
还有一块代码在Startup
文件中。在这里我将TestService
注册在 DI 容器中作为范围内服务,并设置 MVC 中间件和服务:
publicclassStartup{publicvoidConfigureServices(IServiceCollectionservices){services.AddMvc();services.AddScoped<TestService>();services.AddTransient(ctx=>newHomeController(newTestService("Non-defaultvalue")));}publicvoidConfigure(IApplicationBuilderapp){app.UseMvcWithDefaultRoute();}}
您会注意到,我定义了一个工厂方法用于创建HomeController
的实例。将HomeController
类型注册到 DI 容器中,并且在TestService
实例中传递自定义Name
属性。
如果您运行应用程序,您会看到什么结果?
您可以看到,该TestService.Name
属性使用的是默认值,表示TestService
实例是直接从 DI 容器中获取的,直接忽略了创建HomeController
的工厂方法。
这很容易理解,当您通过DefaultControllerActivator
创建控制器时,它不会从DI容器中创建HomeController
实例,只会解析构造函数的依赖项。
大多数情况下,使用DefaultControllerActivator
是一个不错的选择,但有时您可能希望直接通过 DI 容器来创建控制器,比如您希望使用具有拦截器或装饰器等功能的第三方容器。
幸运的是,MVC 框架包含了一个这样的IControllerActivator
实现,并提供了一种非常方便的扩展方法来启用它。
如您所见,DefaultControllerActivator
使用TypeActivatorCache
来创建控制器,MVC还包括另一个实现,称为ServiceBasedControllerActivator
,它是直接从 DI 容器中获取控制器。它的实现非常简单:
publicclassServiceBasedControllerActivator:IControllerActivator{publicobjectCreate(ControllerContextactionContext){varcontrollerType=actionContext.ActionDescriptor.ControllerTypeInfo.AsType();returnactionContext.HttpContext.RequestServices.GetRequiredService(controllerType);}publicvirtualvoidRelease(ControllerContextcontext,objectcontroller){}}
当您将 MVC 服务添加到应用程序时,可以使用AddControllersAsServices()
扩展方法配置基于 DI 的激活器:
publicclassStartup{publicvoidConfigureServices(IServiceCollectionservices){services.AddMvc().AddControllersAsServices();services.AddScoped<TestService>();services.AddTransient(ctx=>newHomeController(newTestService("Non-defaultvalue")));}publicvoidConfigure(IApplicationBuilderapp){app.UseMvcWithDefaultRoute();}}
通过上面的代码,点击主页将通过 DI 容器来创建一个控制器。由于我们已经注册了一个创建HomeController
的工厂方法,我们自定义TestService
配置将被保留,使用替换后的Name
属性:
AddControllersAsServices
方法实现了两件事情 - 它将您应用程序中的所有控制器注册到 DI 容器(如果尚未注册),并将IControllerActivator
注册为ServiceBasedControllerActivator
:
publicstaticIMvcBuilderAddControllersAsServices(thisIMvcBuilderbuilder){varfeature=newControllerFeature();builder.PartManager.PopulateFeature(feature);foreach(varcontrollerinfeature.Controllers.Select(c=>c.AsType())){builder.Services.TryAddTransient(controller,controller);}builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator,ServiceBasedControllerActivator>());returnbuilder;}
如果需要做一些更复杂的事情,您可以随时实现自己IControllerActivator
;不过我找不到任何理由,这两点实现还不能满足您的需求!
关于“ASP.NETCoreMVC如何创建控制器与依赖注入”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。