話不多說,直入主題看我們的解決方案結構:

分別對上面的工程進行簡單的說明:
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.Web.Mvc; 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); } } }
至此,完成處理,接下來就是見證奇跡的時刻了,我們訪問 /home/index,看看是否能返回學生信息。

我們可以發現,返回了學生的信息,說明我們注入成功了。
總結:
1、采用的是構造函數注入的方式,在構造函數中初始化賦值。
2、StuRepository對象不需要實例化,即不需要new,降低了系統資源的消耗。
3、需要在Global.asax中對StudentRepository寫映射,如果倉儲類比較多的時候,就需要寫很多了,如何避免,這個在后面的篇幅中會講解到。
擴展: 上面講解了構造函數注入的方式,下面擴展屬性注入的方式,在Global.asax中稍微修改下注入語句即可。
將:
builder.RegisterControllers(typeof(MvcApplication).Assembly);
改為:
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
PropertiesAutowired:表示允許屬性注入。
接下來我們來看下怎么使用,修改下我們的依賴注入語句,新增服務層學生類注入:
/// <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.Web.Mvc; using TianYa.DotNetShare.Service; namespace TianYa.DotNetShare.MvcDemo.Controllers { public class HomeController : Controller { /// <summary> /// 通過屬性注入,訪問修飾符必須為public,否則會注入失敗 /// </summary> public IStudentService StuService { get; set; } public ActionResult Index() { var stu = StuService.GetStuInfo("10001"); string msg = $"學號:10001,姓名:{stu.Name},性別:{stu.Sex},年齡:{stu.Age}。"; return Content(msg); } } }
再訪問一下我們的/home/index

我們可以發現,返回了學習信息,說明我們注入成功了。
另外通過這個例子我們可以發現在注入倉儲層對象StudentRepository時,不僅控制器中注入成功了,而且在服務層中也注入成功了,說明我們的Autofac的注入是全局的。
總結:
1、通過屬性注入,訪問修飾符必須為public,否則會注入失敗。
2、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>(); builder.RegisterType<StudentRepository>(); //實現類注入 //設置依賴解析器 var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); }
再來看下我們的控制器
using System.Web.Mvc; using TianYa.DotNetShare.Repository.Impl; namespace TianYa.DotNetShare.MvcDemo.Controllers { public class HomeController : Controller { /// <summary> /// 定義倉儲層學生實現類對象 /// </summary> public StudentRepository StuRepositoryImpl { get; set; } public ActionResult Index() { var stu = StuRepositoryImpl.GetStuInfo("10002"); string msg = $"學號:10002,姓名:{stu.Name},性別:{stu.Sex},年齡:{stu.Age}"; return Content(msg); } } }
再訪問一下我們的/home/index

可以看出已經實現了我們具體的實現類注入
到了這里,大家可能會發現在我們的Global.asax文件中,所有倉儲層、服務層的類都需要一個個注冊,那如果很多類的話,那可就寫老長了,那有什么解決方法嗎,答案是肯定的。Autofac還提供了其他方式注入,下面就介紹下我們的解決辦法。
還記得我們上面介紹倉儲層和服務層實現類的時候都實現了我們的IDependency接口嗎,接下來就派上大用場了,我們可以一次性注冊所有實現了IDependency接口的類。
修改一下我們的依賴注入方式來實現一次性注入:
using System; using System.Linq; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using System.Reflection; using System.IO; using Autofac; using Autofac.Integration.Mvc; using TianYa.DotNetShare.Model; 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控制器(注冊所有到控制器,控制器注入,就是需要在控制器的構造函數中接收對象) //PropertiesAutowired:允許屬性注入 builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired(); //一次性注冊所有實現了IDependency接口的類 Type baseType = typeof(IDependency); Assembly[] assemblies = Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath, "*.dll").Select(Assembly.LoadFrom).ToArray(); builder.RegisterAssemblyTypes(assemblies) .Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract) .AsSelf().AsImplementedInterfaces() .PropertiesAutowired().InstancePerLifetimeScope(); //設置依賴解析器 var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } } }
最后再來看下我們的控制器
using System.Web.Mvc; using TianYa.DotNetShare.Service; using TianYa.DotNetShare.Repository; using TianYa.DotNetShare.Repository.Impl; namespace TianYa.DotNetShare.MvcDemo.Controllers { public class HomeController : Controller { /// <summary> /// 定義倉儲層學生實現類對象 /// </summary> public StudentRepository StuRepositoryImpl { get; set; } /// <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 stu1 = StuRepository.GetStuInfo("10000"); var stu2 = StuService.GetStuInfo("10001"); var stu3 = StuRepositoryImpl.GetStuInfo("10002"); string msg = $"學號:10000,姓名:{stu1.Name},性別:{stu1.Sex},年齡:{stu1.Age}<br />"; msg += $"學號:10001,姓名:{stu2.Name},性別:{stu2.Sex},年齡:{stu2.Age}<br />"; msg += $"學號:10002,姓名:{stu3.Name},性別:{stu3.Sex},年齡:{stu3.Age}"; return Content(msg); } } }
再次訪問一下我們的/home/index

可以看出成功返回了學生信息,說明我們的一次性注入成功了。
至此我們就介紹完了Autofac依賴注入在MVC中的具體使用,下一章我們將繼續簡單的介紹下Autofac在普通的WebForm當中的使用。
demo源碼:
鏈接:https://pan.baidu.com/s/1jUbf1pk2-bSybf9OfUh8Tw 提取碼:24ki
參考博文:https://www.cnblogs.com/fei686868/p/10979790.html
版權聲明:如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!
