January 27, 2013

ASP.NET MVC 4中使用StructureMap

筆者在IoC container的選擇上一直是使用StructureMap,其實也不是有什麼偏好,只是當時初入門Denpendency Injection這議題時,看的便是使用StructureMap。一般IoC container在設定上不外乎在Web.config、App.config或是IoC framework自己的設定檔裡設定相依,如
<?xml version="1.0" encoding="utf-8" ?>
<StructureMap MementoStyle="Attribute">
  <DefaultInstance
    PluginType="Wais.Service.IRegisterService,Wais.Service"
    PluggedType="Wais.Service.RegisterService,Wais.Service"
    Scope="Singleton" />
  <DefaultInstance
    PluginType="Wais.Domain.IUserAccountRepository,Wais.Domain"
    PluggedType="Wais.Infrastructure.Data.EF.UserAccountRepository,Wais.Infrastructure.Data.EF"
    Scope="Singleton" />
  <DefaultInstance
    PluginType="Wais.Infrastructure.IUnitOfWork,Wais.Infrastructure"
    PluggedType="Wais.Infrastructure.Data.EF.WaisEntities,Wais.Infrastructure.Data.EF"
    Scope="Singleton" />
</StructureMap>
或是直接將container的設定寫在Global.asax的Application_Start裡如
ObjectFactory.Initialize(x =>
            {
                x.For<IUnitOfWork>().Use<WaisEntities>();
                x.For<IUserAccountRepository>().Use<UserAccountRepository>();
                x.For<IForgotPasswordRepository>().Use<ForgotPasswordRepository>();
                x.For<IRegisterService>().Use<RegisterService>();
                x.For<IUserAccountService>().Use<UserAccountService>();
                x.For<IForgotPasswordService>().Use<ForgotPasswordService>();
            });
將container設定寫在程式裡好處是有intellisense的支援,不過就必須把相依的實作也加入專案中,如此Web Application專案也會相依Data Access Layer或是Repository的實作專案,但一般我們會避免這種情況發生以免開發人員誤用。理想的狀況應該只相依介面專案,如Service Layer的介面專案。在這情況下使用設定檔方式設定IoC container即可免除上述困擾,但壞處就是要謹慎一點,有時打錯個字找半天都找不到問題在哪裡,實作類別更名時也得記得回來修改。

還有一種做法是將IoC container的設定全放在另一個專案中,例如筆者有個函式庫專案名稱叫Wais.Web.DependencyInjection,裡面載入Service Layer及Repoistory所用到的介面及實作。而筆者的Web Application專案叫Wais.Web則加入Wais.Web.DependencyInjection為參考,如此只要在Application_Start中呼叫Wais.Web.DependencyInjection專案中某支方法便可初始化IoC container。

不過在ASP.NET MVC 4中如果要使用StructureMap在設定上有點小麻煩,為了要能初始化Controller,還需額外實作IDependencyResolver介面,在此我們不多談,直接使用nuget上所提供的StructureMap.MVC4。安裝完後會在專案中建立App_StartDependencyResolution資料夾。App_Start下會有一個StructuremapMvc類別,而DependencyResolution下會有IoC、StructureMapDependencyResolver及StructureMapDependencyScope三個類別。我們只要到IoC這個類別中設定dependency即可,完全不需要在Global.asax做任何程式上的修改,StructureMap.MVC4即會透過WebActivator(StructuremapMvc這支類別)於應用程式啟動時自動載入。
using StructureMap;
using Wais.Domain;
using Wais.Infrastructure;
using Wais.Infrastructure.Data.EF;
using Wais.Service;

namespace Wais.Web.DependencyInjection.DependencyResolution
{
    public static class IoC
    {
        public static IContainer Initialize()
        {
            ObjectFactory.Initialize(x =>
                        {
                            x.For<IUnitOfWork>().Use<WaisEntities>();
                            x.For<IUserAccountRepository>().Use<UserAccountRepository>();
                            x.For<IForgotPasswordRepository>().Use<ForgotPasswordRepository>();
                            x.For<IRegisterService>().Use<RegisterService>();
                            x.For<IUserAccountService>().Use<UserAccountService>();
                            x.For<IForgotPasswordService>().Use<ForgotPasswordService>();
                        });
            return ObjectFactory.Container;
        }
    }
}
而在Controller或是Service做Constructor Injection時,StructureMap就會自動對應到相依的實作類別了,相當方便。
private IRegisterService _registerService;
private IUserAccountService _userAccountService;

public HomeController(IRegisterService registerService, IUserAccountService userAccountService)
{
    this._registerService = registerService;
    this._userAccountService = userAccountService;
}
private IUserAccountRepository _userAccountRepository;

public RegisterService(IUserAccountRepository userAccountRepository)
{
    if (userAccountRepository == null)
    {
        throw new ArgumentNullException("userAccountRepository");
    }

    this._userAccountRepository = userAccountRepository;
}
相關文章

ASP.NET MVC 4中使用Bootstrap

Bootstrap是Twitter出的前端框架,在ASP.MVC 4中如果要使用Bootstrap,可以透過nuget來掛載它。在nuget官網可以發現有兩種方式可以載入Bootstrap,只要輸入指令Install-Package Twitter.BootstrapInstall-Package Twitter.Bootstrap.MVC

兩者的差別在於前者僅載入Bootstrap會用到的assets(scripts, css和images),安裝後我們仍須手動註冊Bootstrap的bundles在BundleConfig類別的RegisterBundles方法中,如
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( "~/Scripts/bootstrap*"));
bundles.Add(new StyleBundle("~/Content/bootstrap")
       .Include( "~/Content/bootstrap.css", "~/Content/bootstrap-responsive.css"));
而後者適用於MVC 4專案中,安裝後會在App_Start資料夾註冊上述的bundles並透過WebActivator於應用程式啟動時自動加載bundles,所以我們無須在BundleConfig類別的RegisterBundles方法中手動加入bundles

參考
http://nuget.org/packages/twitter.bootstrap
http://nuget.org/packages/Twitter.Bootstrap.MVC/
http://nuget.org/packages/WebActivator
http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification

January 13, 2013

與Jenkins共舞 - 安裝與基本設定(2)

接續前篇文章,筆者已經將Jenkins安裝完成並且可以透過http://localhost來瀏覽Jenkins的管理介面,接下來本篇文章將介紹Jenkins的基本設定。Jenkins的設定頁面可以透過管理介面首頁->Manage Jenkins->Configure System進入或是直接瀏覽http://localhost/configure


以下列出幾個筆者有使用過的設定做說明
  • Home directory: Jenkins的安裝目錄,如C:\Program Files (x86)\Jenkins
  • Workspace Root Directory(點選Advanced按鈕後出現): 原始碼存放路徑,用來儲存Jenkins從版本控制軟體(如Subversion)取下來的原始碼,作為之後編譯程式碼用。它的預設值為${ITEM_ROOTDIR}/workspace,意思是Jenkins會將原始碼放在某個Build Job下的workspace資料夾。例如建立了一個Build Job名為Build001,Jenkins會在home directory下的jobs資料夾中建立一個名為Build001的資料夾,而在Build001中會有一個workspace資料夾用來存放編譯用的原始碼。也就是說,如果你有3個Build Jobs,那就會有三份原始碼被下載放到不同的位置,當然你也可以更改預設值把它設定成固定的路徑如此多個Build Jobs便可共用同一份原始碼

  • Build Record Root Directory(點選Advanced按鈕後出現): 建置結果存放路徑。它的預設值為${ITEM_ROOTDIR}/builds,意思是Jenkins會將編譯原始碼後的結果放在某個Build Job下的builds資料夾。例如建立了一個Build Job名為Build001,Jenkins會在home directory下的jobs資料夾中建立一個名為Build001的資料夾,而在Build001中會有一個builds資料夾用來存放建置原始碼後的結果,建置的結果會以日期為命名方式做儲存如

  • System Message: 管理介面首頁的顯示訊息,可使用HTML,如



  • System Admin e-mail address: 系統管理者的Email及顯示名稱,如Pete Chen <pete.chen@outlook.com>。當Job建置失敗時,Jenkins可以寄送Email通知相關人員,此時Email的寄件者就會以這裡的設定做為顯示
  • Subversion Workspace Version: Subversion的版本,預設為1.4。如果要支援到1.7,則需將Jenkins內建的Subversion Plugin升級到最新的版本。可透過管理介面首頁-> Manage Jenkins-> Manage Plugins-> Updates找到Subversion Plugin,安裝[註1]後重新啟動[註2]Jenkins即可。

  • SMTP server: SMTP伺服器位址,如192.168.0.92。當Job建置失敗時,Jenkins可以透過此SMTP伺服器寄送Email通知相關人員。如需對寄送通訊埠、認證、SSL支援功能做進階設定,可按下Advanced按鈕。Jenkins也提供了一個貼心的功能,在做完設定後,可以直接測試是否能正常使用所設定的SMTP伺服器進行Email寄送,只要核取Test configuration by sending test e-mail,輸入收件者Email並按下Test configuration按鈕即可

備註
  1. 筆者在升級Subversion Plugin時出現過plugin安裝失敗的訊息,不過在重新啟動Jenkins後發現這個plugin實際上是有安裝成功,Subversion的版本也可以支援到1.7
  2. 如要重新啟動Jenkins,可透過Windows服務管理介面,或是使用RESTful的方式連結至http://localhost/restart重啟Jenkins

January 12, 2013

與Jenkins共舞 - 安裝與基本設定(1)

公司目前用的CI Server是CruiseControl.NET,會想試試Jenkins主要是因為它提供了Web管理介面,而不像CuriseControl.NET主要是透過修改XML來更新設定檔,相比較之下Jenkins算是親和許多。在寫這篇文章時,Jenkins的版本為1.498

筆者的慣用系統是Windows,目前是將Jenkins安裝在Windows Server 2008 R2 SP1 64-bit的VM上,Jenkins的安裝目錄在C:\Program Files (x86)\Jenkins。Jenkins的安裝很簡單,到官網下載其壓縮檔,解壓縮後會有兩個檔案,jenkins-1.498.msi及setup.exe。執行setup.exe即可進行安裝,安裝過程也很簡單,這裡不詳述。安裝完畢後,瀏覽器會自動開啟並連結至http://localhost:8080,這是Jenkins預設的管理介面位址,同時也可以在Windows服務看到Jenkins。



Jenkins提供內建的web server,預設通訊埠為8080,如果需要變更預設值,可以修改安裝目錄下的jenkins.xml,將--httpPort=8080改成新的通訊埠。如要將通訊埠改成80,需先檢查IIS或是其它服務(如Skype)是否已佔用80,修改完後存檔重新啟動Jenkins的Windows服務即可。


January 8, 2013

January 5, 2013

AnkhSVN not showing on Visual Studio

AnkhSVN is a Visual Studio plug-in which can let you do subversion commands directly thru GUI in Visual Studio. I've been using it since Visual Studio 2005. It's a great tool saving me much time on  version control thing. But today after installing it on Visual Studio 2012, I found it does not appear in the IDE even I restarted the IDE and OS. Follow the steps below to get it appeared in your IDE if you happen to have the same problem.
  1. Go to Tools-> Options in your VS
  2. Expand Source Control
  3. Select Plug-in Selection
  4. Change your current source control plug-in to AnkhSVN - Subversion Support for Visual Studio
  5. Click OK and restart your Visual Studio