簡體   English   中英

如何使用城堡溫莎在諸如PerWebRequest之類的范圍內的生活方式中注冊服務?

[英]How to register services in scoped lifestyle behaving like PerWebRequest using castle windsor?

我正在使用OWIN開發自托管的Web api,我需要使用Castle Windsor按范圍的生活方式注冊服務。

我知道使用HttpContext可以使用PerWebRequestHybridPerWebRequestPerThread的生活方式來實現,但就我而言,我沒有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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM