寫在前面
關于Unity的使用可以參照《Unity依賴注入使用詳解》,依賴注入的概念參照《小菜學習設計模式(五)—控制反轉(zhuǎn)(Ioc)》。
在MVC中,控制器依賴于模型對數(shù)據(jù)進行處理,也可以說執(zhí)行業(yè)務邏輯。我們可以使用依賴注入(DI)在控制層分離模型層,這邊要用到Repository模式,在領域驅(qū)動設計(DDD)中,Repository翻譯為倉儲,顧名思義,就是儲存東西的倉庫,可以理解為一種用來封裝存儲,讀取和查找行為的機制,它模擬了一個對象集合。使用依賴注入(DI)就是對Repository進行管理,用于解決它與控制器之間耦合度問題,下面我們一步一步做一個簡單示例。
安裝Unity
首先我們需要新建一個UnityMVCDemo項目(ASP.NET MVC4.0),選擇工具-庫程序包管理器-程序包管理控制臺,輸入“Install-Package Unity.Mvc4”命令,VS2010可能需要先安裝NuGet。

或者通過工具-庫程序包管理器-管理解決方案的 NuGet 程序包,通過聯(lián)機搜索“Unity.Mvc4”進行安裝。

在安裝過程中可能會遇到下面這樣錯誤:

根據(jù)異常信息,可以肯定是項目的.net framework版本無法安裝Unity,這種安裝VS會自動搜索Unity最新版本,但是最新版本往往有. net framework版本要求,不知道有沒有指定Unity版本安裝,可以看到我們安裝的是Unity3.0版本,修改一下項目. net framework的版本為4.5,重新安裝就可以了。
安裝Unity成功后,我們發(fā)現(xiàn)項目中多了“Microsoft.Practices.Unity”和“Microsoft.Practices.Unity.Configuration”兩個引用,還有一個Bootstrapper類文件,Bootstrapper翻譯為引導程序,也就是Ioc容器。
1 public static class Bootstrapper
2 {
3 public static IUnityContainer Initialise()
4 {
5 var container = BuildUnityContainer();
6
7 DependencyResolver.SetResolver(new UnityDependencyResolver(container));
8
9 return container;
10 }
11
12 private static IUnityContainer BuildUnityContainer()
13 {
14 var container = new UnityContainer();
15
16 // register all your components with the container here
17 // it is NOT necessary to register your controllers
18
19 // e.g. container.RegisterType<ITestService, TestService>();
20 RegisterTypes(container);
21
22 return container;
23 }
24
25 public static void RegisterTypes(IUnityContainer container)
26 {
27
28 }
29 }
添加服務層
首先我們添加一個Article實體類:
1 /// <summary>
2 /// Article實體類
3 /// </summary>
4 public class Article
5 {
6 public int Id { get; set; }
7 public string Title { get; set; }
8 public string Author { get; set; }
9 public string Content { get; set; }
10 public DateTime CreateTime { get; set; }
11 }
一般Repository都有一些相似的操作,比如增刪改查,我們可以把它抽象為IArticleRepository接口,這樣控制器依賴于抽象接口,而不依賴于具體實現(xiàn)Repository類,符合依賴倒置原則,我們才可以使用Unity進行依賴注入。
1 /// <summary>
2 /// IArticleRepository接口
3 /// </summary>
4 public interface IArticleRepository
5 {
6 IEnumerable<Article> GetAll();
7 Article Get(int id);
8 Article Add(Article item);
9 bool Update(Article item);
10 bool Delete(int id);
11 }
創(chuàng)建ArticleRepository,依賴于IArticleRepository接口,實現(xiàn)基本操作。

1 public class ArticleRepository : IArticleRepository
2 {
3 private List<Article> Articles = new List<Article>();
4
5 public ArticleRepository()
6 {
7 //添加演示數(shù)據(jù)
8 Add(new Article { Id = 1, Title = "UnityMVCDemo1", Content = "UnityMVCDemo", Author = "xishuai", CreateTime = DateTime.Now });
9 Add(new Article { Id = 2, Title = "UnityMVCDemo2", Content = "UnityMVCDemo", Author = "xishuai", CreateTime = DateTime.Now });
10 Add(new Article { Id = 3, Title = "UnityMVCDemo2", Content = "UnityMVCDemo", Author = "xishuai", CreateTime = DateTime.Now });
11 }
12 /// <summary>
13 /// 獲取全部文章
14 /// </summary>
15 /// <returns></returns>
16 public IEnumerable GetAll()
17 {
18 return Articles;
19 }
20 /// <summary>
21 /// 通過ID獲取文章
22 /// </summary>
23 /// <param name="id"></param>
24 /// <returns></returns>
25 public Article Get(int id)
26 {
27 return Articles.Find(p => p.Id == id);
28 }
29 /// <summary>
30 /// 添加文章
31 /// </summary>
32 /// <param name="item"></param>
33 /// <returns></returns>
34 public Article Add(Article item)
35 {
36 if (item == null)
37 {
38 throw new ArgumentNullException("item");
39 }
40 Articles.Add(item);
41 return item;
42 }
43 /// <summary>
44 /// 更新文章
45 /// </summary>
46 /// <param name="item"></param>
47 /// <returns></returns>
48 public bool Update(Article item)
49 {
50 if (item == null)
51 {
52 throw new ArgumentNullException("item");
53 }
54
55 int index = Articles.FindIndex(p => p.Id == item.Id);
56 if (index == -1)
57 {
58 return false;
59 }
60 Articles.RemoveAt(index);
61 Articles.Add(item);
62 return true;
63 }
64 /// <summary>
65 /// 刪除文章
66 /// </summary>
67 /// <param name="id"></param>
68 /// <returns></returns>
69 public bool Delete(int id)
70 {
71 Articles.RemoveAll(p => p.Id == id);
72 return true;
73 }
74 }

IArticleRepository類型映射
上面工作做好后,我們需要在Bootstrapper中的BuildUnityContainer方法添加此類型映射。
1 private static IUnityContainer BuildUnityContainer()
2 {
3 var container = new UnityContainer();
4
5 // register all your components with the container here
6 // it is NOT necessary to register your controllers
7
8 container.RegisterType<IArticleRepository, ArticleRepository>();
9
10 // e.g. container.RegisterType<ITestService, TestService>();
11 RegisterTypes(container);
12
13 return container;
14 }
我們還可以在配置文件中添加類型映射,UnityContainer根據(jù)配置信息,自動注冊相關類型,這樣我們就只要改配置文件了,當然推薦是這種方法,配置文件:
1 <configSections>
2 <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
3 Microsoft.Practices.Unity.Configuration" />
4 </configSections>
5 <unity>
6 <containers>
7 <container name="defaultContainer">
8 <register type="UnityMVCDemo.Models.IArticleRepository, UnityMVCDemo" mapTo="UnityMVCDemo.Models.ArticleRepository, UnityMVCDemo"/>
9 </container>
10 </containers>
11 </unity>
注意configSections節(jié)點要放在configuration節(jié)點下的第一個節(jié)點,關于Unity的配置文件配置參照http://www.cnblogs.com/xishuai/p/3670292.html,加載配置文件代碼:
1 UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
2 configuration.Configure(container, "defaultContainer");
上面這段代碼替換掉上面使用的RegisterType方法。
服務注入到控制器
在ArticleController中我們使用是構(gòu)造器注入方式,當然還有屬性注入和方法注入,可以看到ArticleController依賴于抽象IArticleRepository接口,而并不是依賴于ArticleRepository具體實現(xiàn)類。
1 public class ArticleController : Controller
2 {
3 readonly IArticleRepository repository;
4 //構(gòu)造器注入
5 public ArticleController(IArticleRepository repository)
6 {
7 this.repository = repository;
8 }
9
10 public ActionResult Index()
11 {
12 var data = repository.GetAll();
13 return View(data);
14 }
15 }
Global.asax初始化
做完上面的工作后,我們需要在Global.asax中的Application_Start方法添加依賴注入初始化。
1 // Note: For instructions on enabling IIS6 or IIS7 classic mode,
2 // visit http://go.microsoft.com/?LinkId=9394801
3 public class MvcApplication : System.Web.HttpApplication
4 {
5 protected void Application_Start()
6 {
7 AreaRegistration.RegisterAllAreas();
8
9 WebApiConfig.Register(GlobalConfiguration.Configuration);
10 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
11 RouteConfig.RegisterRoutes(RouteTable.Routes);
12
13 Bootstrapper.Initialise();
14 }
15 }