c# - MVC3 和 Ninject/Unity : Injecting a hierarchical service container

标签 c# asp.net-mvc-3 dependency-injection ninject unity-container

我使用 Ninject 一段时间了,但仅限于简单的 DI。我想要满足一个稍微复杂的场景。

我正在使用带有 Controller 注入(inject)的 Ninject.Web.MVC 插件,该插件强制作用于我的基本 Controller ,并传递到所有继承的 Controller 。这是我的基本模式:

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,我将必须修改实现基本 Controller 的每个 Controller 。虽然这并不是一项艰巨的工作,但当项目规模更大时,这将是一项艰巨的工作......

我想做的是实现某种服务容器,我将其注入(inject)到基本 Controller 中,因此所有实现 Controller (以及任何后续类):

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
}

这样,如果我需要添加全局依赖项,我不必更改任何 Controller ,只需更改基本 Controller ,这更容易维护。

有没有一种方法可以使用 Ninject(甚至 Unity,因为我很快就会将其更改为 Unity)来实现此目的,并且该模式/方法是否有一个我尚未听说过的特定名称?

最佳答案

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;
    }
}

然后是你的基本 Controller :

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

    protected IMyServiceContainer Container { get; private set; }
}

然后是派生 Controller :

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>();
}

关于c# - MVC3 和 Ninject/Unity : Injecting a hierarchical service container,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10733814/

相关文章:

c# - 如何为 Facebook 登录编码 redirect_uri

C# - 将 Unity 添加到我的 Visual Studio 项目?

c# - StructureMap 生命周期范围

haskell - 在 Haskell 中,使用 ExistentialQuantification 的依赖注入(inject)是一种反模式吗?

c# - 从任务继续写入 ASP.NET 响应输出流

c# - 设置复选框的高度不起作用

asp.net-mvc-3 - Ajax.BeginForm 可以重定向到新页面并传递路由值

html - Bootstrap typeahead ajax 结果格式 - 示例

C#:static object.Equals 如何检查是否相等?

c# - .Cast<T> 扩展方法总是抛出 InvalidCastException - 你应该如何使用这个方法?