How do I call an asynchronous process from an asp.net hosted module using C#5 async / await?

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>

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 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.

Method 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


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x