ASP.NET Core Controller與IOC的羈絆
阿新 • • 發佈:2021-01-04
#### 前言
看到標題可能大家會有所疑問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擴充套件類中[[點選檢視原始碼