对WCF服务的异步调用不会保留CurrentCulture

Dmi*_*nov 6 c# wcf cultureinfo async-await asp.net-web-api

根据这个问题 的答案,async/await调用应该保留CurrentCulture.就我而言,当我调用自己的异步方法时,将保留CurrentCulture.但是,如果我调用某种WCF服务方法,则不会保留CurrentCulture,它会被更改为看起来像服务器默认线程文化的东西.

我已经了解了调用托管线程的内容.它发生在每个代码行都在一个托管线程上执行(ManagedThreadId保持不变).在调用我自己的异步方法后,CultureInfo保持不变.但是当我调用WCF的方法时,ManagedTrheadId保持不变,但CurrentCulture已更改.

简化的代码如下所示::

private async Task Test()
{
    // Befoe this code Thread.CurrentThread.CurrentCulture is "ru-RU", i.e. the default server's culture

    // Here we change current thread's culture to some desired culture, e.g. hu-HU
    Thread.CurrentThread.CurrentCulture = new CultureInfo("hu-HU");

    var intres = await GetIntAsync();
    // after with await Thread.CurrentThread.CurrentCulture is still "hu-HU"

    var wcfres = await wcfClient.GetResultAsync();
    // And here Thread.CurrentThread.CurrentCulture is "ru-RU", i.e. the default server's culture
}


private async Task<int> GetIntAsync()
{
    return await Task.FromResult(1);
}
Run Code Online (Sandbox Code Playgroud)

wcfClient是汽车的一个实例生成WCF客户端(继承的System.ServiceModel.ClientBase)

这一切都发生在ASP.NET MVC Web API(自托管)中,我使用Accept-Language标头将CurrentCulture设置为稍后访问它并使用它来返回本地化资源.我可以在没有CurrentCulture的情况下继续前进,只是将CultureInfo传递给每个方法,但我不喜欢这种方法.

为什么在调用WCF服务后更改CurrentThread的CurrentCulture并在调用我自己的异步方法后保持不变?可以"修复"吗?

nos*_*tio 1

对于为什么会发生所描述的行为,我没有明确的答案,特别是考虑到整个调用链保持在同一线程上(ManagedThreadId保持不变)的声明。此外,我关于文化不随执行环境流动的假设AspNetSynchronizationContext是错误的,事实上,它确实流动。我从@StephenCleary关于尝试的评论中汲取了观点await Task.Delay,并通过以下小研究验证了这一点:

// GET api/values/5
public async Task<string> Get(int id)
{
    // my default culture is en-US
    Log("Get, enter");

    Thread.CurrentThread.CurrentCulture = new CultureInfo("hu-HU");

    Log("Get, before Task.Delay");
    await Task.Delay(200);
    Thread.Sleep(200);

    Log("Get, before Task.Run");
    await Task.Run(() => Thread.Sleep(100));
    Thread.Sleep(200);

    Log("Get, before Task.Yield");
    await Task.Yield();

    Log("Get, before exit");
    return "value";
}

static void Log(string message)
{
    var ctx = SynchronizationContext.Current;
    Debug.Print("{0}; thread: {1}, context: {2}, culture {3}",
        message,
        Thread.CurrentThread.ManagedThreadId,
        ctx != null ? ctx.GetType().Name : String.Empty,
        Thread.CurrentThread.CurrentCulture.Name);
}
Run Code Online (Sandbox Code Playgroud)

输出:

获取、输入;线程:12,上下文:AspNetSynchronizationContext,文化 en-US
获取,在Task.Delay之前;线程:12,上下文:AspNetSynchronizationContext,文化 hu-HU
获取,在Task.Run之前;线程:11,上下文:AspNetSynchronizationContext,文化 hu-HU
获取,在Task.Yield之前;线程:10,上下文:AspNetSynchronizationContext,文化 hu-HU
获取,退出前;线程:11,上下文:AspNetSynchronizationContext,文化 hu-HU

因此,我只能想象里面的某些东西wcfClient.GetResultAsync()实际上改变了当前线程的文化。解决此问题的方法可能是使用像Stephen Toub 那样的CultureAwaiter客户服务员。然而,这种症状令人担忧。也许您应该在生成的 WCF 客户端代理代码中搜索“culture”并检查其中发生的情况。尝试逐步执行并找出何时Thread.CurrentThread.CurrentCulture重置。

  • 该操作是自托管的,因此他没有“AspNetSynchronizationContext”。因此,不应该明确保留文化,但另一方面,我真的很惊讶 WCF 客户端代理正在改变它。 (3认同)