本系列主要講述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.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);
}
}
}
可以看出已經實作了我們具體的實作類注入
到了這裡,大家可能會發現在我們的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
版權聲明:如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!