第 3 章 ASP.NET Core 核心特性
3.3 依賴注入
通常情況下,應(yīng)用程序由多個(gè)組件構(gòu)成,而組件與組件之間往往存在依賴關(guān)系
當(dāng)我們需要獲取數(shù)據(jù)時(shí),通常的做法是實(shí)例化依賴的類,然后調(diào)用類里面的方法,但是這種依賴方式會(huì)增加調(diào)用方和被調(diào)用方之間的耦合,也會(huì)增加應(yīng)用程序維護(hù)成本及靈活性,同時(shí)增加了單元測試的難度
為了解決這一問題,需要用到依賴倒置原則,高層不直接依賴低層,兩者均依賴抽象
public class Book
{
}
public interface IDataService
{
List<Book> GetAllBooks();
}
public class DataService : IDataService
{
public List<Book> GetAllBooks()
{
return new List<Book>();
}
}
public class DisplayDataService
{
private readonly IDataService _dataService;
public DisplayDataService(IDataService dataService)
{
_dataService = dataService;
}
public void ShowData()
{
var data = _dataService.GetAllBooks();
}
}
接下來,只需要在實(shí)例化 DisplayDataService 的時(shí)候,在構(gòu)造函數(shù)傳入一個(gè) IDataService 接口的具體實(shí)現(xiàn)即可
IDataService dataService = new DataService();
DisplayDataService displayDataService = new DisplayDataService(dataService);
除了構(gòu)造函數(shù)注入之外,還有屬性注入和方法注入
當(dāng)應(yīng)用程序中有多處要用到依賴注入時(shí),就需要一個(gè)專門的類來負(fù)責(zé)管理創(chuàng)建所需要的類并創(chuàng)建所有它可能要用到的依賴,這個(gè)類就是依賴注入容器,也可以稱為控制反轉(zhuǎn)容器,IOC 容器
在 ASP.NET Core 中,所有被放入依賴注入容器的類型或組件被稱為服務(wù)
容器中的服務(wù)有兩種類型:第一種是框架服務(wù),它們是 ASP.NET Core 框架的組成部分;另一種是應(yīng)用服務(wù),所有由用戶放到容器中的服務(wù)都屬于這一類
在 ASP.NET Core 內(nèi)置的依賴注入容器中,服務(wù)的生命周期有如下3種類型:
- Singleton:容器會(huì)創(chuàng)建并共享服務(wù)的單例,且一直會(huì)存在于應(yīng)用程序的整個(gè)生命周期內(nèi)
- Transient:每次服務(wù)被請求時(shí),總會(huì)創(chuàng)建新實(shí)例
- Scoped:在每一次請求時(shí)會(huì)創(chuàng)建服務(wù)的新實(shí)例,并在這個(gè)請求內(nèi)一直共享這個(gè)實(shí)例
3.4 MVC
MVC 是模型、視圖、控制器的縮寫,它是 Web 應(yīng)用程序中一種常見的架構(gòu)模式,最主要的優(yōu)點(diǎn)是實(shí)現(xiàn)了關(guān)注點(diǎn)分離
在 ASP.NET Core MVC 框架中,除了 Controller、Model 和 Action 外,它還包括路由、模型綁定、模型驗(yàn)證和過濾器等功能
路由的主要功能是根據(jù)預(yù)先配置的路由信息對客戶端傳來的請求進(jìn)行路由映射,映射完成后,再將請求傳給對應(yīng)的路由處理器處理
對于 ASP.NET Core MVC,定義路由的方法有以下兩種:
- 基于約定的路由
- 特性路由
基于約定的路由需要在 Startup 類中指明,具體來說,應(yīng)該在配置 MVC 中間件時(shí)來設(shè)置路由約定
app.UseMvc(routes =>
{
routes.MapRoute("default",template: "{controller}/{action}");
});
以下約定為 controller 和 action 設(shè)置了默認(rèn)值,參數(shù) id 后面有一個(gè)問號,說明這個(gè)參數(shù)時(shí)可選的,在 URL 中有無此項(xiàng)都可以,注意,一個(gè) URL 模板中只能有一個(gè)可選參數(shù),并且只能放在最后
app.UseMvc(routes =>
{
routes.MapRoute("default",template: "{controller=Home}/{action=Index}/{id?}");
});
指定參數(shù)時(shí),也可以添加約束
app.UseMvc(routes =>
{
routes.MapRoute("default",template: "{controller=Home}/{action=Index}/{id:int}");
});
特性路由只需要在 Controller 類或 Action 方法上添加 [Route] 特性即可
[Route("Home")]
public class HomeController : Controller
{
[Route("Index")]
public IActionResult Index()
{
return View();
}
}
當(dāng) Controller 需要依賴其他服務(wù)時(shí),通常的做法是使用構(gòu)造函數(shù)注入所需要的服務(wù),當(dāng)程序運(yùn)行時(shí),ASP.NET Core 會(huì)在創(chuàng)建 Controller 時(shí)自動(dòng)從其依賴注入的容器中獲取所有依賴的服務(wù),需要注意的是,所注入的服務(wù)必須存在于容器中,否則會(huì)發(fā)生異常
Action 的返回結(jié)果有以下4類:
- StatusCode
- ObjectResult
- 重定向結(jié)果
- 內(nèi)容結(jié)果
模型綁定:將 HTTP 請求中的數(shù)據(jù)映射到 Action 中參數(shù)的過程
ASP.NET Core MVC 模型綁定特性:
- [FromHeader]
- [FromQuery]
- [FromServices]
- [FromRoute]
- [FromForm]
- [FromBody]
還有兩個(gè)特性用于指明參數(shù)是否必須使用綁定:
- BindRequiredAttribute
- BindNeverAttribute
模型驗(yàn)證:指數(shù)據(jù)被使用之前的驗(yàn)證過程,它發(fā)生在模型綁定之后
數(shù)據(jù)注解通常用于驗(yàn)證,只要為類的屬性添加需要的數(shù)據(jù)注解驗(yàn)證特性即可:
- [Required]
- [MinLength(10)]
- [Url]
- [Range(1,5)]
在 Controller 內(nèi)的 Action 中,要檢查一個(gè)對象是否滿足指定的條件,只要調(diào)用 ModelState.IsVaild 屬性,其中 ModelState 是 ControllerBase 類的屬性
ASP.NET Core MVC 提供兩種創(chuàng)建自定義驗(yàn)證的方法:
- 創(chuàng)建新特性,并使它繼承自 ValidationAttribute 類
- 使待驗(yàn)證的 Model 實(shí)現(xiàn) IValidatableObject 接口
過濾器:與中間件很相似,在 ASP.NET Core MVC 中,它們能夠在某些功能的前后執(zhí)行,由此形成一個(gè)管道
ASP.NET Core MVC 提供了以下5種類型的過濾器:
- Authorization
- Resource
- Action
- Exception
- Result
當(dāng)要?jiǎng)?chuàng)建過濾器時(shí),應(yīng)該實(shí)現(xiàn) IXXXFilter 或 IAsyncXXXFilter,前者同步,后者異步,實(shí)現(xiàn)一個(gè)即可
在 startup 種注冊過濾器會(huì)使它影響到應(yīng)用中的每個(gè) Action,如果要僅為一個(gè)或少數(shù)幾個(gè) Action 添加過濾器,就得使用特性,ASP.NET Core 為每一種類型的過濾器都定義了相應(yīng)的特性
如果以特性的方式使用包含依賴項(xiàng)的過濾器時(shí),就會(huì)出錯(cuò),因?yàn)樵谧远x特性的構(gòu)造函數(shù)中定義的接口類型的參數(shù)并不是有效的特性參數(shù),此時(shí)需要使用 [ServiceFilter] 特性或者 [TypeFilter] 特性,并設(shè)置它們的 Type 屬性為自定義過濾器類型
[ServiceFilter] 特性與 [TypeFilter] 特性的區(qū)別是前者會(huì)從容器中獲取過濾器實(shí)例,而后者不會(huì),它使用 ObjectFactory 對指定的過濾器類型進(jìn)行實(shí)例化,如果使用前者,需要在 Startup 類的 ConfigureServices 方法中將該過濾器添加到容器中
????
本文摘自 :https://blog.51cto.com/u