在异步操作中初始化文化完成

时间:2012-01-20 20:51:47

标签: asp.net asp.net-mvc-3 asynchronous localization

我正在使用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有关。但在这种情况下,我应该如何初始化用户的当前文化?

1 个答案:

答案 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
{

}

现在,您可以并行处理来自同一会话的请求。显然,每次尝试写入会话都会引发异常。