web api 控制器和温莎城堡的生活方式
web api controller and castle windsor lifestyle
在 web api 控制器功能中,我使用两个服务,因为它们做独立的事情,我希望它们使用不同的工作单元(事务)。
所有必要的组件(工作单元、存储库)都通过 castle windsor 使用 LifestylePerWebRequest 注入。
据我所知,解决方案是使用 LifeStyleScoped,但我有两个问题:
- 我只希望 LifeStyleScoped 用于这种特殊情况,而不是一般情况
- 我找不到一个关于如何在控制器中使用 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...
}
}
在 web api 控制器功能中,我使用两个服务,因为它们做独立的事情,我希望它们使用不同的工作单元(事务)。
所有必要的组件(工作单元、存储库)都通过 castle windsor 使用 LifestylePerWebRequest 注入。
据我所知,解决方案是使用 LifeStyleScoped,但我有两个问题:
- 我只希望 LifeStyleScoped 用于这种特殊情况,而不是一般情况
- 我找不到一个关于如何在控制器中使用 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...
}
}