10

I have a custom ASP.NET Route that has IO operations in it. For now, assume these IO operations can't be cached (i.e. too big).

In a way I'm looking for a an AsyncRouteBase class with

public async override Task<RouteData> GetRouteDataAsync(HttpContextBase httpContext)
public async override Task<VirtualPathData> GetVirtualPathAsync(RequestContext requestContext, RouteValueDictionary routeValues);
  • Does something similar already exist? (can't find it)
  • Is there any place within the ASP.NET pipeline where I can create this myself?

I'm using ASP.NET MVC 5.2.3.0

Dirk Boer
  • 8,522
  • 13
  • 63
  • 111
  • How long is the IO going to take? If it's quick (likely in routing) then there is no point in using async IO (http://stackoverflow.com/questions/25086866/why-does-the-ef-6-tutorial-use-asychronous-calls/25087273). – usr Jul 18 '15 at 10:00
  • Could be multiple database calls with about 50ms each. – Dirk Boer Jul 18 '15 at 10:19
  • OK, that's probably pointless for async IO. Anyway, good question. – usr Jul 18 '15 at 10:23
  • Thanks. But seriously? I guess I have to investigate further, but 50ms sounds like ages compared to what you can do within that time on a CPU. – Dirk Boer Jul 18 '15 at 10:27
  • 2
    The CPU is not paused during that time. Another thread gets on. Async IO solves memory usage problems due to 1MB stack memory per thread. Also solves thread pool exhaustion which sets in in the hundreds of threads, can be turned off. Maybe you'll find my discussion of these issues enlightening. I bet there's relevant stuff in there that you didn't know yet. Most people don't. – usr Jul 18 '15 at 10:28
  • Thanks, I will look more into your discussions! – Dirk Boer Jul 18 '15 at 10:45
  • Why you don't write an `asynch` Ajax method to show what you want? – Amirhossein Mehrvarzi Jul 24 '15 at 15:03
  • I just want that any IO/db calls during routing don't block a thread :) – Dirk Boer Jul 24 '15 at 15:29
  • Hi sir dirk, I don't know if this helps but, have you tried making this in Threading.Start(method) inside Global.asax event application.start? than of async? just a curious question from your question..peace! – ken lacoste Jul 26 '15 at 08:34

2 Answers2

1

You cannot create AsyncRouteBase, because routes used by ASP.NET MVC are synchronous. You have to understand that in order for you to create async methods, someone must consume them asynchronously, you can't magically make everything asynchronous by adding async method.

Routing can't be asynchronous for various reasons, Routes are cached and are only created once at time of executing first request. Beware, routes are cached, they will not change and they can't be changed in runtime because they are executed first, if Routing will make async db calls, every request will have to wait for Routing condition to fulfill which will slow down entire application.

And you mostly do not need AsyncRouteBase, instead you can create Async Route Handler.

public class AsyncRouteHandler : IRouteHandler
{
    IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
    {
        return new AsyncHttpHandler();
    }
}

public class AsyncHttpHandler : HttpTaskAsyncHandler{
    public override async Task ProcessRequestAsync(HttpContext context)
    {        
    }
}

However, using MVC pipeline inside this will require lots of work, but you can easily ignore that and service your response from here. You can use controller factory inside this and create your methods to execute what you need.

Other alternative is to easily use MEF or other form of DI to manage your larger code base and invoke respective methods inside AsyncHttpHandler.

Akash Kava
  • 39,066
  • 20
  • 121
  • 167
  • Hi Akash, thanks for your answer. Just one note: a custom `RouteBase` isn't cached by default for MVC. How do I know? I make database calls during my (rather) complicated routing :) – Dirk Boer Jul 27 '15 at 14:09
  • About why I want to make it async: same reason why I want to make all my Actions async - so they don't block a thread unnecessary. The request is being stalled anyway (for a few ms) - rather service part of another request in the mean time. – Dirk Boer Jul 27 '15 at 14:12
  • The part with the `HttpTaskAsyncHandler` sounds rather interesting and that it might be the answer - I have to figure out how and if I can implement it within MVC with keeping all the existing behaviour. – Dirk Boer Jul 27 '15 at 14:15
0

Unfortunately, There is no way to override a non async method with an async one. I think your best bet is to have an async non override method and call into that from the non async one like:

public override RouteData GetRouteData(HttpContextBase httpContext) {
    return GetRouteDataAsync(httpContext);
    //return await GetRouteDataAsync(httpContext);
}

public async override Task<RouteData> GetRouteDataAsync(HttpContextBase httpContext){
    //operations here
}

Note: this can cause problems though. If the original code didn't expect for any async code to be executing introducing this pattern could break expectations. Avoid it if possible.

As an advice, See Simplify Asynchronous Programming with Tasks

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70