ASP.NET MVC2 Может ли AsyncController получить доступ к HttpContext.Current? - PullRequest
2 голосов
/ 20 февраля 2011

Я пытаюсь преобразовать этот метод ExportTo3rdParty() для использования AsyncController:

public JsonResult SaveSalesInvoice(SalesInvoice invoice)
{
    SaveInvoiceToDatabase(invoice); // this is very quick 
    ExportTo3rdParty(invoice); // this is very slow and should be async
}

Но метод ExportTo3rdParty () использует HttpContext.Current в нескольких местах (слишком много, чтобы изменить - оригиналкодер не использовал достаточно инъекций зависимости).Например, он вызывает GetDefaultCurrency ().Будет ли это работать, когда ExportTo3rdParty () вызывается через AsyncController?

public Currency GetDefaultCurrency()
{
    Currency currency;
    string key = string.Format("DefaultCurrency_{0}", 
                                HttpContext.Current.User.Identity.Name);
    currency = HttpRuntime.Cache.Get(key) as Currency;
    if (currency == null)
    {
        currency = LookupDefaultCurrency();
        HttpRuntime.Cache[key] = currency;
    }
} 

Я знаю, что если я использую Thread.Start, я не могу получить доступ к HttpContext.Current.Но как насчет AsyncController?

1 Ответ

5 голосов
/ 20 февраля 2011

Итак, позвольте мне спросить вас, почему вы хотите использовать контроллер Async?

Как вы думаете, это будет быстрее?То, что это медленно, не означает, что вам нужно сделать это асинхронным.Фактически, вы, скорее всего, обнаружите, что метод работает медленнее при асинхронном запуске из-за накладных расходов на управление потоками / переключение контекста.

Из того, что я могу понять из двух методов, которые вы показали, я мало что могу понять.Я предполагаю, что ExportTo3Party можно сделать «вне диапазона».Это внешним процессом.То, что вы должны сделать, это либо использовать MSMQ, чтобы поставить задачу в очередь (она сразу возвращается), чтобы она не блокировалась.И еще какой-нибудь процесс / приложение обрабатывает поставленные в очередь задания.Этот другой процесс может быть обычным консольным приложением, которое продолжает работать на сервере (с помощью Task Sheduler), и оно просто обрабатывает задания, как только они поступают в очередь.

Или даже проще (если вы этого не сделали)используется MSMQ), просто запустите внешнее приложение (снова консольное приложение) и не ждите выхода приложения.Таким образом, вы можете использовать System.Diagnostics.Process, чтобы запустить процесс, а не WaitForExit.

Обе эти альтернативы являются правильным / лучшим способом реализовать то, что, по моему мнению, делает ExportTo3rdParty.Если вы не ожидаете ответа от этого метода, не возвращайте его.

Если я вас еще не убедил, то:

Из документации MSDN

Если метод асинхронного действия вызывает службу, которая предоставляет методы с использованием шаблона BeginMethod / EndMethod, метод обратного вызова (то есть метод, передаваемый в качестве параметра асинхронного обратного вызова методу Begin) может выполняться в потоке, который являетсяне под контролем ASP.NET.В этом случае HttpContext.Current будет нулевым, и приложение может столкнуться с условиями гонки, когда оно обращается к членам класса AsyncManager, таким как Параметры.Чтобы убедиться, что у вас есть доступ к экземпляру HttpContext.Current и чтобы избежать условия гонки, вы можете восстановить HttpContext.Current, вызвав Sync () из метода обратного вызова.

Если обратный вызов завершается синхронно, обратный вызовбудет выполняться в потоке, который находится под контролем ASP.NET, и операции будут сериализованы, поэтому проблем с параллелизмом не возникнет.Вызов Sync () из потока, который уже находится под управлением ASP.NET, имеет неопределенное поведение.

Метод ActionCompleted всегда будет вызываться в потоке, который находится под управлением ASP.NET.Поэтому не вызывайте fSync () из этого метода.

Обратный вызов, который вы передаете методу Begin, может быть вызван с использованием потока, находящегося под управлением ASP.NET.Поэтому вы должны проверить это условие, прежде чем вызывать Sync ().Если операция завершена синхронно (то есть, если CompletedSynchronously имеет значение true), обратный вызов выполняется в исходном потоке, и вам не нужно вызывать Sync ().Если операция завершилась асинхронно (т. Е. CompletedSynchronously имеет значение false), обратный вызов выполняется в пуле потоков или в потоке порта завершения ввода-вывода, и необходимо вызвать Sync ().

http://msdn.microsoft.com/en-us/library/ee728598.aspx

...