我如何调用从一个asp.net一个异步过程使用C#5异步/托管的await模块? [英] How do I call an asynchronous process from an asp.net hosted module using C#5 async / await?
问题描述
我有一个长时间运行的过程,通过南希模块获取的方法调用。而不是让浏览器挂在过程中运行,我想这个调用是异步的,换句话说,我想Get方法马上返回并保持长期运行过程中做的事情。然后我可以检查定期的过程中的地位和采取相应的行动。
我是新来的异步/等待的C#5的功能,但我确信,这些都是为了只是这样的任务。下面的code显示了我的尝试。我已经把一些日志记录,以证明如预期它不是异步运行。相反,长时间运行的进程块Get方法等浏览器挂起。
模块
公共类TestModule:NancyModule
{
公共TestModule(ITestService TestService的)
{
获得[/ longprocess] = _ =>
{
Log.Write(模块:启动);
testService.LongProcess();
Log.Write(模块:完成);
返回的HTTPStatus code.OK;
};
}
}
服务
公共接口ITestService
{
任务<布尔> LongProcess();
}公共类TestService的:ITestService
{
公共异步任务<布尔> LongProcess()
{
等待LongProcessAsynch();
返回true;
} 私人任务<布尔> LongProcessAsynch()
{
Log.Write(LongProcess:启动);
Thread.sleep代码(5000);
//Task.Delay(5000); < - 有相同的效果
Log.Write(LongProcess:完成);
返回true.AsTask();
}
}
扩展方法
公共静态任务< T> AsTask< T>(这件T候选人)
{
无功源=新TaskCompletionSource< T>();
source.SetResult(候选人);
返回source.Task;
}
日志输出
14/06/2012 19时22分29秒:模块:开始
14/06/2012 19时22分29秒:LongProcess:开始
14/06/2012 19时22分34秒:LongProcess:完成
14/06/2012 19时22分34秒:模块:完成
您可以从日志输出上面看到 LongProcess()
挡住了获取模块的回报。如果任务异步运行我希望在日志中看起来像这样:
预计登录
模块:启动
LongProcess:启动
模块:完成
LongProcess:完成
我觉得什么是真正需要的是把等待
在NancyModule获取方法。像下面也许是code的东西,但我不能这样做,因为我不能标记模块构造为 asnyc
,所以我不能使用的await
Get方法中(或因此我认为当前)
获取[/ longprocess] = _ =>
{
Log.Write(模块:启动);
等待testService.LongProcess();
Log.Write(模块:完成);
返回的HTTPStatus code.OK;
};
感谢您的帮助,实例或指针资源。
修改1
更多的研究表明,asp.net似乎在默认情况下,积极prevent 异步
调用。事做与会话
并处理非UI线程我相信的样子。所以我增加了以下到我的web.config(见下文)
- UseTaskFriendlySynchronizationContext
- ENABLESESSIONSTATE =FALSE
不幸的是,没有任何区别,我的异步
/ 等待
来电 LongProcess ()
仍然阻塞。
<结构>
<&的appSettings GT;
<添加键=ASPNET:UseTaskFriendlySynchronizationContextVALUE =真/>
<添加键=网页:启用VALUE =FALSE/>
< /的appSettings>
<&的System.Web GT;
<的httpRuntime targetFramework =4.5/>
<页面controlRenderingCompatibilityVersion =4.0ENABLESESSIONSTATE =FALSE/>
...更多配置
< /结构>
我是新来的异步/等待的C#5的功能,但我确信,这些都是为了只是这样的任务。
块引用>没有。
异步
/等待
目的是为了使异步编程方便的单个进程的上下文中的。他们不改变HTTP通信的性质。当您使用
等待
的ASP.NET服务器(HTTP请求的情况下),你的ASP.NET线程返回线程池。但是,ASP.NET意识到该HTTP请求还没有完成,因此它不会完成向客户端(浏览器)的响应。这是由设计。
您需要使用AJAX,SignalR,或一些其他的解决方案,以你想要的东西。
I have a long running process that is called via a Nancy Module Get method. Rather than have the browser hang while the process runs I would like this call to be asynchronous, in other words I want the Get method to return right away and leave the long running process to do its thing. I could then check the status of the process at regular intervals and act accordingly.
I am new to the async / await features of C#5 but I feel sure these are meant for just this kind of task. The code below shows my attempt. I have put in some Logging that demonstrates that it is not running asynchronously as expected. Instead the long running process blocks the Get method and so the browser hangs.
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
You can see from the Log Output above that the
LongProcess()
is blocking the return of the Get module. If the task was running asynchronously I would expect the log to look something like this:Expected Log
Module : Start LongProcess : Start Module : Finish LongProcess : Finish
I think what is actually required is to put the
await
in the NancyModule Get method. Something like the code below perhaps, but I cannot do this because I cannot mark the module constructor asasnyc
and so I cannot useawait
within the Get method (or so I currently believe)Get["/longprocess"] = _ => { Log.Write("Module : Start"); await testService.LongProcess(); Log.Write("Module : Finish"); return HttpStatusCode.OK; };
Thanks for any help, examples or pointers to resources.
Edit 1
More research reveals that asp.net seems to actively prevent
async
calls by default. Something to do with theSession
and the way it processes non UI threads I believe. So I have added the following to my web.config (see below)
- UseTaskFriendlySynchronizationContext
- enableSessionState="false"
Unfortunately it does not make any difference and my
async
/await
call toLongProcess()
is still blocking.<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>
解决方案I am new to the async / await features of C#5 but I feel sure these are meant for just this kind of task.
No.
async
/await
are intended to make asynchronous programming easy within the context of a single process. They do not change the nature of HTTP communications.When you use
await
on an ASP.NET server (in the context of an HTTP request), you are returning the ASP.NET thread to the thread pool. However, ASP.NET is aware that the HTTP request has not completed, so it does not complete the response to the client (browser).This is by design.
You'll need to use AJAX, SignalR, or some other solution in order to do what you want.
这篇关于我如何调用从一个asp.net一个异步过程使用C#5异步/托管的await模块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!