我正在使用ASP.NET MVC 3。 一旦我决定将我的一些同步动作改为异步动作。在此之前,我创建了一个示例异步操作来测试它是否能正常工作。它是这样的:
public void SampleAsync()
{
AsyncManager.OutstandingOperations.Increment();
var task = System.Threading.Tasks.Task.Factory.StartNew(() => DoStuff());
task.ContinueWith(t =>
{
AsyncManager.Parameters["pars"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
}
private object DoStuff()
{
System.Threading.Thread.Sleep(20000);
return null;
}
public ActionResult SampleCompleted(object pars)
{
return View();
}
但是这个动作并不是异步工作的!这绝对是同步的。至少,它阻止了其他请求(在运行时)作为传统操作。经过几个小时的调查后,我发现问题出在我的asax中,我在初始化当前的文化:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
CultureInfo ci;
//It's important to check whether session object is ready
if (HttpContext.Current.Session != null)
{
ci = (CultureInfo)this.Session["Culture"];
//Checking first if there is no value in session
//and set default language
//this can happen for first user's request
if (ci == null)
{
ci = GetCultureFromCookie();
this.Session["Culture"] = ci;
}
if (ci == null)
{
ci = GetStandardCulture();
this.Session["Culture"] = ci;
}
}
else
{
ci = GetCultureFromCookie();
if (ci == null) ci = GetStandardCulture();
}
//Finally setting culture for each request
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name);
}
当我评论这个方法时,一切都开始工作得很好。我假设问题与从动作完成线程访问HttpContext.Current有关。但在这种情况下,我应该如何初始化用户的当前文化?
答案 0 :(得分:2)
以下问题是:
this.Session["Culture"] = ci;
您正在写入会话。在ASP.NET中,会话不是线程安全的。出于这个原因ASP.NET synchronizes access。这基本上意味着如果你从同一个会话的2个并行请求中找到写入会话的ASP.NET处理程序,ASP.NET将只是顺序执行它们。
别误会我的意思。这并不意味着将依次执行来自2个不同用户的两个并行请求。它们将是完全平行的。我只是假设您对此控制器操作运行了2个并行AJAX请求,并且您在FireBug或其他任何情况下观察到了这种行为。由于2个AJAX请求来自同一个会话,并且由于您写入会话,因此您被破坏,您的请求无法并行执行。
你必须找到另一种处理文化的方法。 Cookie或网址参数(在搜索引擎优化方面更好)是一个不错的选择。而且,由于会话是不好的事情,摆脱它们只会对你的应用程序有益。
在ASP.NET MVC 3中,您可以使用SessionState属性来指示控制器操作将不使用会话,或者它只会从中读取:
[SessionState(SessionStateBehavior.ReadOnly)]
public class FooController: AsyncController
{
}
现在,您可以并行处理来自同一会话的请求。显然,每次尝试写入会话都会引发异常。