[英]How to register services in scoped lifestyle behaving like PerWebRequest using castle windsor?
I am working on self-hosted web api using OWIN and I need to register a service per scope lifestyle using Castle Windsor. 我正在使用OWIN开发自托管的Web api,我需要使用Castle Windsor按范围的生活方式注册服务。
I know that using HttpContext I can achieve that using PerWebRequest or HybridPerWebRequestPerThread lifestyle but in my case I don't have HttpContext. 我知道使用HttpContext可以使用PerWebRequest或HybridPerWebRequestPerThread的生活方式来实现,但就我而言,我没有HttpContext。
I have created the following owin middleware which will be the first and the last middleware will be executed during the request : 我创建了以下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();
}
}
And when I Startup my application I register my service inside the IoC container as following: 当我启动应用程序时,我在IoC容器中注册我的服务,如下所示:
container.BeginScope();
container.Register(Component.For<ICurrentRequestService>().ImplementedBy<CurrentRequestService>().LifestyleScoped());
The problem when I resolve instance of CurrentRequestService, it does not work as per scope which owin middleware will begin it when a new request comes and dispose it when it finishes. 当我解析CurrentRequestService实例时,该问题无法按范围工作,当新请求到来时,中间件将启动该中间件,并在完成时处置该中间件。
Could you please guide me to how can I register services per scope to behave like PerWebRequest in my application? 您能否指导我如何在每个范围内注册服务,使其在应用程序中表现得像PerWebRequest一样?
There may be many scopes. 可能有很多范围。
To use the scope that is controlled by SetupMiddleware
you need to resolve ICurrentRequestService
service somewhere deeper than SetupMiddleware
during request processing (eg in controller action). 要使用由
SetupMiddleware
控制的范围,您需要在请求处理期间(例如,在控制器操作中)解决ICurrentRequestService
服务, ICurrentRequestService
服务比SetupMiddleware
更深。
Thus, SetupMiddleware
will create the scope, then in controller action ICurrentRequestService
will be resolved inside that scope, finally SetupMiddleware
will dispose ICurrentRequestService
by calling scope.Dispose()
. 因此,
SetupMiddleware
将创建范围,然后在控制器动作ICurrentRequestService
解析到该范围内,最后SetupMiddleware
将通过调用scope.Dispose()
处置ICurrentRequestService
。
As I understand, currently you have something like this: 据我了解,目前您有以下类似信息:
// 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
Thus, service
uses the application scope instead of the request scope. 因此,
service
使用应用程序范围而不是请求范围。
As I expected that I should define a custom scope to be started and dispose within a middleware . 正如我期望的那样,我应该定义一个自定义范围,以将其启动并放置在中间件中。
I have created the following custom scope accessor: 我创建了以下自定义作用域访问器:
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;
}
}
Then I have modified my SetupMiddleware as followings: 然后,我对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();
}
}
}
Then I registered my service using the above scope : 然后,我使用上述范围注册了服务:
container.Register(Component.For<ICurrentRequestService>().ImplementedBy<CurrentRequestService>().LifestyleScoped<OwinWebRequestScopeAccessor>());
PS: PS:
SetupMiddleware should be the first middleware in the owin pipeline. SetupMiddleware应该是owin管道中的第一个中间件。
I hope my code will help others. 希望我的代码对其他人有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.