c# - 异步 WebApi Thread.CurrentCulture

标签 c# multithreading asynchronous asp.net-web-api culture

我有一个自托管的 OWIN 托管 Web API 项目,为我提供了一些基本的 REST 方法。

我想要多语言错误消息,所以我使用 Resource 文件和一个设置 Thread.CurrentCultureBaseController Thread.CurrentUICulture 到请求的 Accept-Language header 。

public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
{
    if (controllerContext.Request.Headers.AcceptLanguage != null && 
        controllerContext.Request.Headers.AcceptLanguage.Count > 0)
    {
        string language = controllerContext.Request.Headers.AcceptLanguage.First().Value;
        var culture = CultureInfo.CreateSpecificCulture(language);

        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = culture;
    }

    base.ExecuteAsync(controllerContext, cancellationToken);
}

一切正常,但如果我使我的 Controller 方法异步,问题就会出现。

当我在方法中使用 await 时,它可能会在另一个线程中继续,因此我的 CurrentCultureCurrentUICulture 丢失了。

这是我用来发现这个问题的一个小例子。

public async Task<HttpResponseMessage> PostData(MyData data)
{
    Thread currentThread = Thread.CurrentThread;

    await SomeThing();

    if (Thread.CurrentThread.CurrentCulture != currentThread.CurrentCulture)
        Debugger.Break();
}

我并不总是在 Debugger.Break 行中断,但大多数时候我会中断。

这是我实际使用我的资源文件的示例。

public async Task<HttpResponseMessage> PostMyData(MyData data)
{
    //Before this if I'm in the correct thread and have the correct cultures
    if (await this._myDataValidator.Validate(data) == false)
        //However, I might be in another thread here, so I have the wrong cultures
        throw new InvalidMyDataException(); 
}

public class InvalidMyDataException : Exception
{
    public InvalidMyDataException()
        //Here I access my resource file and want to get the error message depending on the current culture, which might be wrong
        : base(ExceptionMessages.InvalidMyData) 
    {

    }
}

一些额外的信息:我有一大堆这样的异常,它们都被捕获在一个自定义的 ExceptionFilterAttribute 中,然后创建响应。

因此,在我使用它之前总是设置正确的文化会是很多代码。

最佳答案

正如 Joe 所指出的,文化是由 ASP.NET 中的 HttpContext 传递的。 ASP.NET 执行此操作的方法是在请求开始时安装 SynchronizationContext,并且该上下文还用于恢复异步方法(默认情况下)。

因此,有几种方法可以解决这个问题:您可以编写自己的 SynchronizationContext 来默认保留文化,或者您可以在每个 await 中显式保留文化

要在每次 await 时保留文化,您可以使用代码 from Stephen Toub :

public static CultureAwaiter WithCulture(this Task task) 
{ 
    return new CultureAwaiter(task); 
}

public class CultureAwaiter : INotifyCompletion
{ 
    private readonly TaskAwaiter m_awaiter; 
    private CultureInfo m_culture;

    public CultureAwaiter(Task task) 
    { 
        if (task == null) throw new ArgumentNullException("task"); 
        m_awaiter = task.GetAwaiter(); 
    }

    public CultureAwaiter GetAwaiter() { return this; }

    public bool IsCompleted { get { return m_awaiter.IsCompleted; } }

    public void OnCompleted(Action continuation) 
    { 
        m_culture = Thread.CurrentThread.CurentCulture; 
        m_awaiter.OnCompleted(continuation); 
    }

    public void GetResult() 
    { 
        Thread.CurrentThread.CurrentCulture = m_culture; 
        m_awaiter.GetResult(); 
    } 
}

SynchronizationContext 方法更复杂,但一旦设置好,使用起来会更容易。我不知道类似 ASP.NET 上下文的好例子,但一个好的起点是 my MSDN article .

关于c# - 异步 WebApi Thread.CurrentCulture,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20601578/

相关文章:

node.js - 运行 npm install 时出错 : No compatible version found: async

c# - 当继承类型具有不同的类型参数时,声明泛型基类型的变量

c# - 从其子类初始化 C# Tuple<T, T> 以便在 WPF 中使用

c# - 追加和读取文本文件

java - 延迟一段时间后执行任务,如果遇到无限循环则停止它

node.js - 如何使 Node fs 与类异步/等待?

c# - 如何以 wpf 样式绑定(bind)按钮命令

java - 并发 hashmap 同时插入

java - 如何在主 UI 线程之外运行 TimerTask?

在 Shiny 的应用程序中异步渲染绘图