本文介绍了对 WCF 服务的异步调用不会保留 CurrentCulture的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据这个问题 async/await 调用应该保留 CurrentCulture.就我而言,当我调用自己的异步方法时,CurrentCulture 会被保留.但是,如果我调用 WCF 服务的某些方法,则不会保留 CurrentCulture,而是将其更改为类似于服务器默认线程文化的内容.

According to the answer in this question async/await call should preserve CurrentCulture. In my case, when I call my own async methods, the CurrentCulture is preserved. But if I call some method of WCF service, CurrentCulture isn't preserved, it's being changed to something that looks like server's default thread's culture.

我查看了调用的托管线程.它发生这样每一行代码都在单个托管线程上执行(ManagedThreadId 保持不变).在调用我自己的异步方法后,CultureInfo 保持不变.但是当我调用 WCF 的方法时,ManagedTrheadId 保持不变,但 CurrentCulture 发生了变化.

I've looked at what managed threads are invoked. It happens so that every line of code was executed on a single managed thread (ManagedThreadId stays the same). And CultureInfo stays the same after a call to my own async method. But when I call a WCF's method, ManagedTrheadId stays the same, but CurrentCulture is changed.

简化后的代码如下:

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);
}

wcfClient 是自动生成的 WCF 客户端的实例(System.ServiceModel.ClientBase 的继承者)

The wcfClient is an instance of auto generated WCF client (inheritor of System.ServiceModel.ClientBase)

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

This all happens in ASP.NET MVC Web API (self-hosted), I use Accept-Language header to set CurrentCulture to access it later and use it to return localized resources. I could move along without CurrentCulture and just pass CultureInfo to every method, but I don't like this approach.

为什么 CurrentThread 的 CurrentCulture 在调用 WCF 服务后发生变化,而在调用我自己的异步方法后保持不变?可以修复"吗?

Why CurrentThread's CurrentCulture is changed after a call to WCF service and remains the same after a call to my own async method? Can it be "fixed"?

推荐答案

将文化重置为 await 之前的状态通常是同步上下文的工作.但是由于(据我所知),您没有任何同步上下文,await 不会以任何方式修改线程文化.

Resetting culture back to what it was before the await is usually the job of the synchronization context. But since (as far as I understand it), you don't have any synchronization context, the await won't modify the thread culture in any way.

这意味着,如果您在 await 之后回到同一线程,您将看到您设置的文化.但是,如果您在另一个线程上继续,您将看到默认文化(除非其他人也为该线程修改了它).

This means that if you're back on the same thread after await, you're going to see the culture that you set. But if you resume on a different thread, you will see the default culture (unless somebody else modified it for that thread too).

在没有同步上下文的情况下,在 await 之后你什么时候会在同一个线程上?如果异步操作同步完成(如您的 GetIntAsync()),您可以保证在同一线程上,因为在这种情况下,该方法只是在 await.如果幸运的话,您也可以在同一线程上继续,但您不能依赖它.这可能是不确定的,因此您的代码有时似乎可以工作,有时却不能.

When are you going to be on the same thread after an await, when there is no synchronization context? You're guaranteed to be on the same thread if the async operation completes synchronously (like your GetIntAsync()), because in that case, the method just synchronously continues after the await. You can also resume on the same thread if you're lucky, but you can't rely on that. This can be non-deterministic, so your code might seem to work sometimes, and sometimes not.

如果您想使用 await 来传递文化,而您又没有同步上下文为您做这件事,您应该怎么做?基本上,您有两个选择:

What you should do when you want to flow culture with awaits and you don't have a synchronization context that does it for you? Basically, you have two options:

  1. 使用自定义等待程序(请参阅 Stephen Toub 的 WithCulture(),由 Noseratio 链接).这意味着您需要将此添加到所有需要传递文化的 await 中,这可能很麻烦.
  2. 使用自定义同步上下文,该上下文将为每个 await 自动流动文化.这意味着您只能为每个操作设置一次上下文并且它会正常工作(类似于 ASP.NET 同步上下文所做的).从长远来看,这可能是更好的解决方案.
  1. Use a custom awaiter (see Stephen Toub's WithCulture(), as linked by Noseratio). This means that you need to add this to all your awaits where you need to flow the culture, which could be cumbersome.
  2. Use a custom synchronization context that will flow the culture automatically for every await. This means you can set up the context only once for each operation and it will work correctly (similarly to what ASP.NET synchronization context does). This is probably the better solution in the long run.

这篇关于对 WCF 服务的异步调用不会保留 CurrentCulture的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 22:09