组合根与服务定位器

时间:2016-01-26 05:46:23

标签: c# dependency-injection ninject inversion-of-control compositionroot

我一直在阅读这两种解决依赖关系的方法,并为ninject实现找到了一些示例代码。

对于服务定位器,跟随

之类的内容
 public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
 {
    IKernel kernel;

    public NinjectDependencyResolver(IKernel kernel)
        : base(kernel)
    {
        this.kernel = kernel;
    }

    public IDependencyScope BeginScope()
    {
        return new NinjectDependencyScope(kernel.BeginBlock());
    }
}

并且

public class NinjectDependencyScope : IDependencyScope
{
    IResolutionRoot resolver;

    public NinjectDependencyScope(IResolutionRoot resolver)
    {
        this.resolver = resolver;
    }

    public object GetService(Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        return resolver.TryGet(serviceType);
    }

    public System.Collections.Generic.IEnumerable<object> GetServices(Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        return resolver.GetAll(serviceType);
    }

    public void Dispose()
    {
        IDisposable disposable = resolver as IDisposable;
        if (disposable != null)
            disposable.Dispose();

        resolver = null;
    }
}

开箱即用的课程

    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 the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        try
        {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(kernel);
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }

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

对于组合词根我遵循 - https://gist.github.com/paigecook/3860942

 public class NinjectKernelActivator: IHttpControllerActivator
{
    private readonly IKernel _kernel;

    public NinjectKernelActivator(IKernel kernel)
    {
        _kernel = kernel;
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        var controller = (IHttpController) _kernel.Get(controllerType);

        request.RegisterForDispose( new Release(()=> _kernel.Release(controller)));

        return controller;
    }
}

internal class Release : IDisposable
{
    private readonly Action _release;

    public Release(Action release)
    {
        _release = release;
    }

    public void Dispose()
    {
        _release();
    }
}

在NinjectWebCommon中对Create(..)进行了一次更改。

                //GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
            GlobalConfiguration.Configuration.Services.Replace(
              typeof(IHttpControllerActivator),
                new NinjectCompositionRoot(kernel));

编辑

控制器和服务创建

public class MembersController : ApiController
{
    private readonly IMembersService _membersService;

    public MembersController(IMembersService membersService)
    {
        _membersService = embersService;
    }

    ...
}


public class MembersService : IMembersService
{
    private readonly MembersContext _context;

    public MembersService(MemberContext context)
    {
        _context = context;
    }

    ...
}

我是否正确实施了组合根? 我真的不明白这两种方法有什么区别?

1 个答案:

答案 0 :(得分:3)

Composition root(应该如何进行依赖注入)和Service Locator之间的区别在于组合根应该位于应用程序的一个位置(尽可能接近应用程序的入口点)。这并不意味着它只会被调用一次。例如,在MVC / WebAPI的情况下,组合根的好处是控制器工厂,它为每个HTTP请求应用程序接收创建控制器。关键是在控制器工厂中实现的组合根应该创建整个对象图(具有所有依赖关系的控制器),它们需要处理请求,以便在此请求期间不需要单独从容器中解析其他依赖关系。

另一方面,

Service Locator是您在需要时从服务定位器检索依赖关系的方法。服务定位器成为应用程序中的环境上下文(通常提供静态ServiceLocator.Get<T>()方法)。 Service Locator与Dependency Injection相反,因为您不是注入依赖项,而是在需要时检索它们。这意味着在应用程序代码中调用ServiceLocator.Get<T>()方法,并且应用程序的所有层都依赖于服务定位器。这种方法有几个缺点,其中之一就是它使代码更难以进行单元测试,因为所有测试都需要与同一个全局服务定位器类进行交互,以设置被测试类的伪依赖。

您的NinjectKernelActivator组合根的实现是正确的,假设您没有在某些公共静态属性中将IKernel公开,以便稍后使用它来获取您未注入的依赖项。