如何使用温莎城堡在范围内的生活方式中注册服务,表现得像 PerWebRequest?
How to register services in scoped lifestyle behaving like PerWebRequest using castle windsor?
我正在使用 OWIN 在自托管网络 api 上工作,我需要使用 Castle Windsor 注册每个范围生活方式的服务。
我知道使用 HttpContext 我可以使用 PerWebRequest 或 HybridPerWebRequestPerThread 生活方式来实现,但是就我而言,我没有 HttpContext。
我创建了以下 owin 中间件,它们将在请求期间执行第一个和最后一个中间件:
public class SetupMiddleware : OwinMiddleware
{
public SetupMiddleware(OwinMiddleware next) : base(next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
}
public override async Task Invoke(IOwinContext context)
{
IDisposable scope = null;
try
{
//here I am starting new scope
var container= IoCResolverFactory.GetContainer();
scope = container.BeginScope();
await Next.Invoke(context);
}
catch (Exception ex)
{
}
finally
{
//here I am disposing it
scope?.Dispose();
}
}
当我启动我的应用程序时,我在 IoC 容器中注册了我的服务,如下所示:
container.BeginScope();
container.Register(Component.For<ICurrentRequestService>().ImplementedBy<CurrentRequestService>().LifestyleScoped());
当我解析 CurrentRequestService 的实例时出现问题,它无法按照范围工作,owin 中间件将在新请求到来时开始它并在它完成时处理它。
能否请您指导我如何注册每个范围的服务,使其在我的应用程序中表现得像 PerWebRequest?
可能有很多范围。
要使用由 SetupMiddleware
控制的范围,您需要在请求处理期间(例如在控制器操作中)解析比 SetupMiddleware
更深的某个地方的 ICurrentRequestService
服务。
因此,SetupMiddleware
将创建范围,然后在控制器操作中 ICurrentRequestService
将在该范围内解析,最后 SetupMiddleware
将通过调用 scope.Dispose()
.
据我了解,目前你有这样的东西:
// when application starts. Executes once
container.BeginScope(); // the 1st (application) scope beginning.
container.Register(Component.For<ICurrentRequestService>().ImplementedBy<CurrentRequestService>().LifestyleScoped());
var service = IoCResolverFactory.GetContainer().Resolve<ICurrentRequestService>();
//in SetupMiddleware. This code executes on every web request
var container = IoCResolverFactory.GetContainer();
scope = container.BeginScope(); // the request scope beginning
// here others middlewares
// here you can resolve ICurrentRequestService to use the request scope
scope?.Dispose(); // the request scope end
因此,service
使用应用程序范围而不是请求范围。
正如我所料,我应该定义一个自定义范围以启动并在中间件中进行处理。
我创建了以下自定义作用域访问器:
public class OwinWebRequestScopeAccessor : IScopeAccessor
{
void IDisposable.Dispose() { }
ILifetimeScope IScopeAccessor.GetScope(CreationContext context)
{
IOwinContext owinContext = HttpContext.Current.GetOwinContext();
string key = SetupMiddleware.EnvironmentKey;
return owinContext.Environment[key] as ILifetimeScope;
}
}
然后我修改了我的 SetupMiddleware 如下:
public class SetupMiddleware : OwinMiddleware
{
public const string EnvironmentKey = "WindsorOwinScope";
public SetupMiddleware(OwinMiddleware next) : base(next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
}
public override async Task Invoke(IOwinContext context)
{
ILifetimeScope lifetimeScope = new DefaultLifetimeScope();
try
{
context.Environment[EnvironmentKey] = lifetimeScope;
await Next.Invoke(context);
}
catch (Exception ex)
{
}
finally
{
context.Environment.Remove(EnvironmentKey);
lifetimeScope.Dispose();
}
}
}
然后我使用上述范围注册了我的服务:
container.Register(Component.For<ICurrentRequestService>().ImplementedBy<CurrentRequestService>().LifestyleScoped<OwinWebRequestScopeAccessor>());
PS:
SetupMiddleware 应该是 owin 管道中的第一个中间件。
希望我的代码对其他人有所帮助。
我正在使用 OWIN 在自托管网络 api 上工作,我需要使用 Castle Windsor 注册每个范围生活方式的服务。
我知道使用 HttpContext 我可以使用 PerWebRequest 或 HybridPerWebRequestPerThread 生活方式来实现,但是就我而言,我没有 HttpContext。
我创建了以下 owin 中间件,它们将在请求期间执行第一个和最后一个中间件:
public class SetupMiddleware : OwinMiddleware
{
public SetupMiddleware(OwinMiddleware next) : base(next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
}
public override async Task Invoke(IOwinContext context)
{
IDisposable scope = null;
try
{
//here I am starting new scope
var container= IoCResolverFactory.GetContainer();
scope = container.BeginScope();
await Next.Invoke(context);
}
catch (Exception ex)
{
}
finally
{
//here I am disposing it
scope?.Dispose();
}
}
当我启动我的应用程序时,我在 IoC 容器中注册了我的服务,如下所示:
container.BeginScope();
container.Register(Component.For<ICurrentRequestService>().ImplementedBy<CurrentRequestService>().LifestyleScoped());
当我解析 CurrentRequestService 的实例时出现问题,它无法按照范围工作,owin 中间件将在新请求到来时开始它并在它完成时处理它。
能否请您指导我如何注册每个范围的服务,使其在我的应用程序中表现得像 PerWebRequest?
可能有很多范围。
要使用由 SetupMiddleware
控制的范围,您需要在请求处理期间(例如在控制器操作中)解析比 SetupMiddleware
更深的某个地方的 ICurrentRequestService
服务。
因此,SetupMiddleware
将创建范围,然后在控制器操作中 ICurrentRequestService
将在该范围内解析,最后 SetupMiddleware
将通过调用 scope.Dispose()
.
据我了解,目前你有这样的东西:
// when application starts. Executes once
container.BeginScope(); // the 1st (application) scope beginning.
container.Register(Component.For<ICurrentRequestService>().ImplementedBy<CurrentRequestService>().LifestyleScoped());
var service = IoCResolverFactory.GetContainer().Resolve<ICurrentRequestService>();
//in SetupMiddleware. This code executes on every web request
var container = IoCResolverFactory.GetContainer();
scope = container.BeginScope(); // the request scope beginning
// here others middlewares
// here you can resolve ICurrentRequestService to use the request scope
scope?.Dispose(); // the request scope end
因此,service
使用应用程序范围而不是请求范围。
正如我所料,我应该定义一个自定义范围以启动并在中间件中进行处理。
我创建了以下自定义作用域访问器:
public class OwinWebRequestScopeAccessor : IScopeAccessor
{
void IDisposable.Dispose() { }
ILifetimeScope IScopeAccessor.GetScope(CreationContext context)
{
IOwinContext owinContext = HttpContext.Current.GetOwinContext();
string key = SetupMiddleware.EnvironmentKey;
return owinContext.Environment[key] as ILifetimeScope;
}
}
然后我修改了我的 SetupMiddleware 如下:
public class SetupMiddleware : OwinMiddleware
{
public const string EnvironmentKey = "WindsorOwinScope";
public SetupMiddleware(OwinMiddleware next) : base(next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
}
public override async Task Invoke(IOwinContext context)
{
ILifetimeScope lifetimeScope = new DefaultLifetimeScope();
try
{
context.Environment[EnvironmentKey] = lifetimeScope;
await Next.Invoke(context);
}
catch (Exception ex)
{
}
finally
{
context.Environment.Remove(EnvironmentKey);
lifetimeScope.Dispose();
}
}
}
然后我使用上述范围注册了我的服务:
container.Register(Component.For<ICurrentRequestService>().ImplementedBy<CurrentRequestService>().LifestyleScoped<OwinWebRequestScopeAccessor>());
PS:
SetupMiddleware 应该是 owin 管道中的第一个中间件。
希望我的代码对其他人有所帮助。