组合根与服务定位器

本文关键字:定位器 服务 组合 | 更新日期: 2023-09-27 18:32:04

我一直在阅读这两种解决依赖关系的方法,并找到了一些用于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;
    }
    ...
}

我是否正确实现了合成根?我真的看不出这两种方法之间有什么区别?

组合根与服务定位器

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

另一方面,服务定位器

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

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