具有每个请求生存期范围的ServiceStack自托管应用程序

时间:2014-10-05 15:50:43

标签: c# servicestack castle-windsor ioc-container lifetime-scoping

使用ServiceStack我一直坚持自托管Web应用程序中对象生存期管理的问题。

我的要求:

  1. 需要每个请求对象的生命周期范围。
  2. 我正在使用Castle Windsor IoC和已实施的ServiceStack IoC适配器。
  3. 我的应用程序是自托管的,具有基类AppHostHttpListenerPoolBase(ServiceStack v4)
  4. 可能有一天我想继续使用IIS,因此它必须是灵活的。
  5. 一般问题:

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

    给出

    public class MyScopeAccessor : IScopeAccessor
    {
        public ILifetimeScope GetScope(CreationContext context)
        {
           //implement it
        }
    }
    

    我必须实现GetScope方法。

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

    使用[Threadstatic]

    在MyScopeAccessor中我只存储

    [ThreadStatic] 
    private static ILifetimeScope _currentLifetimeScope;
    

    并在第一个GetScope之后创建新范围,如果它尚未初始化。

    问题:

    1. 难以处置。处理_currentLifetimeScope的最佳方法是实现自定义的IServiceRunner(或从ServiceRunner继承)覆盖AfterEachRequest方法。但我并不完全知道AfterEachRequest是否实际在请求线程中执行。
    2. 迁移到IIS可能会导致一些问题,因为我知道IIS不保证theads和请求上下文之间不可更改的绑定。
    3. 使用IRequest实例

      在MyScopeAccessor中我只存储

      private static readonly ConcurrentDictionary<IRequest, ILifetimeScope> LifetimeScopes;
      

      并在相应的自定义ServiceRunner方法(OnBeforeEachRequest,OnAfterEachRequest)中创建和处置当前生命周期范围。

      问题:

      1. 我不知道如何从GetScope全局访问当前请求,MyScopeAccessor对服务和请求一无所知。
      2. 此外,有趣的是,如果ServiceStack默认Funq IoC解决了这个问题。

1 个答案:

答案 0 :(得分:3)

Funq会处理RequestScoped dependencies,它会在RequestContext.Instance.Items[]字典中存储请求上下文依赖项。

任何可以在RequestContext.Instance.TrackDisposable()注册的一次性用品都会在请求结束时自动处理。

在每个请求结束时AppHost.OnEndRequest()被触发,该请求将通过并释放存储在RequestContext中的该请求的所有依赖项。

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

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*/ }
}