日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core Controller与IOC的羁绊

發(fā)布時(shí)間:2023/12/4 asp.net 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core Controller与IOC的羁绊 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

????看到標(biāo)題可能大家會(huì)有所疑問(wèn)Controller和IOC能有啥羈絆,但是我還是拒絕當(dāng)一個(gè)標(biāo)題黨的。相信有很大一部分人已經(jīng)知道了這么一個(gè)結(jié)論,默認(rèn)情況下ASP.NET Core的Controller并不會(huì)托管到IOC容器中,注意關(guān)鍵字我說(shuō)的是"默認(rèn)",首先咱們不先說(shuō)為什么,如果還有不知道這個(gè)結(jié)論的同學(xué)們可以自己驗(yàn)證一下,驗(yàn)證方式也很簡(jiǎn)單,大概可以通過(guò)以下幾種方式。

驗(yàn)證Controller不在IOC中

首先,我們可以嘗試在ServiceProvider中獲取某個(gè)Controller實(shí)例,比如

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {var productController = app.ApplicationServices.GetService<ProductController>(); }

這是最直接的方式,可以在IOC容器中獲取注冊(cè)過(guò)的類(lèi)型實(shí)例,很顯然結(jié)果會(huì)為null。另一種方式,也是利用它的另一個(gè)特征,那就是通過(guò)構(gòu)造注入的方式,如下所示我們?cè)贠rderController中注入ProductController,顯然這種方式是不合理的,但是為了求證一個(gè)結(jié)果,我們這里僅做演示,強(qiáng)烈不建議實(shí)際開(kāi)發(fā)中這么寫(xiě),這是不規(guī)范也是不合理的寫(xiě)法

public class OrderController : Controller {private readonly ProductController _productController;public OrderController(ProductController productController){_productController = productController;}public IActionResult Index(){return View();} }

結(jié)果顯然是會(huì)報(bào)一個(gè)錯(cuò)InvalidOperationException: Unable to resolve service for type 'ProductController' while attempting to activate 'OrderController'。原因就是因?yàn)镻roductController并不在IOC容器中,所以通過(guò)注入的方式會(huì)報(bào)錯(cuò)。還有一種方式,可能不太常用,這個(gè)是利用注入的一個(gè)特征,可能有些同學(xué)已經(jīng)了解過(guò)了,那就是通過(guò)自帶的DI,即使一個(gè)類(lèi)中包含多個(gè)構(gòu)造函數(shù),它也會(huì)選擇最優(yōu)的一個(gè),也就是說(shuō)自帶的DI允許類(lèi)包含多個(gè)構(gòu)造函數(shù)。利用這個(gè)特征,我們可以在Controller中驗(yàn)證一下

public class OrderController : Controller {private readonly IOrderService _orderService;private readonly IPersonService _personService;public OrderController(IOrderService orderService){_orderService = orderService;}public OrderController(IOrderService orderService, IPersonService personService){_orderService = orderService;_personService = personService;}public IActionResult Index(){return View();} }

我們?cè)贑ontroller中編寫(xiě)了兩個(gè)構(gòu)造函數(shù),理論上來(lái)說(shuō)這是符合DI特征的,運(yùn)行起來(lái)測(cè)試一下,依然會(huì)報(bào)錯(cuò)InvalidOperationException: Multiple constructors accepting all given argument types have been found in type 'OrderController'. There should only be one applicable constructor。以上種種都是為了證實(shí)一個(gè)結(jié)論,默認(rèn)情況下Controller并不會(huì)托管到IOC當(dāng)中。

DefaultControllerFactory源碼探究

????上面雖然我們看到了一些現(xiàn)象,能說(shuō)明Controller默認(rèn)情況下并不在IOC中托管,但是還沒(méi)有足夠的說(shuō)服力,接下來(lái)我們就來(lái)查看源碼,這是最有說(shuō)服力的。我們找到Controller工廠注冊(cè)的地方,在MvcCoreServiceCollectionExtensions擴(kuò)展類(lèi)中[點(diǎn)擊查看源碼????]的AddMvcCoreServices方法里

//給IControllerFactory注冊(cè)默認(rèn)的Controller工廠類(lèi)DefaultControllerFactory //也是Controller創(chuàng)建的入口 services.TryAddSingleton<IControllerFactory, DefaultControllerFactory>(); //真正創(chuàng)建Controller的工作類(lèi)DefaultControllerActivator services.TryAddTransient<IControllerActivator, DefaultControllerActivator>();

由此我們可以得出,默認(rèn)的Controller創(chuàng)建工廠類(lèi)為DefaultControllerFactory,那么我們直接找到源碼位置[點(diǎn)擊查看源碼????],
為了方便閱讀,精簡(jiǎn)一下源碼如下所示

internal class DefaultControllerFactory : IControllerFactory {//真正創(chuàng)建Controller的工作者private readonly IControllerActivator _controllerActivator;private readonly IControllerPropertyActivator[] _propertyActivators;public DefaultControllerFactory(IControllerActivator controllerActivator,IEnumerable<IControllerPropertyActivator> propertyActivators){_controllerActivator = controllerActivator;_propertyActivators = propertyActivators.ToArray();}/// <summary>/// 創(chuàng)建Controller實(shí)例的方法/// </summary>public object CreateController(ControllerContext context){//創(chuàng)建Controller實(shí)例的具體方法(這是關(guān)鍵方法)var controller = _controllerActivator.Create(context);foreach (var propertyActivator in _propertyActivators){propertyActivator.Activate(context, controller);}return controller;}/// <summary>/// 釋放Controller實(shí)例的方法/// </summary>public void ReleaseController(ControllerContext context, object controller){_controllerActivator.Release(context, controller);} }

用過(guò)上面的源碼可知,真正創(chuàng)建Controller的地方在_controllerActivator.Create方法中,通過(guò)上面的源碼可知為IControllerActivator默認(rèn)注冊(cè)的是DefaultControllerActivator類(lèi),直接找到源碼位置[點(diǎn)擊查看源碼????],我們繼續(xù)簡(jiǎn)化一下源碼如下所示

internal class DefaultControllerActivator : IControllerActivator {private readonly ITypeActivatorCache _typeActivatorCache;public DefaultControllerActivator(ITypeActivatorCache typeActivatorCache){_typeActivatorCache = typeActivatorCache;}/// <summary>/// Controller實(shí)例的創(chuàng)建方法/// </summary>public object Create(ControllerContext controllerContext){//獲取Controller類(lèi)型信息var controllerTypeInfo = controllerContext.ActionDescriptor.ControllerTypeInfo;//獲取ServiceProvidervar serviceProvider = controllerContext.HttpContext.RequestServices;//創(chuàng)建controller實(shí)例return _typeActivatorCache.CreateInstance<object>(serviceProvider, controllerTypeInfo.AsType());}/// <summary>/// 釋放Controller實(shí)例/// </summary>public void Release(ControllerContext context, object controller){//如果controller實(shí)現(xiàn)了IDisposable接口,那么Release的時(shí)候會(huì)自動(dòng)調(diào)用Controller的Dispose方法//如果我們?cè)贑ontroller中存在需要釋放或者關(guān)閉的操作,可以再Controller的Dispose方法中統(tǒng)一釋放if (controller is IDisposable disposable){disposable.Dispose();}} }

通過(guò)上面的代碼我們依然要繼續(xù)深入到ITypeActivatorCache實(shí)現(xiàn)中去尋找答案,通過(guò)查看MvcCoreServiceCollectionExtensions類(lèi)的AddMvcCoreServices方法源碼我們可以找到如下信息

services.TryAddSingleton<ITypeActivatorCache, TypeActivatorCache>();

有了這個(gè)信息,我們可以直接找到TypeActivatorCache類(lèi)的源碼[點(diǎn)擊查看源碼????]代碼并不多,大致如下所示

internal class TypeActivatorCache : ITypeActivatorCache {//創(chuàng)建ObjectFactory的委托private readonly Func<Type, ObjectFactory> _createFactory =(type) => ActivatorUtilities.CreateFactory(type, Type.EmptyTypes);//Controller類(lèi)型和對(duì)應(yīng)創(chuàng)建Controller實(shí)例的ObjectFactory實(shí)例的緩存private readonly ConcurrentDictionary<Type, ObjectFactory> _typeActivatorCache =new ConcurrentDictionary<Type, ObjectFactory>();/// <summary>/// 真正創(chuàng)建實(shí)例的地方/// </summary>public TInstance CreateInstance<TInstance>(IServiceProvider serviceProvider,Type implementationType){//真正創(chuàng)建的操作是createFactory//通過(guò)Controller類(lèi)型在ConcurrentDictionary緩存中獲得ObjectFactory//而ObjectFactory實(shí)例由ActivatorUtilities.CreateFactory方法創(chuàng)建的var createFactory = _typeActivatorCache.GetOrAdd(implementationType, _createFactory);//返回創(chuàng)建實(shí)例return (TInstance)createFactory(serviceProvider, arguments: null);} }

通過(guò)上面類(lèi)的代碼我們可以清晰的得出一個(gè)結(jié)論,默認(rèn)情況下Controller實(shí)例是由ObjectFactory創(chuàng)建出來(lái)的,而ObjectFactory實(shí)例是由ActivatorUtilities的CreateFactory創(chuàng)建出來(lái),所以Controller實(shí)例每次都是由ObjectFactory創(chuàng)建而來(lái),并非注冊(cè)到IOC容器中。并且我們還可以得到一個(gè)結(jié)論ObjectFactory應(yīng)該是一個(gè)委托,我們找到ObjectFactory定義的地方[點(diǎn)擊查看源碼????]

delegate?object?ObjectFactory(IServiceProvider?serviceProvider,?object[]?arguments);

這個(gè)確實(shí)如我們猜想的那般,這個(gè)委托會(huì)通過(guò)IServiceProvider實(shí)例去構(gòu)建類(lèi)型的實(shí)例,通過(guò)上述源碼相關(guān)的描述我們會(huì)產(chǎn)生一個(gè)疑問(wèn),既然Controller實(shí)例并非由IOC容器托管,它由ObjectFactory創(chuàng)建而來(lái),但是ObjectFactory實(shí)例又是由ActivatorUtilities構(gòu)建的,那么生產(chǎn)對(duì)象的核心也就在ActivatorUtilities類(lèi)中,接下來(lái)我們就來(lái)探究一下ActivatorUtilities的神秘面紗。

ActivatorUtilities類(lèi)的探究

????書(shū)接上面,我們知道了ActivatorUtilities類(lèi)是創(chuàng)建Controller實(shí)例最底層的地方,那么ActivatorUtilities到底和容器是啥關(guān)系,因?yàn)槲覀兛吹搅薃ctivatorUtilities創(chuàng)建實(shí)例需要依賴(lài)ServiceProvider,一切都要從找到ActivatorUtilities類(lèi)的源碼開(kāi)始。我們最初接觸這個(gè)類(lèi)的地方在于它通過(guò)CreateFactory方法創(chuàng)建了ObjectFactory實(shí)例,那么我們就從這個(gè)地方開(kāi)始,找到源碼位置[點(diǎn)擊查看源碼????]實(shí)現(xiàn)如下

public static ObjectFactory CreateFactory(Type instanceType, Type[] argumentTypes) {//查找instanceType的構(gòu)造函數(shù)//找到構(gòu)造信息ConstructorInfo//得到給定類(lèi)型與查找類(lèi)型instanceType構(gòu)造函數(shù)的映射關(guān)系FindApplicableConstructor(instanceType, argumentTypes, out ConstructorInfo constructor, out int?[] parameterMap);//構(gòu)建IServiceProvider類(lèi)型參數(shù)var provider = Expression.Parameter(typeof(IServiceProvider), "provider");//構(gòu)建給定類(lèi)型參數(shù)數(shù)組參數(shù)var argumentArray = Expression.Parameter(typeof(object[]), "argumentArray");//通過(guò)構(gòu)造信息、構(gòu)造參數(shù)對(duì)應(yīng)關(guān)系、容器和給定類(lèi)型構(gòu)建表達(dá)式樹(shù)Bodyvar factoryExpressionBody = BuildFactoryExpression(constructor, parameterMap, provider, argumentArray);//構(gòu)建lambdavar factoryLamda = Expression.Lambda<Func<IServiceProvider, object[], object>>(factoryExpressionBody, provider, argumentArray);var result = factoryLamda.Compile();//返回執(zhí)行結(jié)果return result.Invoke; }

ActivatorUtilities類(lèi)的CreateFactory方法代碼雖然比較簡(jiǎn)單,但是它涉及到調(diào)用了其他方法,由于嵌套的比較深代碼比較多,而且不是本文講述的重點(diǎn),我們就不再這里細(xì)說(shuō)了,我們可以大概的描述一下它的工作流程。

  • 首先在給定的類(lèi)型里查找到合適的構(gòu)造函數(shù),這里我們可以理解為查找Controller的構(gòu)造函數(shù)。

  • 然后得到構(gòu)造信息,并得到構(gòu)造函數(shù)的參數(shù)與給定類(lèi)型參數(shù)的對(duì)應(yīng)關(guān)系

  • 通過(guò)構(gòu)造信息和構(gòu)造參數(shù)的對(duì)應(yīng)關(guān)系,在IServiceProvider得到對(duì)應(yīng)類(lèi)型的實(shí)例為構(gòu)造函數(shù)賦值

  • 最后經(jīng)過(guò)上面的操作通過(guò)初始化指定的構(gòu)造函數(shù)來(lái)創(chuàng)建給定Controller類(lèi)型的實(shí)例
    綜上述的相關(guān)步驟,我們可以得到一個(gè)結(jié)論,Controller實(shí)例的初始化是通過(guò)遍歷Controller類(lèi)型構(gòu)造函數(shù)里的參數(shù),然后根據(jù)構(gòu)造函數(shù)每個(gè)參數(shù)的類(lèi)型在IServiceProvider查找已經(jīng)注冊(cè)到容器中相關(guān)的類(lèi)型實(shí)例,最終初始化得到的Controller實(shí)例。這就是在IServiceProvider得到需要的依賴(lài)關(guān)系,然后創(chuàng)建自己的實(shí)例,它內(nèi)部是使用的表達(dá)式樹(shù)來(lái)完成的這一切,可以理解為更高效的反射方式。
    關(guān)于ActivatorUtilities類(lèi)還包含了其他比較實(shí)用的方法,比如CreateInstance方法

public static T CreateInstance<T>(IServiceProvider provider, params object[] parameters)

它可以通過(guò)構(gòu)造注入的方式創(chuàng)建指定類(lèi)型T的實(shí)例,其中構(gòu)造函數(shù)里具體的參數(shù)實(shí)例是通過(guò)在IServiceProvider實(shí)例里獲取到的,比如我們我們有這么一個(gè)類(lèi)

public class OrderController {private readonly IOrderService _orderService;private readonly IPersonService _personService;public OrderController(IOrderService orderService, IPersonService personService){_orderService = orderService;_personService = personService;} }

其中它所依賴(lài)的IOrderService和IPersonService實(shí)例是注冊(cè)到IOC容器中的

IServiceCollection services = new ServiceCollection().AddScoped<IPersonService, PersonService>().AddScoped<IOrderService, OrderService>();

然后你想獲取到OrderController的實(shí)例,但是它只包含一個(gè)有參構(gòu)造函數(shù),但是構(gòu)造函數(shù)的參數(shù)都以注冊(cè)到IOC容器中。當(dāng)存在這種場(chǎng)景你便可以通過(guò)以下方式得到你想要的類(lèi)型實(shí)例,如下所示

IServiceProvider serviceProvider = services.BuildServiceProvider(); OrderController?orderController?=?ActivatorUtilities.CreateInstance<OrderController>(serviceProvider);

即使你的類(lèi)型OrderController并沒(méi)有注冊(cè)到IOC容器中,但是它的依賴(lài)都在容器中,你也可以通過(guò)構(gòu)造注入的方式得到你想要的實(shí)例。總的來(lái)說(shuō)ActivatorUtilities里的方法還是比較實(shí)用的,有興趣的同學(xué)可以自行嘗試一下,也可以通過(guò)查看ActivatorUtilities源碼的方式了解它的工作原理。

AddControllersAsServices方法

????上面我們主要是講解了默認(rèn)情況下Controller并不是托管到IOC容器中的,它只是表現(xiàn)出來(lái)的讓你以為它是在IOC容器中,因?yàn)樗梢酝ㄟ^(guò)構(gòu)造函數(shù)注入相關(guān)實(shí)例,這主要是ActivatorUtilities類(lèi)的功勞。說(shuō)了這么多Controller實(shí)例到底可不可以注冊(cè)到IOC容器中,讓它成為真正受到IOC容器的托管者。要解決這個(gè),必須要滿足兩點(diǎn)條件

  • 首先,需要將Controller注冊(cè)到IOC容器中,但是僅僅這樣還不夠,因?yàn)镃ontroller是由ControllerFactory創(chuàng)建而來(lái)

  • 其次,我們要改造ControllerFactory類(lèi)中創(chuàng)建Controller實(shí)例的地方讓它從容器中獲取Controller實(shí)例,這樣就解決了所有的問(wèn)題
    如果我們自己去實(shí)現(xiàn)將Controller托管到IOC容器中,就需要滿足以上兩個(gè)操作一個(gè)是要將Controller放入容器,然后讓創(chuàng)建Controller的地方從IOC容器中直接獲取Controller實(shí)例。慶幸的是,微軟幫我們封裝了一個(gè)相關(guān)的方法,它可以幫我們解決將Controller托管到IOC容器的問(wèn)題,它的使用方法如下所示

services.AddMvc().AddControllersAsServices(); //或其他方式,這取決于你構(gòu)建的Web項(xiàng)目的用途可以是WebApi、Mvc、RazorPage等 //services.AddMvcCore().AddControllersAsServices();

相信大家都看到了,玄機(jī)就在AddControllersAsServices方法中,但是它存在于MvcCoreMvcBuilderExtensions類(lèi)和MvcCoreMvcCoreBuilderExtensions類(lèi)中,不過(guò)問(wèn)題不大,因?yàn)樗鼈兊拇a是完全一樣的。只是因?yàn)槟憧梢酝ㄟ^(guò)多種方式構(gòu)建Web項(xiàng)目比如AddMvc或者AddMvcCore,廢話不多說(shuō)直接上代碼[點(diǎn)擊查看源碼????]

public static IMvcBuilder AddControllersAsServices(this IMvcBuilder builder) {if (builder == null){throw new ArgumentNullException(nameof(builder));}var feature = new ControllerFeature();builder.PartManager.PopulateFeature(feature);//第一將Controller實(shí)例添加到IOC容器中foreach (var controller in feature.Controllers.Select(c => c.AsType())){//注冊(cè)的聲明周期是Transientbuilder.Services.TryAddTransient(controller, controller);}//第二替換掉原本DefaultControllerActivator的為ServiceBasedControllerActivatorbuilder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());return builder; }

第一點(diǎn)沒(méi)問(wèn)題那就是將Controller實(shí)例添加到IOC容器中,第二點(diǎn)它替換掉了DefaultControllerActivator為為ServiceBasedControllerActivator。通過(guò)上面我們講述的源碼了解到DefaultControllerActivator是默認(rèn)提供Controller實(shí)例的地方是獲取Controller實(shí)例的核心所在,那么我們看看ServiceBasedControllerActivator與DefaultControllerActivator到底有何不同,直接貼出代碼[點(diǎn)擊查看源碼????]

public class ServiceBasedControllerActivator : IControllerActivator {public object Create(ControllerContext actionContext){if (actionContext == null){throw new ArgumentNullException(nameof(actionContext));}//獲取Controller類(lèi)型var controllerType = actionContext.ActionDescriptor.ControllerTypeInfo.AsType();//通過(guò)Controller類(lèi)型在容器中獲取實(shí)例return actionContext.HttpContext.RequestServices.GetRequiredService(controllerType);}public virtual void Release(ControllerContext context, object controller){} }

相信大家對(duì)上面的代碼一目了然了,和我們上面描述的一樣,將創(chuàng)建Controller實(shí)例的地方改造了在容器中獲取的方式。不知道大家有沒(méi)有注意到ServiceBasedControllerActivator的Release的方法居然沒(méi)有實(shí)現(xiàn),這并不是我沒(méi)有粘貼出來(lái),確實(shí)是沒(méi)有代碼,之前我們看到的DefaultControllerActivator可是有調(diào)用Controller的Disposed的方法,這里卻啥也沒(méi)有。相信聰明的你已經(jīng)想到了,因?yàn)镃ontroller已經(jīng)托管到了IOC容器中,所以他的生命及其相關(guān)釋放都是由IOC容器完成的,所以這里不需要任何操作。
????我們上面還看到了注冊(cè)Controller實(shí)例的時(shí)候使用的是TryAddTransient方法,也就是說(shuō)每次都會(huì)創(chuàng)建Controller實(shí)例,至于為什么,我想大概是因?yàn)槊看握?qǐng)求都其實(shí)只會(huì)需要一個(gè)Controller實(shí)例,況且EFCore的注冊(cè)方式官方建議也是Scope的,而這里的Scope正是對(duì)應(yīng)的一次Controller請(qǐng)求。在加上自帶的IOC會(huì)提升依賴(lài)類(lèi)型的聲明周期,如果將Controller注冊(cè)為單例的話如果使用了EFCore那么它也會(huì)被提升為單例,這樣會(huì)存在很大的問(wèn)題。也許正是基于這個(gè)原因默認(rèn)才將Controller注冊(cè)為T(mén)ransient類(lèi)型的,當(dāng)然這并不代表只能注冊(cè)為T(mén)ransient類(lèi)型的,如果你不使用類(lèi)似EFCore這種需要作用域?yàn)镾cope的服務(wù)的時(shí)候,而且保證使用的主鍵都可以使用單例的話,完全可以將Controller注冊(cè)為別的生命周期,當(dāng)然這種方式個(gè)人不是很建議。

Controller結(jié)合Autofac

????有時(shí)候大家可能會(huì)結(jié)合Autofac一起使用,Autofac確實(shí)是一款非常優(yōu)秀的IOC框架,它它支持屬性和構(gòu)造兩種方式注入,關(guān)于Autofac托管自帶IOC的原理咱們?cè)谥暗奈恼聹\談.Net Core DependencyInjection源碼探究中曾詳細(xì)的講解過(guò),這里咱們就不過(guò)多的描述了,咱們今天要說(shuō)的是Autofac和Controller的結(jié)合。如果你想保持和原有的IOC一致的使用習(xí)慣,即只使用構(gòu)造注入的話,你只需要完成兩步即可

  • 首先將默認(rèn)的IOC容器替換為Autofac,具體操作也非常簡(jiǎn)單,如下所示

public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseStartup<Startup>();})//只需要在這里設(shè)置ServiceProviderFactory為AutofacServiceProviderFactory即可.UseServiceProviderFactory(new AutofacServiceProviderFactory());
  • 然后就是咱們之前說(shuō)的,要將Controller放入容器中,然后修改生產(chǎn)Controller實(shí)例的ControllerFactory的操作為在容器中獲取,當(dāng)然這一步微軟已經(jīng)為我們封裝了便捷的方法

services.AddMvc().AddControllersAsServices();

只需要通過(guò)上面簡(jiǎn)單得兩步,既可以將Controller托管到Autofac容器中。但是,我們說(shuō)過(guò)了Autofac還支持屬性注入,但是默認(rèn)的方式只支持構(gòu)造注入的方式,那么怎么讓Controller支持屬性注入呢?我們還得從最根本的出發(fā),那就是解決Controller實(shí)例存和取的問(wèn)題

  • 首先為了讓Controller托管到Autofac中并且支持屬性注入,那么就只能使用Autofac的方式去注冊(cè)Controller實(shí)例,具體操作是在Startup類(lèi)中添加ConfigureContainer方法,然后注冊(cè)Controller并聲明支持屬性注入

public void ConfigureContainer(ContainerBuilder builder) {var controllerBaseType = typeof(ControllerBase);//掃描Controller類(lèi)builder.RegisterAssemblyTypes(typeof(Program).Assembly).Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)//屬性注入.PropertiesAutowired(); }
  • 其次是解決取的問(wèn)題,這里我們就不需要AddControllersAsServices方法了,因?yàn)锳ddControllersAsServices解決了Controller實(shí)例在IOC中存和取的問(wèn)題,但是這里我們只需要解決Controller取得問(wèn)題說(shuō)只需要使用ServiceBasedControllerActivator即可,具體操作是

services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

僅需要在默認(rèn)的狀態(tài)下完成這兩步,既可以解決Controller托管到Autofac中并支持屬性注入的問(wèn)題,這也是最合理的方式。當(dāng)然如果你使用AddControllersAsServices可是可以實(shí)現(xiàn)相同的效果了,只不過(guò)是沒(méi)必要將容器重復(fù)的放入容器中了。

總結(jié)

????本文我們講述了關(guān)于ASP.NET Core Controller與IOC結(jié)合的問(wèn)題,我覺(jué)得這是有必要讓每個(gè)人都有所了解的知識(shí)點(diǎn),因?yàn)樵谌粘5腤eb開(kāi)發(fā)中Controller太常用了,知道這個(gè)問(wèn)題可能會(huì)讓大家在開(kāi)發(fā)中少走一點(diǎn)彎路,接下來(lái)我們來(lái)總結(jié)一下本文大致講解的內(nèi)容

  • 首先說(shuō)明了一個(gè)現(xiàn)象,那就是默認(rèn)情況下Controller并不在IOC容器中,我們也通過(guò)幾個(gè)示例驗(yàn)證了一下。

  • 其次講解了默認(rèn)情況下創(chuàng)造Controller實(shí)例真正的類(lèi)ActivatorUtilities,并大致講解了ActivatorUtilities的用途。

  • 然后我們找到了將Controller托管到IOC容器中的辦法AddControllersAsServices,并探究了它的源碼,了解了它的工作方式。

  • 最后我們又演示了如何使用最合理的方式將Controller結(jié)合Autofac一起使用,并且支持屬性注入。

本次講解到這里就差不多了,希望本來(lái)就知道的同學(xué)們能加深一點(diǎn)了解,不知道的同學(xué)能夠給你們提供一點(diǎn)幫助,能夠在日常開(kāi)發(fā)中少走一點(diǎn)彎路。新的一年開(kāi)始了,本篇文章是我2021年的第一篇文章,新的一年感謝大家的支持。

????歡迎掃碼關(guān)注我的公眾號(hào)????

總結(jié)

以上是生活随笔為你收集整理的ASP.NET Core Controller与IOC的羁绊的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。