我有一个通过 Nancy Module Get 方法调用的长时间运行的进程。我希望这个调用是异步的,而不是让浏览器在进程运行时挂起,换句话说,我希望 Get 方法立即返回并让长时间运行的进程去做它的事情。然后,我可以定期检查流程的状态并采取相应措施。
我是 C#5 的 async / await 特性的新手,但我确信这些特性仅用于此类任务。下面的代码显示了我的尝试。我已经添加了一些日志记录,证明它没有按预期异步运行。相反,长时间运行的进程会阻止 Get 方法,因此浏览器会挂起。
模块
public class TestModule : NancyModule
{
public TestModule(ITestService testService)
{
Get["/longprocess"] = _ =>
{
Log.Write("Module : Start");
testService.LongProcess();
Log.Write("Module : Finish");
return HttpStatusCode.OK;
};
}
}
服务
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();
}
}
扩展方法
public static Task<T> AsTask<T>(this T candidate)
{
var source = new TaskCompletionSource<T>();
source.SetResult(candidate);
return source.Task;
}
日志输出
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 模块的返回。如果任务异步运行,我希望日志看起来像这样:
预期日志
Module : Start
LongProcess : Start
Module : Finish
LongProcess : Finish
我认为实际需要的是把await
NancyModule Get 方法。可能类似于下面的代码,但我不能这样做,因为我不能将模块构造函数标记为asnyc
,所以我不能await
在 Get 方法中使用(或者我目前相信)
Get["/longprocess"] = _ =>
{
Log.Write("Module : Start");
await testService.LongProcess();
Log.Write("Module : Finish");
return HttpStatusCode.OK;
};
感谢您提供任何帮助、示例或资源指针。
编辑 1
更多研究表明,async
默认情况下,asp.net 似乎会主动阻止调用。我相信这与Session
它处理非 UI 线程的方式有关。所以我在我的 web.config 中添加了以下内容(见下文)
- 使用TaskFriendlySynchronizationContext
- enableSessionState="假"
不幸的是,它没有任何区别,我的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>