问题
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 as asnyc
and so I cannot use await
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 the Session
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 to LongProcess()
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>
回答1:
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.
回答2:
try setting the page attribute Async="true"
in the aspx page
after doing that it wold look like this
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="XXX.aspx.cs" Inherits="xxx" Async="true" %>
the in tcode behile file you can make the tasks and methods of type async and calll await
tasks from them ...
it might work
来源:https://stackoverflow.com/questions/11039411/how-do-i-call-an-asynchronous-process-from-an-asp-net-hosted-module-using-c5-as