2017-07-21 1 views
2

私はこのようなミドルウェア何か使用して要求パイプラインに設定したカスタム実行コンテキストとWEBAPIありますASP .NETコア要求パイプラインでまだ未完了の子スレッドを残したままスレッドの再利用を停止する方法はありますか。

public async Task Invoke(HttpContext httpContext) 
{ 
    using (Context.With(new TokenContext("token"))) 
    { 
    await _next(httpContext); 
    } 
} 

とコンテキストマネージャは、ローカルにあるIContextオブジェクトのスタックで、このようなビットに見えます現在のスレッド(およびスレッドが作成するスレッド)

public static class Context 
{ 
    private static AsyncLocal<Stack<IContext>> _current = new AsyncLocal<Stack<IContext>>(); 
    public static IContext Current 
    { 
    get 
    { 
     return _current.Value != null && _current.Value.Count > 0 ?_current.Value.Peek() : null; 
    } 
    } 

    public static IDisposable With(IContext context) 
    { 
    Assert.IsNotNull(context); 

    if (_current.Value == null) _current.Value = new Stack<IContext>(); 
    _current.Value.Push(context); 

    return new DelegateDisposable(() => 
    { 
     _current.Value.Pop(); 
    }); 
    } 
} 

同時に起こって複数の要求を持ったときに私が経験する問題があります。時には私は、現在の状況が私が期待していたものではないという問題を抱えています。私は、現在の文脈が時にはusingステートメントで設定する前に値を持っていることに気付きました。私の結論は、要求に使用された最初のスレッドがawait _nextに当たったときにスレッドプールに返され、このスレッドが「子スレッド」が完了する前に時々起こる要求に再利用できることです。これは私に予測不可能な多くの動作を残します。

私の質問:どうすればこの問題にぶつからないのですか?すべての「子スレッド」が完了する前に、要求パイプラインがスレッドを返さないように強制できますか?これは非効率的でしょうか? 「マザースレッド」が自分自身をプールに戻す前にコンテキストスタックへの参照をクリーンアップするよう強制できますか?

他のオプションはありますか?

答えて

1

the documentationからは明らかではありませんが、the types stored in AsyncLocal<T> should be immutableです。

これはあなたの問題(ImmutableStack from NuGetを使用して)までクリアする必要があります:

public static class Context 
{ 
    private static AsyncLocal<ImmutableStack<IContext>> _local = new AsyncLocal<ImmutableStack<IContext>>(); 
    private static ImmutableStack<IContext> Value => _local.Value ?? ImmutableStack<IContext>.Empty; 
    public static IContext Current 
    { 
    get 
    { 
     var value = Value; 
     return value.IsEmpty ? null : value.Peek(); 
    } 
    } 

    public static IDisposable With(IContext context) 
    { 
    Assert.IsNotNull(context); 

    _local.Value = Value.Push(context); 

    return new DelegateDisposable(() => 
    { 
     _local.Value = Value.Pop(); 
    }); 
    } 
} 

をキーにはすべての修正(プッシュとポップの両方)AsyncLocal<T>.Valueを設定しなければならないということです。これは通常のStack<T>で行うことができますが、ImmutableStack<T>を使用すると正しいセマンティクスが強制されます。

+0

ありがとうございました! –

関連する問題