1. 程式人生 > >ASP.NET Core Controller與IOC的羈絆

ASP.NET Core Controller與IOC的羈絆

#### 前言     看到標題可能大家會有所疑問Controller和IOC能有啥羈絆,但是我還是拒絕當一個標題黨的。相信有很大一部分人已經知道了這麼一個結論,預設情況下ASP.NET Core的Controller並不會託管到IOC容器中,注意關鍵字我說的是"預設",首先咱們不先說為什麼,如果還有不知道這個結論的同學們可以自己驗證一下,驗證方式也很簡單,大概可以通過以下幾種方式。 #### 驗證Controller不在IOC中 首先,我們可以嘗試在ServiceProvider中獲取某個Controller例項,比如 ```cs public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { var productController = app.ApplicationServices.GetService(); } ``` 這是最直接的方式,可以在IOC容器中獲取註冊過的型別例項,很顯然結果會為null。另一種方式,也是利用它的另一個特徵,那就是通過構造注入的方式,如下所示我們在OrderController中注入ProductController,顯然這種方式是不合理的,但是為了求證一個結果,我們這裡僅做演示,強烈不建議實際開發中這麼寫,這是不規範也是不合理的寫法 ```cs public class OrderController : Controller { private readonly ProductController _productController; public OrderController(ProductController productController) { _productController = productController; } public IActionResult Index() { return View(); } } ``` 結果顯然是會報一個錯InvalidOperationException: Unable to resolve service for type 'ProductController' while attempting to activate 'OrderController'。原因就是因為ProductController並不在IOC容器中,所以通過注入的方式會報錯。還有一種方式,可能不太常用,這個是利用注入的一個特徵,可能有些同學已經瞭解過了,那就是通過自帶的DI,即使一個類中包含多個建構函式,它也會選擇最優的一個,也就是說自帶的DI允許類包含多個建構函式。利用這個特徵,我們可以在Controller中驗證一下 ```cs 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(); } } ``` 我們在Controller中編寫了兩個建構函式,理論上來說這是符合DI特徵的,執行起來測試一下,依然會報錯InvalidOperationException: Multiple constructors accepting all given argument types have been found in type 'OrderController'. There should only be one applicable constructor。以上種種都是為了證實一個結論,預設情況下Controller並不會託管到IOC當中。 #### DefaultControllerFactory原始碼探究     上面雖然我們看到了一些現象,能說明Controller預設情況下並不在IOC中託管,但是還沒有足夠的說服力,接下來我們就來檢視原始碼,這是最有說服力的。我們找到Controller工廠註冊的地方,在MvcCoreServiceCollectionExtensions擴充套件類中[[點選檢視原始碼