2011-07-20 132 views
3

我有以下類/接口:依賴注入/構造器注入幫助

public interface IProjectRepository 
{ 
    IQueryably<Project> GetProjects(); 
} 

// Depends on my EF Context 
public ProjectRepository : IProjectRepository 
{ 
    private MyDbEntities context; 

    public ProjectRepository(MyDbEntities context) 
    { 
     this.context = context; 
    } 

    public IQueryable<Project> GetProjects() 
    { 
     return context.Projects; 
    } 
} 

我的控制器:

// Depends on IProjectRepository 
public class ProjectsController : Controller 
{ 
    private IProjectRepository projectRepository; 

    public ProjectsController(IProjectRepository projectRepository) 
    { 
     this.projectRepository = projectRepository; 
    } 

    public ActionResult Index() 
    { 
     return View(projectRepository.GetProjects()); 
    } 
} 

我需要使之穿過ProjectRepository爲建立我的依賴注入我的控制器它需要將我的實體框架上下文傳遞到項目存儲庫。我需要將實體上下文作爲HTTP請求範圍。

我不知道在哪裏我應該把所有的映射代碼,使依賴項注入工作。我也不明白MVC如何在沒有默認構造函數的情況下工作。

有人能幫我把所有的東西放在一起嗎?我正在使用StructureMap,但我可以輕鬆切換到其他的東西,因爲我不知道自己在做什麼。

+0

您運行的是哪個版本的MVC? – Charlino

+0

ASP.net MVC 3。 。 – Dismissile

+0

如果您使用的是ASP。NET MVC 3,你應該真正利用它的內置'DependencyResolver'。查看我的答案獲取更多信息。 – Charlino

回答

-3

當使用StructureMap我通常會有這樣的事情在我的控制器:

private static IProjectRepository GetProjectRepository() 
{ 
    var retVal = ObjectFactory.TryGetInstance<IProjectRepository>() 
       ?? new ProjectRepository(); 
    return retVal; 
} 

如果TryGetInstance返回null(因爲沒有爲那個類型設置),則默認爲您指定的具體類型。

現在你有一個引導程序的地方是這樣的:

public static class StructureMapBootStrapper 
{ 
    public static void InitializeStructureMap() 
    { 
     ObjectFactory.Initialize(x => 
     { 
      x.For<IProjectRepository>().Use<ProjectRepository>(); 
     } 
    } 
} 

現在你罵這個引導程序在你的Global.asax Application_Start事件:

protected void Application_Start() 
    { 
     StructureMapBootStrapper.InitializeStructureMap(); 
    } 

現在,在一個測試項目,當你想注入一個模擬存儲庫,你可以這樣做:

[TestMethod] 
    public void SomeControllerTest() 
    { 
     StructureMap.ObjectFactory.Inject(
      typeof(IProjectRepository), 
      new MockProjectRepository()); 

     // ... do some test of your controller with the mock 
    } 
+0

謝謝。這是我正在尋找的。如何將它們粘合在一起。現在我在ProjectRepository中遇到了問題。我如何設置它以獲取我的實體上下文HTTP請求作用域的默認類型? – Dismissile

+0

根據HTTP請求確定您的上下文範圍: http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in​​-n-layered-ASP-NET-applications.aspx 使用延遲加載方案的建議也很好。 –

+3

-1對不起,但是這絕對不是用ASP.NET MVC 3進行依賴注入的正確方法。 – Charlino

-1

所有的工作都差不多。從歷史上看,所有人都擁有二流注射器(設置一個隨後被填充的屬性),但現在大多數都有構造注射器。在結構圖中,最簡單的方法是使用屬性:[StructureMap.DefaultConstructor]。

一旦你添加了屬性,你放置在你的「地圖」中的對象應該注入而不需要額外的工作。如果你不能使用屬性,請考慮使用setter。

有結構上的地圖站點中的文件: http://structuremap.net/structuremap/ConstructorAndSetterInjection.htm

+0

錯誤:沒有爲此對象定義的無參數構造函數。 – Dismissile

+0

我仍然不知道應該在哪裏放置配置/設置代碼。 – Dismissile

0

如果您在使用StructureMap設置,here是,你可能需要設置的教程。

其他一些依賴注入框架附帶自定義控制器工廠,它們將爲您執行此操作。 Ninject(開放源代碼依賴注入),例如有一個可用於包含此行爲的擴展。例如,請參閱here。並here到擴展名。

你也可以使用Unity IOC,這是另一個流行的依賴注入框架,據我所知,你將不得不創建一個自定義控制器工廠(如結構圖)來實現這種行爲。一個例子見here

你也可以研究所有其他的依賴注入框架,看看你可以得到哪些支持。

編輯: 我希望我解釋正確,但這裏是一些背景信息。

MVC使用一個控制器工廠,負責在發出請求時實例化所需的各個控制器。默認情況下,它將通過調用其無參數構造函數來初始化控制器。

要創建構造函數參數注入的基礎結構,您需要創建一個可以解析構造函數參數的自定義工廠。這就是依賴注入容器的來源:基本上,DI容器(如果配置正確)知道如何解決這些依賴關係,並且您的自定義工廠將利用它來請求已註冊的依賴關係並將其傳遞給控制器​​構造函數。

4

如果你正在使用MVC 3,要正確地做事情,你應該使用內置的依賴分辨率位。我強烈建議你閱讀series of blog posts from Brad Wilson(ASP.NET MVC團隊的成員)。

就StructureMap特定實現而言,我發現以下博客文章很有幫助。

StructureMap and ASP.NET MVC 3 – Getting Started
StructureMap, Model Binders and Dependency Injection in ASP.NET MVC 3
StructureMap, Action Filters and Dependency Injection in ASP.NET MVC 3
StructureMap, Global Action Filters and Dependency Injection in ASP.NET MVC 3

總之,這裏的一些代碼。首先,我建議你安裝StructureMap-MVC3 NuGet package

我不記得它以文件的方式創建了什麼,但這裏是基本涉及的內容。

/App_Start/StructuremapMvc.cs - 此掛鉤插入的Application_Start並建立您的容器(SmIoC.Initialize()),然後設置MVC 3 DependencyResolver到您的SmDependencyResolver

using System.Web.Mvc; 
using YourAppNamespace.Website.IoC; 
using StructureMap; 

[assembly: WebActivator.PreApplicationStartMethod(typeof(YourAppNamespace.App_Start.StructuremapMvc), "Start")] 

namespace YourAppNamespace.Website.App_Start { 
    public static class StructuremapMvc { 
     public static void Start() { 
      var container = SmIoC.Initialize(); 
      DependencyResolver.SetResolver(new SmDependencyResolver(container)); 
     } 
    } 
} 

/IOC/SmDependencyResolver。 cs - 這是您的MVC 3 IDependencyResolver實現。它在上面的App_Start代碼中使用。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.Mvc; 
using StructureMap; 

namespace YourAppNamespace.Website.IoC 
{ 
    public class SmDependencyResolver : IDependencyResolver 
    { 
     private readonly IContainer _container; 

     public SmDependencyResolver(IContainer container) 
     { 
      _container = container; 
     } 

     public object GetService(Type serviceType) 
     { 
      if (serviceType == null) 
      { 
       return null; 
      } 

      try 
      { 
       return _container.GetInstance(serviceType); 
      } 
      catch 
      { 
       return null; 
      } 
     } 

     public IEnumerable<object> GetServices(Type serviceType) 
     { 
      return _container.GetAllInstances(serviceType).Cast<object>(); ; 
     } 
    } 
} 

/IoC/SmIoC.cs - 這就是你設置你的容器......在App_Start代碼也可使用。

namespace YourAppNamespace.Website.IoC 
{ 
    public static class SmIoC 
    { 
     public static IContainer Initialize() 
     { 
      ObjectFactory.Initialize(x => 
         { 
          x.For<IProjectRepository>().Use<ProjectRepository>(); 
          //etc... 
         }); 

      return ObjectFactory.Container; 
     } 
    } 
} 

現在一切都被迷住了......(我想;-)但是你還有最後一件事情要做。在你的Global.asax裏面,我們需要確保你處理所有的HttpContext作用域。

protected void Application_EndRequest() 
{ 
    ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects(); 
} 

所以你應該能夠通過構造器注入實現依賴注入,這是正確的方式去做事情。

+0

我注意到的一件事是如果我的IIS Express端口已經運行,那麼容器不會中斷。 /App_Start/StructuremapMvc.cs是我把第一個中斷點,並感到驚訝,它沒有被擊中......所以只是一個觀察。 –