servicestack,castle-windsor,ioc-container,lifetime-scoping,C#,servicestack,Castle Windsor,Ioc Container,Lifetime Scoping" /> servicestack,castle-windsor,ioc-container,lifetime-scoping,C#,servicestack,Castle Windsor,Ioc Container,Lifetime Scoping" />

C# 具有每个请求生存期作用域的ServiceStack自托管应用程序

C# 具有每个请求生存期作用域的ServiceStack自托管应用程序,c#,servicestack,castle-windsor,ioc-container,lifetime-scoping,C#,servicestack,Castle Windsor,Ioc Container,Lifetime Scoping,使用ServiceStack时,我一直在解决自托管web应用程序中的对象生命周期管理问题 我的要求: 需要每个请求对象的生存期范围 我正在使用Castle Windsor IoC和已实现的ServiceStack IoC适配器 我的应用程序是使用基类AppHostHttpListenerPoolBase(ServiceStack v4)自托管的 也许有一天我想在IIS上移动,所以它必须是灵活的 一般问题: Castle Windsor IoC实现了自己的每请求生存期策略,但它绑定到http模块,

使用ServiceStack时,我一直在解决自托管web应用程序中的对象生命周期管理问题

我的要求:

  • 需要每个请求对象的生存期范围
  • 我正在使用Castle Windsor IoC和已实现的ServiceStack IoC适配器
  • 我的应用程序是使用基类AppHostHttpListenerPoolBase(ServiceStack v4)自托管的
  • 也许有一天我想在IIS上移动,所以它必须是灵活的
  • 一般问题:

    Castle Windsor IoC实现了自己的每请求生存期策略,但它绑定到http模块,因此它仅适用于IIS托管的应用程序。因此,我必须实现我的自定义IScopeAccessor(由Castle Windsor提供)来处理对象。这里的问题是缺少可以用来绑定到当前请求的钩子

    给定

    公共类MyScopeAccessor:IScopeAccessor
    {
    公共ILifetimeScope GetScope(CreationContext上下文)
    {
    //实施它
    }
    }
    
    我必须实现GetScope方法

    有两个主要想法我无法完成:

    使用[Threadstatic]

    在MyScopeAccessor中,我只存储

    [ThreadStatic]
    专用静态ILifetimeScope\u currentLifetimeScope;
    
    并在第一个GetScope之后创建新的作用域(如果尚未初始化)

    问题:

  • 很难处理。处理_currentLifetimeScope的最佳方法是在每个请求方法之后实现自定义IServiceRunner(或从ServiceRunner继承)重写。但我不知道每次请求后是否在请求线程中执行
  • 移动到IIS可能会导致一些问题,因为据我所知,IIS不能保证AD和请求上下文之间的绑定不可更改
  • 使用IRequest实例

    在MyScopeAccessor中,我只存储

    私有静态只读ConcurrentDictionary生存时间范围;
    
    并在相应的自定义ServiceRunner方法(OnBeforeAchRequest、OnAfterEachRequest)中创建和处理当前生存期范围

    问题:

  • 我不知道如何从GetScope全局访问当前请求,MyScopeAccessor对服务和请求一无所知
  • 另外,如果ServiceStack default Funq IoC解决了这个问题,这也很有趣。

    Funq会处理在
    RequestContext.Instance.Items[]字典中存储请求上下文依赖项的操作

    可以在
    RequestContext中注册任何可处置项。Instance.TrackDisposable()
    将在请求结束时自动处置

    在每个请求结束时,都会触发AppHost.OnEndRequest()
    ,该请求会遍历并释放该请求的RequestContext中存储的任何依赖项

    如果您的Windsor ContainerAdapter实现了
    IRelease
    接口,则会自动调用该接口以释放任何可自行处理的实例。如果要更改默认行为,则可在
    AppHost
    中重写这两个API:

    public virtual void OnEndRequest()
    {
        var disposables = RequestContext.Instance.Items.Values;
        foreach (var item in disposables)
        {
            Release(item);
        }
    
        RequestContext.Instance.EndRequest();
    }
    
    public virtual void Release(object instance)
    {
        try
        {
            var iocAdapterReleases = Container.Adapter as IRelease;
            if (iocAdapterReleases != null)
            {
                iocAdapterReleases.Release(instance);
            }
            else
            {
                var disposable = instance as IDisposable;
                if (disposable != null)
                    disposable.Dispose();
            }
        }
        catch { /*ignore*/ }
    }
    

    谢谢现在很清楚Funq是如何工作的。但主要问题是如何从任意代码位置(包括MyScopeAccessor)映射到当前请求上下文。有了这个能力,我可以做任何事情,也可以处理。另外,我不想实现已经实现的温莎城堡的一部分。我认为RequestContext.Instance.Items是请求上下文标识的最佳选择,对吗?也就是像使用静态ConcurrentDictionary LifetimeScopes一样使用它以RequestContext.Instance.Items对象作为键。并且不符合
    RequestContext.Instance
    的要求,因为它似乎是一个单例?@ValentinP.
    RequestContext.Instance
    是一个单例,您可以使用
    RequestContext.Instance.Items
    对象字典来保存请求范围的依赖项来标识请求。默认情况下,幕后
    Items
    使用
    HttpContext.Current.Items
    (ASP.NET)或
    CallContext.LogicalData
    进行自我托管,否则
    RequestContext.RequestItems
    如果
    RequestContext.UseThreadStatic=true
    。有关详细信息,请参阅impl。