38

.NET 4.5 で async/await パターンを使用して、WCF でいくつかのサービス メソッドを実装しています。サービス例:

契約:

[ServiceContract(Namespace = "http://async.test/")]
public interface IAsyncTest
{
    Task DoSomethingAsync();
}

実装:

MyAsyncService : IAsyncTest
{
    public async Task DoSomethingAsync()
    {
        var context = OperationContext.Current; // context is present

        await Task.Delay(10);

        context = OperationContext.Current; // context is null
    }
}

私が抱えている問題は、最初await OperationContext.Currentに戻った後null、にアクセスできないことですOperationContext.Current.IncomingMessageHeaders

この単純な例では、await. しかし、実際のケースOperationContext.Currentではコール スタックの奥深くからアクセスされており、コンテキストをさらに渡すためだけに多くのコードを変更したくありません。

await手動でスタックに渡すことなく、ポイントの後に操作コンテキストを取得する方法はありますか?

4

7 に答える 7

29

これが機能しないのは残念です。将来のリリースで修正が行われる予定です。

それまでの間、現在のスレッドにコンテキストを再適用して、オブジェクトを渡す必要がないようにする方法があります。

    public async Task<double> Add(double n1, double n2)
    {

        OperationContext ctx = OperationContext.Current;

        await Task.Delay(100);

        using (new OperationContextScope(ctx))
        {
            DoSomethingElse();
        }
        return n1 + n2;
    }  

上記の例では、DoSomethingElse()メソッドは期待どおりにOperationContext.Currentにアクセスできます。

于 2012-10-16T16:42:02.803 に答える
22

あなたの最善の選択肢は、実際にキャプチャして手動で渡すことだと思います。これにより、コードのテスト容易性が向上することがあります。

とはいえ、他にもいくつかのオプションがあります。

  1. に追加しLogicalCallContextます。
  2. ;を実行するときにSynchronizationContext設定する独自のものをインストールします。これは、ASP.NET がその.OperationContext.CurrentPostHttpContext.Current
  3. TaskScheduler独自のセットをインストールしますOperationContext.Current

Microsoft Connect でこの問題を提起することもできます。

于 2012-10-09T11:16:28.007 に答える
8

.Net 4.6.2 で修正されたようです。お知らせを見る

于 2016-08-11T09:33:24.510 に答える
3

SynchronizationContext実装例は次のとおりです。

public class OperationContextSynchronizationContext : SynchronizationContext
{
    private readonly OperationContext context;

    public OperationContextSynchronizationContext(IClientChannel channel) : this(new OperationContext(channel)) { }

    public OperationContextSynchronizationContext(OperationContext context)
    {
        OperationContext.Current = context;
        this.context = context;
    }

    public override void Post(SendOrPostCallback d, object state)
    {
        OperationContext.Current = context;
        d(state);
    }
}

そして使用法:

var currentSynchronizationContext = SynchronizationContext.Current;
try
{
    SynchronizationContext.SetSynchronizationContext(new OperationContextSynchronizationContext(client.InnerChannel));
    var response = await client.RequestAsync();
    // safe to use OperationContext.Current here
}
finally
{
    SynchronizationContext.SetSynchronizationContext(currentSynchronizationContext);
}
于 2014-03-21T08:42:52.360 に答える
2

幸いなことに、実際のサービスの実装はUnityIoC コンテナーを介してインスタンス化されます。これにより、 のインスタンスごとに のインスタンスが1 つだけ存在することを意味するIWcfOperationContextを持つように構成されたを作成できました。 のコンストラクタでキャプチャし、それを必要とするすべての場所で から取得します。これは事実上、Stephen Cleary が彼の回答で示唆したことです。PerResolveLifetimeManagerWcfOperationContextRealService
WcfOperationContextOperationContext.CurrentIWcfOperationContext

于 2012-10-28T12:39:16.810 に答える
-2

更新: 以下のコメントで指摘されているように、このソリューションはスレッドセーフではないため、上記のソリューションが依然として最善の方法であると思います。

HttpContext を DI コンテナー (Application_BeginRequest) に登録することで問題を回避し、必要に応じて解決します。

登録:

this.UnityContainer.RegisterInstance<HttpContextBase>(new HttpContextWrapper(HttpContext.Current));

解決:

var context = Dependencies.ResolveInstance<HttpContextBase>();
于 2016-04-28T02:55:12.203 に答える