我有一个自托管的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时,它可能会在另一个线程中继续,因此我的CurrentCulture和CurrentUICulture将丢失
这里有一个我用来发现这个问题的小例子
公共异步任务<;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文章是一个很好的起点