异步WebApi线程.CurrentCulture

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

我希望有多语言错误消息,因此我使用资源文件和基本控制器,将线程.CurrentCulture线程.CurrentUICulture设置为请求的接受语言

公共覆盖任务<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(语言);
Thread.CurrentThread.CurrentCulture=区域性;
Thread.CurrentThread.CurrentUICulture=区域性;
}
base.ExecuteAsync(controllerContext,cancellationToken);
}

这一切都很好,但如果我将我的控制器方法设置为异步,问题就会出现

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

这里有一个我用来发现这个问题的小例子

公共异步任务<HttpResponseMessage>PostData(MyData数据)
{
Thread currentThread=Thread.currentThread;
等待某事;
if(Thread.CurrentThread.CurrentCulture!=CurrentThread.CurrentCulture)
Debugger.Break();
}

我并不总是打断调试器。打断行,但大多数时候我会这样做

下面是一个我实际使用资源文件的示例

公共异步任务<HttpResponseMessage>后期数据(MyData数据)
{
//在此之前,如果我在正确的线程和有正确的文化
if(等待此消息。\u myDataValidator.Validate(数据)==false)
//然而,我可能在这里的另一个线程,所以我有错误的文化
抛出新的InvalidMyDataException();
}
公共类InvalidMyDataException:异常
{
public InvalidMyDataException()
//在这里,我访问我的资源文件,并希望根据当前区域性获取错误消息,这可能是错误的
:base(ExceptionMessages.InvalidMyData除外)
{
}
}

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

因此,在我使用文化之前,总是将其设置为正确的,这将是很多代码

正如Joe所指出的,文化是通过ASP.NET中的HttpContext传递的。ASP.NET实现这一点的方法是在请求启动时安装SynchronizationContext,该上下文还用于恢复异步方法(默认情况下)

因此,有两种方法可以解决这个问题:您可以编写自己的SynchronizationContext,默认情况下保留区域性,也可以跨每个wait显式保留区域性

要在每个wait中保留区域性,可以使用Stephen Toub的代码:

公共静态文化区(此任务)
{ 
返回新的CultureAserver(任务);
}
公共类文化服务员:INotifyCompletion
{ 
私有只读任务等待器m_等待器;
私人文化信息m_文化;
公共文化服务员(任务)
{ 
如果(task==null)抛出新的ArgumentNullException(“task”);
m_waiter=task.getwaiter();
}
public CultureAwer GetWaiter(){返回此;}
公共bool已完成{get{return m_waiter.IsCompleted;}
未完成公共作废(行动继续)
{ 
m_culture=Thread.CurrentThread.currentCulture;
m_等待者未完成(续);
}
public void GetResult()
{ 
Thread.CurrentThread.CurrentCulture=m_culture;
m_waiter.GetResult();
} 
}

SynchronizationContext方法更为复杂,但一旦设置好,它将更易于使用。我不知道有什么类似ASP.NET的上下文的好例子,但我的MSDN文章是一个很好的起点

发表评论