最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ASP.NET Core Controller與IOC結(jié)合問(wèn)題整理

 更新時(shí)間:2021年01月04日 10:08:06   作者:yi念之間  
在本篇文章里小編給大家整理了一篇關(guān)于ASP.NET Core Controller與IOC結(jié)合問(wèn)題整理內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。

前言

看到標(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)容

  1. 首先說(shuō)明了一個(gè)現(xiàn)象,那就是默認(rèn)情況下Controller并不在IOC容器中,我們也通過(guò)幾個(gè)示例驗(yàn)證了一下。
  2. 其次講解了默認(rèn)情況下創(chuàng)造Controller實(shí)例真正的類(lèi)ActivatorUtilities,并大致講解了ActivatorUtilities的用途。
  3. 然后我們找到了將Controller托管到IOC容器中的辦法AddControllersAsServices,并探究了它的源碼,了解了它的工作方式。
  4. 最后我們又演示了如何使用最合理的方式將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)文章

最新評(píng)論

祥云县| 浑源县| 九龙坡区| 宜昌市| 清河县| 陇西县| 肇庆市| 赤城县| 灵台县| 商城县| 望谟县| 浙江省| 渭南市| 高密市| 合水县| 军事| 黄山市| 梁河县| 南涧| 离岛区| 永靖县| 泾源县| 青河县| 山阳县| 合水县| 盐边县| 师宗县| 施甸县| 嘉祥县| 高安市| 彭泽县| 荥阳市| 平阳县| 教育| 合江县| 龙海市| 阳曲县| 高要市| 葵青区| 苏尼特右旗| 吴桥县|