2012-01-20 5 views
1

Я использую 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 из полного потока действий. Но в этом случае, как я должен начать текущую культуру пользователя?

ответ

2

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

this.Session["Culture"] = ci; 

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

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

Вам нужно будет найти другой способ обработки культуры. Параметры cookie или url (лучше с точки зрения SEO) весны на ум как хорошая альтернатива. И так как сеансы плохо, так или иначе, избавление от них будет полезно только для вашего приложения.

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

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

} 

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

+0

Это очень хороший, всеобъемлющий ответ. Спасибо! –

Смежные вопросы