Как я могу вызвать асинхронный процесс из размещенного модуля asp.net, используя C # 5 async / await?
У меня есть длительный процесс, который вызывается с помощью метода Get модуля Nancy. Вместо того, чтобы браузер зависал во время работы процесса, я хотел бы, чтобы этот вызов был асинхронным, другими словами, я хочу, чтобы метод Get сразу возвращался и оставлял длительно работающий процесс на свое место. Затем я мог бы регулярно проверять состояние процесса и действовать соответствующим образом.
Я новичок в асинхронных / ожидающих функциях C # 5, но я уверен, что они предназначены именно для такого рода задач. Код ниже показывает мою попытку. Я вставил некоторые записи, которые демонстрируют, что он не работает асинхронно, как ожидалось. Вместо этого длительный процесс блокирует метод Get и браузер зависает.
Module
public class TestModule : NancyModule
{
public TestModule(ITestService testService)
{
Get["/longprocess"] = _ =>
{
Log.Write("Module : Start");
testService.LongProcess();
Log.Write("Module : Finish");
return HttpStatusCode.OK;
};
}
}
Service
public interface ITestService
{
Task<bool> LongProcess();
}
public class TestService : ITestService
{
public async Task<bool> LongProcess()
{
await LongProcessAsynch();
return true;
}
private Task<bool> LongProcessAsynch()
{
Log.Write("LongProcess : Start");
Thread.Sleep(5000);
//Task.Delay(5000); <- Has same effect
Log.Write("LongProcess : Finish");
return true.AsTask();
}
}
Extension Method
public static Task<T> AsTask<T>(this T candidate)
{
var source = new TaskCompletionSource<T>();
source.SetResult(candidate);
return source.Task;
}
Log Output
14/06/2012 19:22:29 : Module : Start
14/06/2012 19:22:29 : LongProcess : Start
14/06/2012 19:22:34 : LongProcess : Finish
14/06/2012 19:22:34 : Module : Finish
Вы можете видеть из выхода журнала выше, чтоLongProcess()
блокирует возврат модуля Get. Если бы задача выполнялась асинхронно, я бы ожидал, что журнал будет выглядеть примерно так:
Expected Log
Module : Start
LongProcess : Start
Module : Finish
LongProcess : Finish
Я думаю, что на самом деле требуется поставитьawait
в методе Get NancyModule. Возможно, что-то вроде приведенного ниже кода, но я не могу сделать это, потому что я не могу пометить конструктор модуля какasnyc
и поэтому я не могу использоватьawait
в методе Get (или так в настоящее время я верю)
Get["/longprocess"] = _ =>
{
Log.Write("Module : Start");
await testService.LongProcess();
Log.Write("Module : Finish");
return HttpStatusCode.OK;
};
Спасибо за любую помощь, примеры или указатели на ресурсы.
Edit 1
Дополнительные исследования показывают, что asp.net активно предотвращаетasync
звонки по умолчанию. Что-то делать сSession
и то, как он обрабатывает не потоки пользовательского интерфейса, я верю. Поэтому я добавил следующее в мой web.config (см. Ниже)
К сожалению, это не имеет никакого значения, и мойasync
/ await
позвонитьLongProcess()
все еще блокирует
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
<add key="webPages:Enabled" value="false" />
</appSettings>
<system.web>
<httpRuntime targetFramework="4.5"/>
<pages controlRenderingCompatibilityVersion="4.0" enableSessionState="false" />
... more config
</configuration>