2012-02-13 19 views
2

我正在爲我的控制器創建自定義ActionResult,因爲我注意到許多重複代碼可以重複使用。它看起來是這樣的:當我構建對象時依賴注入

public ExtendedViewResult<T> : ActionResult 
{ 
     protected T Model { get; set; } 
     protected IModelExtender<T> Extender { get; set; } 

     public ExtendedActionResult(T model, IModelExtender<T> extender) 
     { 
      this.Model = model; 
      this.Extender = extender; 
     } 
} 

public class BaseController : Controller 
{ 
    public ExtendedViewResult<T> ExtendedView<T>(T model) 
    { 
     // I need to create the result here, but how? 
     var result = new ExtendedViewResult<T>(model, ???????); 

     return result; 
    } 
} 

我遇到的問題是,我不知道如何構建我的ExtendedViewResult對象。由於界面是通用的,我想使用依賴注入來獲得適當的對象,但我不知道如何做,因爲我自己構造對象。

我使用Ninject和Ninject.MVC3和默認的NuGet包我創建了一個引導程序類,當我訪問Bootstrapper.Kernel財產,我得到以下警告:

Ninject.Web.Mvc.Bootstrapper.Kernel is obsolete. Do not use Ninject as Service Locator.

如果我我不應該直接訪問內核,那麼我怎樣才能更改我的代碼,以便我可以獲得適當的具體類?

編輯
這裏是ninject引導程序代碼。我添加的唯一方法是GetInstance()

public static class NinjectMVC3 
{ 
    private static readonly Bootstrapper bootstrapper = new Bootstrapper(); 

    /// <summary> 
    /// Starts the application 
    /// </summary> 
    public static void Start() 
    { 
     DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule)); 
     DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule)); 
     bootstrapper.Initialize(CreateKernel); 
    } 

    /// <summary> 
    /// Stops the application. 
    /// </summary> 
    public static void Stop() 
    { 
     bootstrapper.ShutDown(); 
    } 

    // I ADDED THIS CODE, EVERYTHING ELSE IS AUTO-GENERATED 
    // BY THE NUGET PACKAGE 
    public static T GetInstance<T>() 
    { 
     return bootstrapper.Kernel.Get<T>(); 
    } 

    /// <summary> 
    /// Creates the kernel that will manage your application. 
    /// </summary> 
    /// <returns>The created kernel.</returns> 
    private static IKernel CreateKernel() 
    { 
     var kernel = new StandardKernel(); 
     RegisterServices(kernel); 
     return kernel; 
    } 

    /// <summary> 
    /// Load your modules or register your services here! 
    /// </summary> 
    /// <param name="kernel">The kernel.</param> 
    private static void RegisterServices(IKernel kernel) 
    { 
    }   
} 

回答

1

對不起,這將在實際的代碼幹 - 我沒有使用ninject很多,但其他的DI容器有這個解決方案,我相信ninject也會有這個構造。

問題是您正在構建對象本身。當您真正使用DI容器和IoC後,任何時候您都會看到關鍵字new應該是紅旗 - 並且將該容器用作服務定位器是黃色的。

那麼,我們如何擺脫'新',因爲你需要一個新的對象?答案是讓您的BaseController依賴可創建ExtendedViewResult的工廠。在Autofac(我選擇的容器)中,這將會像注入Func<ExtendedViewResult>一樣簡單。如果Ninject不一樣,我會感到驚訝。實際上,看起來像是這樣 - this ninject wiki page指向此blog post on Ninject.Extensions.Factory

因此,這意味着你的控制器代碼可能看起來是這樣的:

public class ConcreteController : BaseController 
{ 
    private Func<Foo,ExtendedViewResult<Foo>> _factory; 
    public BaseController(Func<Foo,ExtendedViewResult<Foo>> factory) 
    { 
     _factory = factory; 
    } 

    public ExtendedViewResult<Foo> Method(Foo model) 
    {    
     var result = _factory(model);  
     return result; 
    } 
} 

如果你真的想有一個通用的方法就在你的基類的創建,那麼你可能需要去明確從上面鏈接的博客文章的工廠界面路線。有了這個樣式代碼,在大多數情況下你不需要它,你的控制器顯式聲明他們需要的依賴關係。

+0

傳遞給具體控制器的問題是我可能有10種不同的動作方法,它們都有不同的模型。爲了做到這一點,我需要將10個不同的Func依賴項傳遞給我的控制器,這似乎不是最好的選擇。 – Dismissile 2012-02-13 17:16:57

+0

@Dmissmissile在這種情況下,我會推薦自己創建一個工廠。我不認爲ninject可以基於一個開放的泛型自動創建工廠,而構造函數參數只會讓它更難。如果你確實發現它可以,請更新你的問題,編輯這個答案,或者回答你自己的問題 - 我很樂意看到結果。我選擇的容器是AutoFac,我認爲這需要一些註冊源來實現。 – 2012-02-13 17:30:53

+0

@關於你自己的工廠,請記住,你可以依賴IResolutionRoot並調用。獲取。在簡單情況下,您可以簡單地在您的BaseController中依賴IResolutionRoot。這幾乎是使用ServiceLocator,但是您要求定位器作爲依賴項而不是自己找到它。 – 2012-02-13 17:34:38