1

我一直在使用Ninject,但僅適用於簡單的DI。我有一個稍微更復雜的場景,我想迎合。MVC3&Ninject/Unity:注入分層服務容器

我使用控制器注入的Ninject.Web.MVC插件,強制在我的基礎控制器上傳遞給所有的繼承控制器。這是我的基本模式:

using System; 
using System.Web; 
using System.Web.Mvc; 

using Business; 

using Microsoft.Web.Infrastructure.DynamicModuleHelper; 

using Ninject; 
using Ninject.Web.Common; 

namespace Web { 

    #region Controller 

    public class MyController : MyBaseController { 
     public MyController(IMyService1 myService1, IMyService2 myService2) 
      : base(myService1, myService2) { 
     } 
     public ActionResult MyAction() { 
      MyServiceProp1.DoSomething(); 
      MyServiceProp2.DoSomethingElse(); 
      return View(); 
     } 
    } 

    public class MyBaseController : Controller { 
     protected IMyService1 MyServiceProp1 { get; set; } 
     protected IMyService2 MyServiceProp2 { get; set; } 

     public MyBaseController(IMyService1 myService1, IMyService2 myService2) { 
      MyServiceProp1 = myService1; 
      MyServiceProp2 = myService2; 
     } 
    } 

    #endregion 
} 

namespace Business { 

    #region Services 

    public interface IMyService1 { 
     void DoSomething(); 
    } 

    public interface IMyService2 { 
     void DoSomethingElse(); 
    } 

    public class MyService1 : IMyService1 { 
     public void DoSomething() { 
     } 
    } 

    public class MyService2 : IMyService2 { 
     public void DoSomethingElse() { 
     } 
    } 

    #endregion 
} 

#region Ninject stuff 

namespace Web.App_Start { 
    public static class NinjectWebCommon { 
     private static readonly Bootstrapper bootstrapper = new Bootstrapper(); 

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

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

     /// <summary> 
     /// Creates a kernel that will manage the application. 
     /// </summary> 
     /// <returns>The created kernel.</returns> 
     private static IKernel CreateKernel() { 
      var kernel = new StandardKernel(); 
      kernel.Bind<Func<IKernel>>().ToMethod(ctx =>() => new Bootstrapper().Kernel); 
      kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); 

      RegisterServices(kernel); 
      return kernel; 
     } 

     /// <summary> 
     /// Loads modules and services 
     /// </summary> 
     /// <param name="kernel">The kernel.</param> 
     private static void RegisterServices(IKernel kernel) { 
      kernel.Bind<IMyService1>().To<MyService1>(); 
      kernel.Bind<IMyService2>().To<MyService2>(); 
     } 
    } 
} 

#endregion 

正如你所看到的,我有多個服務。如果我想添加MyService3,我將不得不修改每個實現基本控制器的單個控制器。雖然這不是一個巨大的工作,但它會是當項目更大時...

我想要做的是實現某種服務容器,我將注入到基本控制器,因此,所有的執行控制器(及任何後續類)的:

namespace Web { 

    #region Controller 

    public class MyController : MyBaseController { 
     public MyController(IMyServiceContainer container) 
      : base(container) { 
     } 
     public ActionResult MyAction() { 
      MyServiceProp1.DoSomething(); 
      MyServiceProp2.DoSomethingElse(); 
      return View(); 
     } 
    } 

    public interface IMyServiceContainer { 
     IMyService1 MyServiceProp1 { get; set; } 
     IMyService2 MyServiceProp2 { get; set; } 
    } 

    public class MyBaseController : Controller, IMyServiceContainer { 
     public MyBaseController(IMyServiceContainer container) { 
      MyServiceProp1 = container.MyServiceProp1; 
      MyServiceProp2 = container.MyServiceProp2; 
     } 

     #region Implementation of IMyServiceContainer 

     public IMyService1 MyServiceProp1 { get; set; } 
     public IMyService2 MyServiceProp2 { get; set; } 

     #endregion 
    } 

    #endregion 
} 

這樣,如果我需要添加一個全球性的依賴,我不會改變任何控制器,只是基本控制器,這更容易維護。

有沒有一種方法可以用Ninject(甚至是Unity)實現這一點,因爲我將很快改變它,並且該模式/方法是否有一個我尚未聽到的特定名稱?

+0

Autofac將此模式稱爲「聚合服務」https: //code.google.com/p/autofac/wiki/AggregateService – Doug

回答

2
public interface IMyServiceContainer 
{ 
    IMyService1 MyService1 { get; } 
    IMyService2 MyService2 { get; } 
    IMyService3 MyService3 { get; } 
} 

public class MyServiceContainer 
{ 
    public IMyService1 MyService1 { get; private set; } 
    public IMyService2 MyService2 { get; private set; } 
    public IMyService3 MyService3 { get; private set; } 

    public MyServiceContainer(IMyService1 myService1, IMyService2 myService2, IMyService3 myService3) 
    { 
     MyService1 = myService1; 
     MyService2 = myService2; 
     MyService3 = myService3; 
    } 
} 

,然後你的基地控制器:

public class MyBaseController : Controller 
{ 
    public MyBaseController(IMyServiceContainer container) 
    { 
     Container = container; 
    } 

    protected IMyServiceContainer Container { get; private set; } 
} 

,然後得出控制器:

public class MyController : MyBaseController 
{ 
    public MyController(IMyServiceContainer container) : base(container) 
    { 
    } 

    public ActionResult MyAction() 
    { 
     Container.MyService1.DoSomething(); 
     Container.MyService2.DoSomethingElse(); 
     return View(); 
    } 
} 

現在所有剩下的就是配置NInject:

private static void RegisterServices(IKernel kernel) 
{ 
    kernel.Bind<IMyService1>().To<MyService1>(); 
    kernel.Bind<IMyService2>().To<MyService2>(); 
    kernel.Bind<IMyService3>().To<MyService3>(); 

    kernel.Bind<IMyServiceContainer>().To<MyServiceContainer>(); 
} 
+0

好的。所以我需要實現服務容器?我不能僅僅通過界面來使用它? 我認爲可能有內置的東西來處理這個......沒有意識到我可以添加另一個綁定。 – Spikeh

+0

你不能實例化一個接口。其實你並不需要IMyServiceContainer接口。您可以直接使用MyServiceContainer聚合類。 –

+0

當然。我認爲在後臺有一些實例化。顯然,我從來沒有使用創建的實際類。 我會有一把小提琴:) – Spikeh