![](/img/trans.png)
[英]How to use Castle Windsor's PerWebRequest lifestyle with OWIN
[英]How to register services in scoped lifestyle behaving like PerWebRequest using castle windsor?
我正在使用OWIN開發自托管的Web 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實例時,該問題無法按范圍工作,當新請求到來時,中間件將啟動該中間件,並在完成時處置該中間件。
您能否指導我如何在每個范圍內注冊服務,使其在應用程序中表現得像PerWebRequest一樣?
可能有很多范圍。
要使用由SetupMiddleware
控制的范圍,您需要在請求處理期間(例如,在控制器操作中)解決ICurrentRequestService
服務, ICurrentRequestService
服務比SetupMiddleware
更深。
因此, SetupMiddleware
將創建范圍,然后在控制器動作ICurrentRequestService
解析到該范圍內,最后SetupMiddleware
將通過調用scope.Dispose()
處置ICurrentRequestService
。
據我了解,目前您有以下類似信息:
// 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管道中的第一個中間件。
希望我的代碼對其他人有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.