<?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_Start及DependencyResolution資料夾。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; }相關文章