ASP.NET Core Controller與IOC結(jié)合問(wèn)題整理
前言
看到標(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工廠(chǎng)注冊(cè)的地方,在MvcCoreServiceCollectionExtensions擴(kuò)展類(lèi)中[點(diǎn)擊查看源碼]的AddMvcCoreServices方法里
//給IControllerFactory注冊(cè)默認(rèn)的Controller工廠(chǎng)類(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)建工廠(chǎ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;
//獲取ServiceProvider
var 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ù)Body
var factoryExpressionBody = BuildFactoryExpression(constructor, parameterMap, provider, argumentArray);
//構(gòu)建lambda
var 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è),必須要滿(mǎn)足兩點(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容器中,就需要滿(mǎn)足以上兩個(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,廢話(huà)不多說(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è)的聲明周期是Transient
builder.Services.TryAddTransient(controller, controller);
}
//第二替換掉原本DefaultControllerActivator的為ServiceBasedControllerActivator
builder.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è)為單例的話(huà)如果使用了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í)候,而且保證使用的主鍵都可以使用單例的話(huà),完全可以將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)造注入的話(huà),你只需要完成兩步即可
首先將默認(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一起使用,并且支持屬性注入。
到此這篇關(guān)于ASP.NET Core Controller與IOC結(jié)合問(wèn)題整理的文章就介紹到這了,更多相關(guān)ASP.NET Core Controller與IOC結(jié)合問(wèn)題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
asp.net core多文件分塊同時(shí)上傳組件使用詳解
這篇文章主要為大家介紹了一個(gè)可多個(gè)文件同時(shí)上傳、斷點(diǎn)續(xù)傳,并實(shí)時(shí)反饋上傳進(jìn)度的 Asp.Net core 組件,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
WPF實(shí)現(xiàn)進(jìn)度條實(shí)時(shí)更新效果
這篇文章主要為大家詳細(xì)介紹了WPF實(shí)現(xiàn)進(jìn)度條實(shí)時(shí)更新效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
詳解ASP.NET MVC 解析模板生成靜態(tài)頁(yè)(RazorEngine)
我們?cè)诤芏囗?xiàng)目開(kāi)發(fā)中會(huì)常常用到頁(yè)面靜態(tài)化,本篇文章主要介紹了詳解ASP.NET MVC 解析模板生成靜態(tài)頁(yè)(RazorEngine) ,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03
C#實(shí)現(xiàn)HTTP協(xié)議迷你服務(wù)器(兩種方法)
用C#語(yǔ)言實(shí)現(xiàn)HTTP協(xié)議的服務(wù)器類(lèi)本文將以?xún)煞N稍微有差別的方式用C#語(yǔ)言實(shí)現(xiàn);要完成高性能的Web服務(wù)功能,通常都是需要寫(xiě)入到服務(wù),如IIS,Apache Tomcat感興趣的朋友可以了解下,或許對(duì)你學(xué)習(xí)c#有所幫助2013-02-02
ASP.NET 固定標(biāo)題列與欄位的具體實(shí)現(xiàn)
客戶(hù)提這個(gè)要求很久了,最近才時(shí)間弄,但是看到百度中要沒(méi)有很多詳細(xì)的代碼。廢話(huà)不多說(shuō)直接貼代碼。2013-06-06
ASP.NET MVC 5之郵件服務(wù)器與客戶(hù)端
這篇文章主要介紹了ASP.NET MVC5郵件服務(wù)器與客戶(hù)端,需要的朋友可以參考下2015-09-09
asp.net運(yùn)算符之邏輯運(yùn)算符以及其他運(yùn)算符介紹與實(shí)例
在.net中運(yùn)算符分類(lèi)很多種類(lèi)型,包括有我們常用的boolean型運(yùn)算符,通用的運(yùn)行符有 ==、!=、<、>、<=、>=、binary +、binary -、^、&、|、~、++、-- 和 sizeof()2013-08-08
淺談ASP.NET Core中間件實(shí)現(xiàn)分布式 Session
這篇文章主要介紹了淺談ASP.NET Core中間件實(shí)現(xiàn)分布式 Session,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11

