初識ASP.NET Core的小夥伴必定會發現,其幾乎全部的項目依賴都是經過依賴注入方式進行鏈式串通的。這是由於其使用了依賴注入 (DI) 的軟件設計模式,代碼的設計是遵循着「高內聚、低耦合」的原則,使得各個類與類之間的關係依賴於接口,這樣作的目的是能更有利於項目代碼的維護與擴展。設計模式
Autofaccookie
在進入主題以前我們仍是先來簡單的認識下鼎鼎大名的「Autofac」吧。那麼何爲Autofac呢,通俗的講就是一個開源的,且基於.NET Core、ASP.NET Core、.NET 4.5.1+等框架實現的控制反轉(IOC)類庫。經過Autofac能夠在.NET Core、ASP.NET Core、.NET 4.5.1+等項目上很容易的實現依賴注入,代碼很容易就能達到「高內聚、低耦合」的原則。另外,Autofac的中文資料也不少,須要詳細瞭解的也可在網上自行查看。框架
Autofac官方網站:https://autofac.org/async
Autofac官方的中文文檔網站:https://autofaccn.readthedocs.io/zh/latest/ide
背景網站
在咱們大部分的項目中都會將代碼抽成多層,每層之間經過相互依賴串聯工做。在這裏,咱們將ASP.NET Core項目代碼抽成三層結構,分別爲輸入輸出層(MVC項目)、業務層(類庫)、數據層(類庫),每層的功能描述以下:ui
一、Lezhima.Web:接受來自客戶端的請求,及服務端響應的出入口。由一個基於ASP.NET Core的MVC項目組成。spa
二、Lezhima.Core:根據請求作出相應的業務判斷,及調度上下游數據並計算,輸出相應的業務結果給調用者。由一個基於.NET Core的類庫組成。設計
三、Lezhima.Data:直接跟DB進行通信交互,實現對DB的增、刪、改、查等操做。由一個基於.NET Core的類庫組成。code
依賴關係:
基於上述中的三層代碼結構,咱們能夠清晰的看出Lezhima.Web作爲項目出入口,在其須要時會調用Lezhima.Core類庫,並將業務交由Lezhima.Core庫處理,而Lezhima.Core類庫在其須要時會調用Lezhima.Data類庫操做DB。那麼,它們之間的依懶關係應該是這樣子的:
一、Lezhima.Web同時依賴於Lezhima.Core與Lezhima.Data類庫。
二、Lezhima.Core依賴於Lezhima.Data類庫。
實現代碼
經過上面的介紹,咱們清楚了三個分層之間的功能與依賴關係,那麼接下來咱們就分別來看看它們具體代碼及使用Autofac如何優雅的實現依賴注入吧。
一、首先在Lezhima.Web項目中經過NuGet管理器引用:Autofac、Autofac.Extensions.DependencyInjection兩個類庫。
二、咱們先來看看Lezhima.Data層的代碼,首先定義一個名爲「IRepository」接口,代碼以下:
1 using System; 2 using System.Collections.Generic; 3 using System.Data; 4 using System.Linq; 5 using System.Linq.Expressions; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Lezhima.Data.Interface 10 { 11 public interface IRepository<T> where T : class 12 { 13 /// <summary> 14 /// 從指定的表中獲取符合條件的一條實體數據 15 /// </summary> 16 /// <param name="predicate"></param> 17 /// <returns></returns> 18 Task<T> GetAsync(Expression<Func<T, bool>> predicate); 19 } 20 }
三、在Lezhima.Data層再增長一個名爲「Repository」類,實現「IRepository」接口,代碼以下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Data; 7 using System.Linq.Expressions; 8 using Microsoft.EntityFrameworkCore; 9 using System.Data.SqlClient; 10 using Lezhima.Data.Interface; 11 12 namespace Lezhima.Data 13 { 14 /// <summary> 15 /// 數據層 16 /// 實現IRepository接口 17 /// </summary> 18 /// <typeparam name="T"></typeparam> 19 public class Repository<T> : IRepository<T> where T : class 20 { 21 22 /// <summary> 23 /// 從指定的表中獲取符合條件的一條實體數據 24 /// </summary> 25 /// <param name="predicate"></param> 26 /// <returns></returns> 27 public async Task<T> GetAsync(Expression<Func<T, bool>> predicate) 28 { 29 using (var db = new LezhimaContext()) 30 { 31 if (predicate == null) 32 return null; 33 34 return await db.Set<T>().Where(predicate).FirstOrDefaultAsync<T>(); 35 } 36 } 37 } 38 } 39
四、在Lezhima.Core層再定義一個名爲「IUserCore」接口,代碼以下:
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Threading.Tasks; 5 6 namespace Lezhima.Core.Interface 7 { 8 public interface IUserCore 9 { 10 /// <summary> 11 /// 根據帳號密碼判斷用戶是否擁有合法登陸權限 12 /// </summary> 13 /// <param name="email"></param> 14 /// <returns>100成功,101帳號錯誤,102密碼錯誤,103參數不合法</returns> 15 Task<MobiResult> Login(string email,string pwd); 16 } 17 } 18
五、在Lezhima.Core層再增長一個名爲「UserCore」類,實現「IUserCore」接口,代碼以下:
1 using Lezhima.Core.Interface; 2 using Lezhima.Data.Interface; 3 using System; 4 using System.Collections.Generic; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Lezhima.Core 9 { 10 public class UserCore : IUserCore 11 { 12 //定義一個依賴屬性 13 private readonly IRepository<EB_User> _Repository; 14 15 /// <summary> 16 /// 經過構造涵數方式注入Data層的Repository實例 17 /// </summary> 18 /// <param name="repository"></param> 19 public UserCore(IRepository<EB_User> repository) 20 { 21 _Repository = repository; 22 } 23 24 25 /// <summary> 26 /// 根據帳號密碼判斷用戶是否擁有合法登陸權限 27 /// </summary> 28 /// <returns>100成功,101帳號錯誤,102密碼錯誤,103參數不合法</returns> 29 public async Task<MobiResult> Login(string email, string pwd) 30 { 31 if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(pwd)) 32 return new MobiResult(103); 33 34 //到Data層去取指定用戶的數據 35 var model= await _Repository.GetAsync(p => p.Email.Equals(email)&&p.IsDelete!=99); 36 if(model ==null) 37 return new MobiResult(101); 38 39 if(!model.Pwd.Equals(pwd)) 40 return new MobiResult(102); 41 42 return new MobiResult(100); 43 } 44 45 } 46 } 47
六、在Lezhima.Web層增長一個名爲「AccountController 」的控制器,代碼以下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Security.Claims; 5 using System.Threading.Tasks; 6 using Lezhima.Core.Interface; 7 using Microsoft.AspNetCore.Authentication; 8 using Microsoft.AspNetCore.Authentication.Cookies; 9 using Microsoft.AspNetCore.Authorization; 10 using Microsoft.AspNetCore.Http; 11 using Microsoft.AspNetCore.Mvc; 12 13 namespace Lezhima.Web.Controllers 14 { 15 [Authorize] 16 [AutoValidateAntiforgeryToken] 17 public class AccountController : Controller 18 { 19 20 //定義一個依賴屬性 21 private readonly IUserCore _UserCore; 22 23 /// <summary> 24 /// 經過構造涵數方式注入Core層的UserCore實例 25 /// </summary> 26 /// <param name="__UserCore"></param> 27 public AccountController(IUserCore __UserCore) 28 { 29 _UserCore = __UserCore; 30 } 31 32 33 // GET: Account 34 public ActionResult Index() 35 { 36 return View(); 37 } 38 39 40 41 42 /// <summary> 43 /// 實現客戶端的登陸操做 44 /// </summary> 45 /// <param name="loginRequest"></param> 46 /// <returns></returns> 47 [HttpPost] 48 [AllowAnonymous] 49 public async Task<IActionResult> Login(LoginRequest loginRequest) 50 { 51 var result = await _UserCore.Login(loginRequest.Email, loginRequest.Pwd); 52 53 if (result.Code != 100) 54 { 55 ViewBag.ResultModel = result; 56 return View(); 57 } 58 59 //向客戶端寫入用戶的身份cookie 60 var _user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] 61 { 62 new Claim("UserId", user_model.UserId.ToString()), 63 }, CookieAuthenticationDefaults.AuthenticationScheme)); 64 await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, _user); 65 66 if (string.IsNullOrWhiteSpace(loginRequest.ReturnUrl)) 67 { 68 return RedirectToAction("Index", "Home"); 69 } 70 return Redirect(loginRequest.ReturnUrl); 71 } 72 73 } 74 }
七、在Lezhima.Web層增長一個名爲「Evolution」的類,用於繼承Autofac的Module類,實現上述三層之間的依賴關係注入,代碼以下:
1 using Autofac; 2 using Lezhima.Core; 3 using Lezhima.Data; 4 using Lezhima.Data.Interface; 5 using System; 6 7 namespace Lezhima.Web.Injection 8 { 9 /// <summary> 10 /// 重寫依賴注入的業務 11 /// </summary> 12 public class Evolution : Module 13 { 14 protected override void Load(ContainerBuilder builder) 15 { 16 //注入Data層的Repository類 17 builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerDependency(); 18 //批量注入Core層的類 19 builder.RegisterAssemblyTypes(typeof(UserCore).Assembly) 20 .Where(t => t.Name.EndsWith("Core")) 21 .AsImplementedInterfaces(); 22 } 23 } 24 } 25
八、在Lezhima.Web層的「Startup」類的「ConfigureServices」方法內注入便可,代碼以下:
1 public IConfiguration Configuration { get; } 2 3 public IServiceProvider ConfigureServices(IServiceCollection services) 4 { 5 services.AddMvc(); 6 7 //將Evolution註冊到項目中來,實現依賴注入 8 var builder = new ContainerBuilder(); 9 builder.RegisterModule(new Evolution()); 10 builder.Populate(services); 11 var container = builder.Build(); 12 return container.Resolve<IServiceProvider>(); 13 }
總結
一、每層在調用時,經過在該類內聲明一個接口類型的屬性(變量),再經過Autofac構造涵數注入方式實現依賴注入並獲取到相應的類實例。
二、經過繼承Autofac的Module類,並在Load方法內重寫自已項目的類關係來實現注入業務。
三、Autofac注入有多種不一樣的生命週期類型,分別爲InstancePerLifetimeScope、SingleInstance、InstancePerDependency等,各位在項目中按需選擇便可。
四、最後再經過在ASP.NET Core項目內的「Startup」類內將注入代碼類註冊到項目中就可正常使用了。
聲明
本文爲做者原創,轉載請備註出處與保留原文地址,謝謝。如文章能給您帶來幫助,請點下推薦或關注,感謝您的支持!