本系列主要講述IOC依賴註入之Autofac在ASP.NET MVC項目中以及在WebForm項目中的具體應用。 ...
話不多說,直入主題看我們的解決方案結構:
分別對上面的工程進行簡單的說明:
1、TianYa.DotNetShare.Model:為demo的實體層
2、TianYa.DotNetShare.Repository:為demo的倉儲層即數據訪問層
3、TianYa.DotNetShare.Service:為demo的服務層即業務邏輯層
4、TianYa.DotNetShare.MvcDemo:為demo的web層項目,MVC框架
約定:本demo的web項目為ASP.NET Web 應用程式(.NET Framework 4.5) MVC框架,實體層、倉儲層、服務層均為.NET Framework 4.5 類庫。
一、實體層
1、定義一個空介面IDependency,後面有妙用,用於一次性註入
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TianYa.DotNetShare.Model { /// <summary> /// 空介面,用於一次性註入 /// </summary> public interface IDependency { } }
2、新建一個學生實體 Student
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TianYa.DotNetShare.Model { /// <summary> /// 學生類 /// </summary> public class Student { /// <summary> /// 學號 /// </summary> public string StuNo { get; set; } /// <summary> /// 姓名 /// </summary> public string Name { get; set; } /// <summary> /// 年齡 /// </summary> public int Age { get; set; } /// <summary> /// 性別 /// </summary> public string Sex { get; set; } } }
demo中的實體就這樣了
二、倉儲層
本demo的倉儲層需要引用我們的實體層TianYa.DotNetShare.Model
為什麼選擇用倉儲,原因很簡單,方便我們進行個性化擴展。在數據操作的底層進行其他個性化邏輯處理。
約定:
1、介面的定義放在根目錄下,介面的實現類,統一放到Impl文件夾,表示實現類目錄。
2、每個實體,對應一個倉儲的介面和實現類,即有多少個實體,就對應創建多少個介面和實現類。
我們新建一個Student的倉儲介面 IStudentRepository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Repository { /// <summary> /// 學生類倉儲層介面 /// </summary> public interface IStudentRepository { /// <summary> /// 根據學號獲取學生信息 /// </summary> /// <param name="stuNo">學號</param> /// <returns>學生信息</returns> Student GetStuInfo(string stuNo); } }
接著在Impl中新建一個Student的倉儲實現StudentRepository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Repository.Impl { /// <summary> /// 學生類倉儲層 /// </summary> public class StudentRepository : IStudentRepository, IDependency { /// <summary> /// 根據學號獲取學生信息 /// </summary> /// <param name="stuNo">學號</param> /// <returns>學生信息</returns> public Student GetStuInfo(string stuNo) { //數據訪問邏輯,此處為了演示就簡單些 var student = new Student(); switch (stuNo) { case "10000": student = new Student() { StuNo = "10000", Name = "張三", Sex = "男", Age = 20 }; break; case "10001": student = new Student() { StuNo = "10001", Name = "錢七七", Sex = "女", Age = 18 }; break; case "10002": student = new Student() { StuNo = "10002", Name = "李四", Sex = "男", Age = 21 }; break; default: student = new Student() { StuNo = "10003", Name = "王五", Sex = "男", Age = 25 }; break; } return student; } } }
該類同時實現了IStudentRepository介面和IDependency介面,其中實現IDependency介面的目的是為了後面的web端進行一次性註入
三、服務層
本demo的服務層需要引用我們的實體層TianYa.DotNetShare.Model和我們的倉儲層TianYa.DotNetShare.Repository
服務層與倉儲層類似,它屬於倉儲層的使用者。定義的方式也與倉儲層類似,有介面和Impl實現目錄。
但服務層不需要一個實體對應一個,服務層更多的是按照功能模塊進行劃分,比如一個登錄模塊,創建一個LoginService。
為了演示,我們新建一個Student的服務層介面IStudentService.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Service { /// <summary> /// 學生類服務層介面 /// </summary> public interface IStudentService { /// <summary> /// 根據學號獲取學生信息 /// </summary> /// <param name="stuNo">學號</param> /// <returns>學生信息</returns> Student GetStuInfo(string stuNo); } }
接著我們同樣在Impl中新建一個Student的服務層實現StudentService.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TianYa.DotNetShare.Model; using TianYa.DotNetShare.Repository; namespace TianYa.DotNetShare.Service.Impl { /// <summary> /// 學生類服務層 /// </summary> public class StudentService : IStudentService, IDependency { /// <summary> /// 定義倉儲層學生抽象類對象 /// </summary> protected IStudentRepository StuRepository; /// <summary> /// 空構造函數 /// </summary> public StudentService() { } /// <summary> /// 構造函數 /// </summary> /// <param name="stuRepository">倉儲層學生抽象類對象</param> public StudentService(IStudentRepository stuRepository) { this.StuRepository = stuRepository; } /// <summary> /// 根據學號獲取學生信息 /// </summary> /// <param name="stuNo">學號</param> /// <returns>學生信息</returns> public Student GetStuInfo(string stuNo) { var stu = StuRepository.GetStuInfo(stuNo); return stu; } } }
該類同時實現了IStudentService介面和IDependency介面,其中實現IDependency介面的目的是為了後面的web端進行一次性註入
四、Web層
本demo的web項目需要引用以下幾個程式集:
1、TianYa.DotNetShare.Model 我們的實體層
2、TianYa.DotNetShare.Service 我們的服務層
3、TianYa.DotNetShare.Repository 我們的倉儲層,正常我們的web項目是不應該使用倉儲層的,此處我們引用是為了演示IOC依賴註入
4、Autofac 依賴註入基礎組件
5、Autofac.Mvc5 依賴註入Mvc5的輔助組件
其中Autofac和Autofac.Mvc5可以從我們的NuGet上引用:
如果從線下已安裝的程式包源中找不到我們要的程式集,可以嘗試添加我們的程式包源,具體步驟如下:
名稱:nuget.org 源:https://api.nuget.org/v3/index.json
添加新的包源後點擊確定(如果已經有此包源就忽略該步驟),接下來就從NuGet上安裝我們需要的程式集。
依次點擊下載以下2個組件
至此我們所有的工作都已經準備好了,接下來就是重頭戲,開始做註入工作了。
打開我們的Global.asax文件進行註入工作
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using Autofac; using Autofac.Integration.Mvc; using TianYa.DotNetShare.Model; using TianYa.DotNetShare.Repository.Impl; using TianYa.DotNetShare.Repository; namespace TianYa.DotNetShare.MvcDemo { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AutofacRegister(); //Autofac依賴註入 } /// <summary> /// Autofac依賴註入 /// </summary> private void AutofacRegister() { var builder = new ContainerBuilder(); //註冊MVC控制器(註冊所有到控制器,控制器註入,就是需要在控制器的構造函數中接收對象) builder.RegisterControllers(typeof(MvcApplication).Assembly); //構造函數註入,對StudentRepository與介面進行註入 builder.RegisterType<StudentRepository>().As<IStudentRepository>(); //設置依賴解析器 var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } } }
至此,我們就完成了依賴註入工作,此方式為構造函數註入,接下來我們來看看控制器裡面怎麼弄。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using TianYa.DotNetShare.Model; using TianYa.DotNetShare.Service; using TianYa.DotNetShare.Repository; namespace TianYa.DotNetShare.MvcDemo.Controllers { public class HomeController : Controller { /// <summary> /// 定義倉儲層學生抽象類對象 /// </summary> protected IStudentRepository StuRepository; /// <summary> /// 通過構造函數進行註入 /// 註意:參數是抽象類,而非實現類,因為已經在Global.asax中將實現類映射給了抽象類 /// </summary> /// <param name="stuRepository">倉儲層學生抽象類對象</param> public HomeController(IStudentRepository stuRepository) { this.StuRepository = stuRepository; } public ActionResult Index() { var stu = StuRepository.GetStuInfo("10000"); string msg = $"學號:10000,姓名:{stu.Name},性別:{stu.Sex},年齡:{stu.Age}。"; return Content(msg); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } } }
至此,完成處理,接下來就是見證奇跡的時刻了,我們訪問 /home/index,看看是否能返回學生信息。
我們可以發現,返回了學生的信息,說明我們註入成功了。
總結:
1、採用的是構造函數註入的方式,在構造函數中初始化賦值。
2、StuRepository對象不需要實例化,即不需要new,降低了系統資源的消耗。
3、需要在Global.asax中對StudentRepository寫映射,如果倉儲類比較多的時候,就需要寫很多了,如何避免,這個在後面的篇幅中會講解到。
擴展: 上面講解了構造函數註入的方式,下麵擴展屬性註入的方式,在Global.asax中稍微修改下註入語句即可。
將:
builder.RegisterControllers(typeof(MvcApplication).Assembly);
改為:
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
PropertiesAutowired:表示允許屬性註入。
接下來我們來看下怎麼使用,修改我們的Global.asax代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using Autofac; using Autofac.Integration.Mvc; using TianYa.DotNetShare.Model; using TianYa.DotNetShare.Repository.Impl; using TianYa.DotNetShare.Repository; using TianYa.DotNetShare.Service; using TianYa.DotNetShare.Service.Impl; namespace TianYa.DotNetShare.MvcDemo { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AutofacRegister(); //Autofac依賴註入 } /// <summary> /// Autofac依賴註入 /// </summary> private void AutofacRegister() { var builder = new ContainerBuilder(); //註冊MVC控制器(註冊所有到控制器,控制器註入,就是需要在控制器的構造函數中接收對象) builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired(); //構造函數註入,對StudentRepository與介面進行註入 builder.RegisterType<StudentRepository>().As<IStudentRepository>(); builder.RegisterType<StudentService>().As<IStudentService>(); //設置依賴解析器 var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } } }
修改我們的控制器代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using TianYa.DotNetShare.Model; using TianYa.DotNetShare.Service; using TianYa.DotNetShare.Repository; namespace TianYa.DotNetShare.MvcDemo.Controllers { public class HomeController : Controller { /// <summary> /// 定義倉儲層學生抽象類對象 /// </summary> protected IStudentRepository StuRepository; /// <summary> /// 通過屬性註入,訪問修飾符必須為public,否則會註入失敗 /// </summary> public IStudentService StuService { get; set; } /// <summary> /// 通過構造函數進行註入 /// 註意:參數是抽象類,而非實現類,因為已經在Global.asax中將實現類映射給了抽象類 /// </summary> /// <param name="stuRepository">倉儲層學生抽象類對象</param> public HomeController(IStudentRepository stuRepository) { this.StuRepository = stuRepository; } public ActionResult Index() { var stu = StuRepository.GetStuInfo("10000"); var stu2 = StuService.GetStuInfo("10001"); string msg = $"學號:10000,姓名:{stu.Name},性別:{stu.Sex},年齡:{stu.Age}<br />"; msg += $"學號:10001,姓名:{stu2.Name},性別:{stu2.Sex},年齡:{stu2.Age}"; return Content(msg); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } } }
再訪問一下我們的/home/index
我們可以發現,返回了學習信息,說明我們註入成功了。
另外通過這個例子我們可以發現在註入倉儲層對象StudentRepository時,不僅控制器中註入成功了,而且在服務層中也註入成功了,說明我們的Autofac的註入是全局的。
總結:
1、通過屬性註入,訪問修飾符必須為public,否則會註入失敗。
2、Autofac的註入是全局的。
未完待續......
參考博文:https://www.cnblogs.com/fei686868/p/10979790.html
版權聲明:如有雷同純屬巧合,如有侵權請及時聯繫本人修改,謝謝!!!