【ASP.net MVC + DI】ASP.net MVC 使用 DI Framework - Autofac
在一開始我也搞不懂什麼是DI,IoC又是什麼,而且兩個通常都會同時提起,他們有什麼不尋常的關係...直到看了幾位前輩的Blog後才逐漸明朗
好的接下來得開始在專案上時做DI了!在幾位前輩的部落格中,找到幾套好用的DI Framework:Unity及Autofac,這邊選擇以Autofac主要原因是饅頭在網路上找到的資源較為豐富,出錯了還有地方可以詢問與查資料!
OK,選擇好了一個Framework後就開始我們DI的新旅程了!
一開始我們透過nuget來找到Autofac
在一開始我也搞不懂什麼是DI,IoC又是什麼,而且兩個通常都會同時提起,他們有什麼不尋常的關係...直到看了幾位前輩的Blog後才逐漸明朗
IoC:Inversion of control,控制反轉,由Martin Fowler提出
系統架構設計應該以抽象的邏輯概念為主,才能更貼近現實世界,才能更符合domain model,當Business logic不變時,需求變更、技術變更、DB變更,都應該要把風險和成本壓到最低。In 91 - [Software Architecture]IoC and DI
DI:Dependency injection,相依住入,透過IoC的概念,讓系統的Method都相依於Interface(介面),在應用程式啟動時去注入Interface所相對應的實體,取代原本以new Class()來產生。
好的接下來得開始在專案上時做DI了!在幾位前輩的部落格中,找到幾套好用的DI Framework:Unity及Autofac,這邊選擇以Autofac主要原因是饅頭在網路上找到的資源較為豐富,出錯了還有地方可以詢問與查資料!
OK,選擇好了一個Framework後就開始我們DI的新旅程了!
一開始我們透過nuget來找到Autofac
因饅頭的專案是MVC 4的專案搭配Web API,所以額外新增這兩個nuget package:Autofac ASP.NET MVC 4 Integration、Autofac ASP.NET Web API Integration
如果是MVC 5 則需安裝:Autofac ASP.NET MVC 5 Integration、Autofac ASP.NET Web API 2 Integration
將這三套DI Framewrok 加入到專案後,就得開始修改程式碼了!
饅頭這邊有使用Repository以及UnitOfWork的設計樣式,所以在一開始需要做一點小小的設定(如未使用可略過此步驟),程式碼的部分是由Kevin前輩所提供的程式碼來實作
程式碼的部分請參考本篇 mrkt 的程式學習筆記 - ASP.NET MVC 使用 Autofac 中的建立 IDbContextFactory 與 DbContextFactory
在Controller移除相依性
原本我們在Controller中會建立一個相對應的Services實體
public class HomeController : Controller
{
HomeServices services = new HomeServices();
// 以下省略
}
而我們希望在Controller中移除實體的相依性,然後讓Autofac幫我們自動產生相對應的實體,所以我們要先將Services先抽出一個介面,這邊可以利用Visual Studio中提供的工具來完成
抽出Interface後,我們將Controller中的程式碼修改為
public class HomeController : Controller
{
private IHomeServices service;
public HomeController(IHomeServices service)
{
this.service = service;
}
}
讓Autofac為我們注入IHomeServices的實體物件,讓Controller中的Services不會直接產生實體,解除了相依的關係
註冊Autofac
我們先在App_Start目錄下新增一個名為AutofacConfig.cs的檔案,並新增以下程式碼
using System.Configuration;
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Autofac.Integration.WebApi;
using Web.CatchNet.Models.DbContextFactory;
using Web.CatchNet.Repository;
using Web.CatchNet.Repository.Interface;
/// <summary>
/// DI設定檔
/// </summary>
public class AutofacConfig
{
/// <summary>
/// 註冊DI注入物件資料
/// </summary>
public static void Register()
{
// 容器建立者
ContainerBuilder builder = new ContainerBuilder();
// 註冊Controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// 註冊DbContextFactory
string connectionString =
ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
builder.RegisterType<DbContextFactory>()
.WithParameter("connectionString", connectionString)
.As<IDbContextFactory>()
.InstancePerHttpRequest();
// 註冊 Repository UnitOfWork
builder.RegisterGeneric(typeof(GenericRepository<>)).As(typeof(IRepository<>));
builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork));
// 註冊Services
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => t.Name.EndsWith("Services"))
.AsImplementedInterfaces();
// 建立容器
IContainer container = builder.Build();
// 解析容器內的型別
AutofacWebApiDependencyResolver resolverApi = new AutofacWebApiDependencyResolver(container);
AutofacDependencyResolver resolver = new AutofacDependencyResolver(container);
// 建立相依解析器
GlobalConfiguration.Configuration.DependencyResolver = resolverApi;
DependencyResolver.SetResolver(resolver);
}
}
在新增程式碼後,要到Global.asax中註冊
protected void Application_Start()
{
// 略
AutofacConfig.Register();
}
如此一來,Autofac在我們系統執行時,會為我們注入相對應的實體!
減少了系統直接依賴實體的問題,也可以在需求變更後快速修改線上服務,甚至替換整個Services
參考資料
KKBruce - 使用AUTOFAC和UNITY學習MVC 4,5和WEB API 1,2的IOC,DI技巧
mrkt 的程式學習筆記 - ASP.NET MVC 使用 Autofac
愛流浪的小風 - 使用Asp.Net MVC打造Web Api (4) - 套用DI Framework – - Autofac
In 91 - [Software Architecture]IoC and DI
大家好我是饅頭,希望大家喜歡我的文章
如果有錯誤的地方請不吝指教 ^_^