一、前言
分層開發的思想在計算機領域中至關重要,從操作系統到軟件設計,分層思想無處不在。
在搭建項目的分層結構前,先簡單了解下分層的優缺點。如下圖,分為(呈現層、業務層、服務層、數據層)
分層的優點:
1、層次分明,各司其職:每層都有各自的責任,各層級相互獨立,上層不需要知道下層的內部實現,上層的改動不會影響下一層。
2、易於開發,便於調試:分層結構使得開發人員可以專注於謀一層進行開發,進行調試時,可以針對每一層進行單獨調試。
3、促進標准,移植復用:可替換任意一層,如當前數據層讀數據庫,可替換為讀文件數據,取網絡數據。亦可移植到其他項目。
4、。。。。。。
分層的缺點:
1、降低性能:一個簡單的數據呈現,需逐層返回且中間的數據轉換等都耗費時間。
2、級聯修改:在呈現層中增加一個功能,為保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼。
3、。。。。。。
二、WebAPI項目分層
簡單了解了分層優缺點后,創建項目的分層結構
此處注意,這里為了規范項目名稱,重新建了個Web API項目命名為MWebAPI(上篇文章項目名稱為mweb-api)
各項目職責如下:
Action:用來分發來自客戶端(PC、移動設備、瀏覽器)的請求;
Services:進行具體的業務處理;
IServices:Services的抽象;
Repository:先假想為數據訪問層(實際上和數據訪問層區別較大);
IRepository:Repository的抽象;
Entity:數據實體映射,通常從數據庫映射而來;
Dto:數據傳輸對象,一般和前端頁面相對應;
Utility:通用工具層,提供公用幫助類;
明確了各層的職責,下面創建一個簡單的業務來貫穿各層。以獲取用戶信息為例
三、獲取用戶信息流程
四、用戶信息各層實現
1、創建UserInfo實體類
在MEntity項目中新建 UserInfo實體類
public class UserInfo { public string UserName { get; set; } public int Age { get; set; } public string Address { get; set; } }
2、創建UserInfoDto傳輸對象
在MDto項目中新建 UserInfoDto
public class UserInfoDto { public string UserName { get; set; } public int Age { get; set; } public string Address { get; set; } }
問題:Dto有什么意義?
初略理解:在項目的初期,數據表字段與Controller返回的字段往往是一致的,如同上面的獲取用戶信息業務。此情形下,Dto無意義。
但當數據表中還有Password,TelPhone等信息但前端並不需要時,此時Dto只返回所需,避免傳輸整張表,一定程度上提高了項目的安全性。
3、創建倉儲接口與倉儲實現類
在MIRepository項目中新建IUserInfoRepository
public interface IUserInfoRepository { UserInfo GetUserInfo(); }
在MRepository項目中新建UserInfoRepository,目前項目並未連接數據庫,故直接返回個實體類對象
public class UserInfoRepository : IUserInfoRepository { public UserInfo GetUserInfo() { return new UserInfo() { UserName = "王二麻子", Age = 20, Address = "那美克星", }; } }
4、創建服務接口與服務實現類
在MIServices項目中新建IUserInfoServices
public interface IUserInfoServices { UserInfoDto GetUserInfo(); }
在MIServices項目中新建UserInfoServices
public class UserInfoServices : IUserInfoServices { readonly IUserInfoRepository _rep = new UserInfoRepository(); public UserInfoDto GetUserInfo() { var entity = _rep.GetUserInfo(); UserInfoDto dto = new UserInfoDto { UserName = entity.UserName, Age = entity.Age, Address = entity.Address }; return dto; } }
5、創建Controller
在MWebAPI項目中新建UserInfoController
[ApiController] [Route("[controller]/[action]")] public class UserInfoController : Controller { private readonly IUserInfoServices _services = new UserInfoServices(); [HttpGet] public UserInfoDto GetUserInfo() { return _services.GetUserInfo(); } }
啟動項目,瀏覽器輸入:http://localhost:5000/UserInfo/GetUserInfo,數據返回成功。
五、服務注入
此時項目中UserInfoController的 _services 是new出來的,UserInfoServices 的_rep也是如此,目前比較流行的是使用依賴注入的方式去注入服務,下面我們改寫Services及Controller,如下:
public class UserInfoServices : IUserInfoServices { private readonly IUserInfoRepository _rep; public UserInfoServices(IUserInfoRepository rep) { _rep = rep; } public UserInfoDto GetUserInfo() { var entity = _rep.GetUserInfo(); UserInfoDto dto = new UserInfoDto { UserName = entity.UserName, Age = entity.Age, Address = entity.Address }; return dto; } }
public class UserInfoController : Controller { private readonly IUserInfoServices _services; public UserInfoController(IUserInfoServices services) { _services = services; } [HttpGet] public UserInfoDto GetUserInfo() { return _services.GetUserInfo(); } }
啟動項目,瀏覽器輸入:http://localhost:5000/UserInfo/GetUserInfo。
此時是因為未注入服務,在Startup類ConfigureServices方法中注入服務
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddScoped<IUserInfoRepository, UserInfoRepository>(); services.AddScoped<IUserInfoServices, UserInfoServices>(); }
再次運行
六、結語
本篇文章中涉及了兩個概念倉儲模式與依賴注入(.Net Core 3.1瀏覽器后端服務(四) 你眼中的依賴注入與我相同嗎?),目前並未深入的研究,將在后續的文章中挖掘。
Services和Repository均定義了相應的接口,一個好處是便於服務注入。這樣做還有哪些好處?歡迎各位道友一起討論!!!