Инициализация культуры в асинхронном действии завершена - PullRequest
1 голос
/ 21 января 2012

Я использую 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();
    }

Но это действие не работало асинхронно!Это было абсолютно синхронно.По крайней мере, он блокировал другие запросы (во время выполнения) как традиционное действие.После нескольких часов исследования я обнаружил, что проблема была в моем асаксе, где я инициализировал текущую культуру:

    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 Ответ

2 голосов
/ 21 января 2012

Следующая строка является проблемой:

this.Session["Culture"] = ci;

Вы пишете на сессию. В ASP.NET сеанс не является потокобезопасным. По этой причине ASP.NET синхронизирует доступ к нему. В основном это означает, что если вы нажмете обработчик ASP.NET, который выполняет запись в сеанс из 2 параллельных запросов из одного сеанса , ASP.NET просто выполнит их последовательно.

Не пойми меня неправильно. Это не означает, что два параллельных запроса от 2 разных пользователей будут выполняться последовательно. Они будут идеально параллельны. Просто я предполагаю, что вы выполнили 2 параллельных AJAX-запроса к этому действию контроллера и наблюдали за поведением в FireBug или чем-то еще. Поскольку 2 AJAX-запроса были из одного и того же сеанса, и поскольку вы записываете в сеанс, вы попали в очередь, ваши запросы не могут выполняться параллельно.

Вам нужно будет найти другой способ обращения с культурой. Cookies или параметры URL (лучше с точки зрения SEO) приходят на ум в качестве хорошей альтернативы. А поскольку сеансы в любом случае плохие, избавиться от них будет полезно только для вашего приложения.

В ASP.NET MVC 3 вы можете использовать атрибут SessionState, чтобы указать, что действие контроллера либо не будет использовать сессию, либо будет только читать из него:

[SessionState(SessionStateBehavior.ReadOnly)]
public class FooController: AsyncController
{

}

Теперь вы можете выполнять параллельную обработку запросов из одного сеанса. Очевидно, что каждая попытка записи в сеанс вызовет исключение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...