Асинхронный контроллер блокирует запросы в ASP.NET MVC через jQuery

Я только начал использовать AsyncController в своем проекте, чтобы позаботиться о некоторых длительных отчетах. Казалось бы идеальным в то время, когда я мог бы начать отчет, а затем выполнить несколько других действий, ожидая его возвращения и заполнения элементов на экране.

Мой контроллер выглядит примерно так. Я попытался использовать поток для выполнения длинной задачи, которую, я надеялся, высвободил бы контроллер, чтобы получить больше запросов:

public class ReportsController : AsyncController
{
    public void LongRunningActionAsync()
    {
        AsyncManager.OutstandingOperations.Increment();

        var newThread = new Thread(LongTask);
        newThread.Start();
    }

    private void LongTask()
    {
        // Do something that takes a really long time
        //.......

        AsyncManager.OutstandingOperations.Decrement();
    }

    public ActionResult LongRunningActionCompleted(string message)
    {
        // Set some data up on the view or something...

        return View();
    }

    public JsonResult AnotherControllerAction()
    {
        // Do a quick task...

        return Json("...");
    }
}

Но то, что я нахожу, заключается в том, что когда я вызываю LongRunningAction с помощью jQuery ajax-запроса, любые последующие запросы, которые я делаю после этого, поддерживают его и не обрабатываются до завершения LongRunningAction. Например, вызовите LongRunningAction, который занимает 10 секунд, а затем вызывает AnotherControllerAction, который меньше секунды. AnotherControllerAction просто ждет завершения LongRunningAction перед возвратом результата.

Я также проверил код jQuery, но это все равно, если я специально установил "async: true":

$.ajax({
    async: true,
    type: "POST",
    url: "/Reports.aspx/LongRunningAction",
    dataType: "html",
    success: function(data, textStatus, XMLHttpRequest) { 
           // ...
        },
    error: function(XMLHttpRequest, textStatus, errorThrown) { 
       // ...
    }
});

В настоящий момент я просто должен предположить, что я использую его неправильно, но я надеюсь, что один из вас, ребята, сможет очистить мой ментальный блок!

Ответ 1

Здесь есть две проблемы. Во-первых, ваш контроллер не является асинхронным. Скручивание потока ThreadPool для выполнения работы обычно имеет худшие характеристики производительности, чем просто выполнение всего из самого метода действия, поскольку вы все еще берете ресурсы ThreadPool из ASP.NET(который просто использует CLR ThreadPool), и вы сейчас заставляя CLR и ОС манипулировать потоками. Подробнее см. http://msdn.microsoft.com/en-us/library/ee728598.aspx#choosing_synchronous_or_asynchronous_action_methods. В основном, эта связь сводится к тому, что если вы не можете использовать порты завершения ввода-вывода для своих асинхронных операций, вы вряд ли увидите улучшенную производительность.

Вторая проблема заключается в том, что ASP.NET MVC выполняет блокировку сеанса для всех запросов. Несколько запросов в течение одного сеанса всегда будут сериализованы, так как в противном случае пользовательский сеанс может стать поврежденным, если один контроллер записывает на сеанс, поскольку другой контроллер пытается его прочитать. См. http://forums.asp.net/t/1501623.aspx для контекста и обходной путь. MVC 2 Futures имеет способ отключить этот замок; он также может быть включен в MVC 3. Подробнее см. https://blogs.msdn.com/b/rickandy/archive/2009/12/17/session-less-mvc-controller.aspx.

Ответ 2

По сути проблема заключается в этом. HttpContext.Session, потому что он заблокирован, если вы пишете что-либо на сеанс в вашем AsyncController, вам следует избегать его и использовать this.HttpContext.Application - это решит проблему, У меня была та же проблема, и попробуйте нас