web api 控制器和温莎城堡的生活方式

web api controller and castle windsor lifestyle

在 web api 控制器功能中,我使用两个服务,因为它们做独立的事情,我希望它们使用不同的工作单元(事务)。

所有必要的组件(工作单元、存储库)都通过 castle windsor 使用 LifestylePerWebRequest 注入。

据我所知,解决方案是使用 LifeStyleScoped,但我有两个问题:

  1. 我只希望 LifeStyleScoped 用于这种特殊情况,而不是一般情况
  2. 我找不到一个关于如何在控制器中使用 LifeStyleScoped 的例子。

如有任何其他建议或代码示例,我们将不胜感激。

编辑:我没有提到没有在控制器中显式注入工作单元。在控制器中注入了两个服务,这些服务使用通过温莎城堡创建的工作单元。

public class SomeController : ApiController
{
    private readonly IService _service1;
    private readonly IService _service2;

    public SomeController (IService service1, IService service2)
    {
        _service1= service1;
        _service2= service2;
    }

    public IHttpActionResult SomeAction() 
    {
        _service1.DoSomething();
        _service2.DoSomething();
    }
}

public Service : IService 
{
    public Service(IUnitOfWork uow) {

    }
}

如果您在 Web API 应用程序中使用 Castle.Windsor,您可能已经在使用 IDependencyResolver,您可以连接它以使用 Windsor 自己的范围,类似于:

class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer _container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        _container = container;
    }

    public object GetService(Type t)
    {
        return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
    }

    public IEnumerable<object> GetServices(Type t)
    {
        return _container.ResolveAll(t).Cast<object>().ToArray();
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(_container);
    }

    public void Dispose()
    {
    }
}

class WindsorDependencyScope : IDependencyScope
{
    private readonly IWindsorContainer _container;
    private readonly IDisposable _scope;

    public WindsorDependencyScope(IWindsorContainer container)
    {
        _container = container;
        _scope = container.BeginScope();
    }

    public object GetService(Type t)
    {
        return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
    }

    public IEnumerable<object> GetServices(Type t)
    {
        return _container.ResolveAll(t).Cast<object>().ToArray();
    }

    public void Dispose()
    {
        _scope.Dispose();
    }
}

Web API 会为每个请求创建一个新的作用域,并在请求完成后释放它。因此,如果您使用此技术,您可能可以取消 LifestylePerWebRequest 并简单地使用 LifestyleScoped,从而解决每个组件需要两次注册的问题。

那么第二个挑战是:如何获得第二个独立的工作单元?显然,所有强制和可选的控制器依赖项都将在同一个 ILifetimeScope 中隐式解析,因此简单地天真地为第二个 IUnitOfWork 声明构造函数依赖项是行不通的。

有多种方法可以做到这一点,但如果您准备好接受 Service Locator Anti-Pattern,您可以像这样简单地创建自己的范围:

public class SomeController : ApiController
{
    private readonly IUnitOfWork _uow;

    public SomeController (IUnitOfWork uow)
    {
        _uow = uow;
    }

    public IHttpActionResult SomeAction() 
    {
        // Get a second UoW
        using (var separatelyScopedResolver = GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
        {
            var anotherUoW = separatelyScopedResolver.GetService(typeof (IUnitOfWork));
            // Do something with this UoW...
            anotherUoW.Save();
        }

         // Do something with the default UoW...
         _uow.Save();

         // Et cetera...
    }
}