简体   繁体   English

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

[英]ServiceStack self-hosted application with per-request lifetime scope

Working with ServiceStack I've stuck with the problem of objects lifetime management in self-hosted web application. 使用ServiceStack我一直坚持自托管Web应用程序中对象生存期管理的问题。

My requirements: 我的要求:

  1. Need of per-request objects lifetime scope. 需要每个请求对象的生命周期范围。
  2. I'm using Castle Windsor IoC with implemented ServiceStack IoC adapter. 我正在使用Castle Windsor IoC和已实施的ServiceStack IoC适配器。
  3. My application is self-hosted with base class AppHostHttpListenerPoolBase (ServiceStack v4) 我的应用程序是自托管的基类AppHostHttpListenerPoolBase(ServiceStack v4)
  4. Probably one day I want to move on IIS, thus it's must be flexible. 可能有一天我想继续使用IIS,因此它必须是灵活的。

General problem: 一般问题:

Castle Windsor IoC implements its own per-request lifetime strategy but it is binded to http modules, thus it works only with IIS hosted apps. Castle Windsor IoC实现了自己的每个请求生命周期策略,但它绑定到http模块,因此它仅适用于IIS托管应用程序。 Hence, I have to implement my custom IScopeAccessor (provided by Castle Windsor) to handle objects lifetime. 因此,我必须实现我的自定义IScopeAccessor(由Castle Windsor提供)来处理对象的生命周期。 The problem here is in absence of hooks which I can use to bind to current request. 这里的问题是没有钩子,我可以用它来绑定当前的请求。

Given 特定

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

I have to implement GetScope method. 我必须实现GetScope方法。

There are two main ideas I cannot complete: 我无法完成两个主要想法:

Using of [Threadstatic] 使用[Threadstatic]

In MyScopeAccessor I just store 在MyScopeAccessor中,我只是存储

[ThreadStatic] 
private static ILifetimeScope _currentLifetimeScope;

and create new scope after first GetScope if it's not initialzied yet. 如果尚未初始化,请在第一个GetScope之后创建新范围。

Problems: 问题:

  1. Hard to dispose. 难以处置。 Best way to dispose _currentLifetimeScope is to implement custom IServiceRunner (or inherit from ServiceRunner) overriding AfterEachRequest method. 处理_currentLifetimeScope的最佳方法是实现自定义的IServiceRunner(或从ServiceRunner继承)覆盖AfterEachRequest方法。 But I don't exactly know if AfterEachRequest is actually executed in request thread. 但我不确切知道AfterEachRequest是否实际在请求线程中执行。
  2. Moving to IIS can cause some problems because as I know IIS doesn't guarantee unchangeable binding between theads and request contexts. 迁移到IIS可能会导致一些问题,因为我知道IIS不保证theads和请求上下文之间不可更改的绑定。

Using of IRequest instance 使用IRequest实例

In MyScopeAccessor I just store 在MyScopeAccessor中,我只是存储

private static readonly ConcurrentDictionary<IRequest, ILifetimeScope> LifetimeScopes;

and create and dispose current lifetime scope in corresponding custom ServiceRunner methods (OnBeforeEachRequest, OnAfterEachRequest). 并在相应的自定义ServiceRunner方法(OnBeforeEachRequest,OnAfterEachRequest)中创建和处置当前生命周期范围。

Problems: 问题:

  1. I don't know how to get access to current request globally from GetScope, MyScopeAccessor knows nothing about services and requests. 我不知道如何从GetScope全局访问当前请求,MyScopeAccessor对服务和请求一无所知。

Also, it is interesting if ServiceStack default Funq IoC solves this problem. 此外,有趣的是ServiceStack默认Funq IoC解决了这个问题。

Funq does handle RequestScoped dependencies which stores Request Context dependencies in the RequestContext.Instance.Items[] dictionary. Funq确实处理RequestScoped依赖项 ,它在RequestContext.Instance.Items[]字典中存储请求上下文依赖项。

Any disposables can be registered in RequestContext.Instance.TrackDisposable() are automatically disposed of at the end of the request. 任何一次性用品都可以在RequestContext.Instance.TrackDisposable()中注册, RequestContext.Instance.TrackDisposable()RequestContext.Instance.TrackDisposable()结束时自动处理。

At the end of each request AppHost.OnEndRequest() is fired which goes through and releases any dependencies stored in the RequestContext for that request. 在每个请求结束时,会触发AppHost.OnEndRequest() ,它会通过并释放存储在AppHost.OnEndRequest()中的该请求的所有依赖项。

If your Windsor ContainerAdapter implements the IRelease interface it's automatically called to release any instances which can be handled itself. 如果您的Windsor ContainerAdapter实现了IRelease接口,它会自动调用以释放任何可以自行处理的实例。 Both these API's are overridable in your AppHost if you want to change the default behavior: 如果要更改默认行为,这两个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*/ }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM