2013年4月27日 星期六

ASP.NET MVC 4 使用 Unity bootstrapper for ASP.NET MVC

上上一篇分層架構系列文章「ASP.NET MVC 專案分層架構 Part.6 - DI/IoC 使用 Unity.MVC」 介紹了如何在一個 ASP.NET MVC 4 的分層架構專案中使用 Unity.MVC4 實作 DI/IoC,不管是 Unity.MVC3 or Unity.MVC4 都是使用了 Enterprise Library Unity Application Block 2.1 版 ( Unity.MVC3 為 2.1.505.0, Unity.MVC4 為 2.1.505.2 ),然而就在 2013-04-26 的時候 Enterprise Library 6.0 正式 Release 了,而 Unity Application Block 也進展到 3.0 版。

此次 EntLib 6.0 增加了兩個 Application Block,而既有的 Application Block 也有很多的更新功能,而其中一點就是 Unity Application Block 加強了對 ASP.NET MVC 與 ASP.NET Web API 的技術整合,另外也推出了自家官方的 ASP.NET MVC, ASP.NET Web API 整合組件,在 NuGet 就可以取得、安裝,這一篇就用之前分層架構的程式來介紹如何在 ASP.NET MVC 4 網站裡使用 Unity bootstrapper for ASP.NET MVC

 


之前我們所使用的 Unity.MVC4,這是給 ASP.NET MVC 4 網站所使用的,

image

而 ASP.NET MVC 3 網站則是可以用 Unity.MVC3,

image

以上兩個 Unity.MVC 都是使用 Unity Application Block 2.1,雖然不是 EntLib 官方所推出,但還是相當容易使用。

 

Unity Application Block 3

http://msdn.microsoft.com/en-us/library/dn170416.aspx

image

The new Unity Application Block includes many improvements:
1. Registration by convention.
2. Support for NetCore (Windows Store apps).
3. Resolving objects of type Lazy<T>.
4. The Unity assembly is now Security Transparent.
5. Support for ASP.NET MVC and ASP.NET Web API.

我建議各位可以先下載文件檔,從文件裡了解如何使用 Unity 3,文件的下載位置如下:

https://entlib.codeplex.com/releases/view/64243

image

文件內容算是相當完整,不單只有 ASP.NET MVC(這只佔其中一部分而已),其他的包含有 ASP.NET Web API, WCF, ASP.NET WebForm 等其他技術的整合使用說明,另外對 EntLib 其他 Application Block 有興趣的朋友也可以下載另外的兩個文件檔。

 

Unity bootstrapper for ASP.NET MVC

以往在 ASP.NET MVC 網站裡想要使用 Unity 來實作 DI/IoC,除了透過 Unity.MVC 的安裝來使用之外,就是要自己手動的方式來完成,而現在 EntLib Unity 也推出了官方版的整合組件「Unity bootstapper for ASP.NET MVC」,在 Visual Studio 裡透過 NuGet 就可以輕鬆安裝。

P.S.
直接在 NuGet 搜尋列裡輸入「Unity bootstrapper for ASP.NET MVC」,可能要在查詢結果裡案好幾次下一頁才能看到,這邊告訴各位可以在關鍵字的前後加上雙引號,這樣就可以直接尋找有完全符合的結果,就跟我們在 Google 裡要搜尋含有限定字詞的操作一樣。

image

不過這邊要特別提醒,Enterprise Library 6.0 僅能安裝在使用 .NET 4.5 的專案裡,而 Unity bootstrapper for ASP.NET MVC 更限定只能在 ASP.NET MVC 4 以上的版本才能使用,所以要特別注意。

安裝完成之後,組件參考會多增加三個項目,

image

另外在 ~/App_Start 目錄下增加了兩個檔案,分別是:UnityConfig.cs, UnityMvcActivator.cs

image

 

首先來看看 UnityConfig.cs 的內容,

using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
 
namespace Mvc_Repository.Web.App_Start
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });
 
        /// <summary>
        /// Gets the configured Unity container.
        /// </summary>
        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion
 
        /// <summary>Registers the type mappings with the Unity container.</summary>
        /// <param name="container">The unity container to configure.</param>
        /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
        /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
        public static void RegisterTypes(IUnityContainer container)
        {
            // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
            // container.LoadConfiguration();
 
            // TODO: Register your types here
            // container.RegisterType<IProductRepository, ProductRepository>();
        }
    }
}

上面用 region 包起來的部分,基本上是很少會去更動到,而下面的靜態方法 RegisterTypes(),這就是我們要註冊型別的地方,這邊就輸入我們要註冊的類別內容,而至於另一個檔案 UnityMvcActivator.cs,這個檔案要修改的機會也不多,但如果像在系統裡對於使用 Unity 註冊的類別在一次的 HTTP Request 範圍中做 Singleton 管理的話,那麼就會需要動到這個程式了(UnityMvcActivator.cs),在我這次的示範並不會對此檔案做任何變動,

using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;
 
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Mvc_Repository.Web.UnityWebActivator), "Start")]
 
namespace Mvc_Repository.Web
{
    /// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
    public static class UnityWebActivator
    {
        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start() 
        {
            var container = UnityConfig.GetConfiguredContainer();
 
            FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
            FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
 
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
 
            // TODO: Uncomment if you want to use PerRequestLifetimeManager
            // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
        }
    }
}

基本上這樣就可以了,基本的動作就是只需要在 UnityConfig.cs 的 RegisterTypes() 靜態方法內加入要註冊的類別就完成,其餘什麼修改 Global.asax 等動作都不用了,這是因為在 UnityMvcActivator.cs 裡面使用了 WebActivator,對於 WebActivator 想要有詳細的了解與說明,黑大(黑暗執行緒)的部落格裡就有一篇文章在做介紹,

WebActivator - 不修改Global.asa也能加入Application_Start - 黑暗執行緒

基本上完成上面的步驟之後就完成了。

 

小插曲

完成上面的步驟之後,我就在 VS2012 裡按下 F5 執行網站,但卻看到了以下的錯誤,

image

問題就在下面的地方,

image

在 GenericRepository.cs 裡有兩個建構式是有傳入參數的,雖然說兩個傳入參數的型別不同,但是對於 Unity 來說,這兩個沒辦法去分別呀,因為建構式的傳入參數個數都一樣,在 Unity 去做型別註冊時就根本不知道該用哪一個建構式,所以先刪除另一個以 ObjectContext 為輸入參數的建構式,

image

但是做了上面的修改後去執行網站卻會發現以下的錯誤,

image

於是我決定把 GenericRepository 的基本建構式給移除,

image

再來的問題就是剩下的建構式,怎麼傳給它 DbContext 參數呢?

要解決這個步驟就是要到 UnityConfig.cs 的 RegisterTypes() 方法內,因為現在 Repository 與 Service 類別的建立都是交給 Unity 來處理,現在 GenericRepository 的建構式只剩下一個,而且要傳入一個 DbContext,所以在 UnityConfig.cs 的 RegisterTypes() 方法內處理 IRepository<T> 註冊的地方,讓類別建立實例的時候也傳入建構式所需要傳入的參數,基本上就是以下的內容,

image

在註冊 IRepository<T> 類別的時候,可以使用 InjectionConstructor 來傳入建立類別實例時所需要的建構式參數值,這樣就可以解決問題了。

image

 

專案使用 .NET Framework 4.5 以及 ASP.NET MVC 4.5 的朋友,不妨使用 Unity 來做為 DI/IoC 的解決方案,並且搭配 Unity bootstrapper for ASP.NET MVC 來使用,也是不錯的選擇。

 

相關連結:

Enterprise Library - MSDN
http://msdn.microsoft.com/library/cc467894.aspx

Enterprise Library 6 - April 2013
http://msdn.microsoft.com/zh-TW/library/dn169621.aspx

Microsoft Enterprise Library 6 - Microsoft Download Center
http://www.microsoft.com/en-us/download/details.aspx?id=38789

Enterprise Library 6 - April Document Download - patterns & practices – Enterprise Library
https://entlib.codeplex.com/releases/view/64243

Unity Container - MSDN
http://msdn.microsoft.com/en-us/library/dd203101.aspx

Unity 3 – April 2013
http://msdn.microsoft.com/en-us/library/dn170416.aspx

Microsoft Unity 3 - Microsoft Download Center
http://www.microsoft.com/en-us/download/details.aspx?id=38788

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。