I have a self-hosted OWIN hosted Web API project providing some basic REST methods for me.
I want to have multilingual error messages, so I use Resource files and a BaseController that sets the Thread.CurrentCulture and Thread.CurrentUICulture to the Accept-Language header of the request.
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);
}
That all works nice, but the problem appears if I make my controller methods async.
When I use await in the method, it might continue in another thread, and so my CurrentCulture and CurrentUICulture are lost.
Here's an little example I used to find this issue.
public async Task<HttpResponseMessage> PostData(MyData data)
{
Thread currentThread = Thread.CurrentThread;
await SomeThing();
if (Thread.CurrentThread.CurrentCulture != currentThread.CurrentCulture)
Debugger.Break();
}
I don't always break in the Debugger.Break line, but most of the time I do.
Here's an example where I actually use my Resource File.
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)
{
}
}
Some additional information: I have a whole bunch of exceptions like this, and they all get caught in an custom ExceptionFilterAttribute which then creates the response.
So it would be much code to always set the culture right before I use it.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…