1

I have a ASP.Net MVC controller and it calls a method that will post a purchase order. However I want the purchase order posting to take place in the background, I don't want the controller to wait for the purchase order to post before returning. The posting takes a long time and there really is nothing the user of the website can do if there is a error, somebody else needs to be alerted.

It seemed like a good case for using the C# await and async functionality, but I am struggling to get it to work. I tried to setup the method that posts the purchase order as a asynchronous method. However I am running into the following problems:

  • The class that has the method that post the purchase order implements a interface. The controller is using the interface and you cannot put async on a method in a interface. So I tried to resolve this by having the method return a Task.
  • The method to post the purchase order is not running asynchronously, it is running synchronously like a normal method.

What am I doing wrong? Here is the code:

public class POReceivingController : Controller
{
    IPOReceivingService poservice;

    public POReceivingController(IPOReceivingService poserviceparm)
    {
        poservice = poserviceparm;
    }

    public ActionResult PostPO(string shipmentid)
    {
        poservice.PostPOAsync(shipmentid);
    }
}

public interface IPOReceivingService
{
    Task PostPOAsync(string shipmentidparm);
}

public class POReceivingService : IPOReceivingService
{
    public async Task PostPOAsync(string shipmentidparm)
    {
        // Code to post PO and alert correct people if there is an error.
    }
}
Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
Eric Maibach
  • 328
  • 3
  • 14
  • 1
    http://stackoverflow.com/a/18509424 – Robert Harvey Jan 23 '14 at 17:49
  • Link provided by @RobertHarvey have explanation why you should not be doing "fire and forget" methods... If you indeed have long running operations you should consider some additional system that would perform operations and let user to track progress/completion separately. – Alexei Levenkov Jan 23 '14 at 17:54
  • Like a Windows Service. – Robert Harvey Jan 23 '14 at 17:54
  • It does sound like I am approaching this the wrong way. I do need to make sure the method completes and does not get killed. I will take a different approach. Thank you for the help. – Eric Maibach Jan 23 '14 at 18:13

2 Answers2

3

As I explain on my blog, async doesn't change the HTTP protocol. Making the controller action async won't cause the response to be sent early.

To do this properly, save the request to a persistent queue (e.g., Azure queue or MSMQ), and have an independent backend (e.g., Azure worker role or Win32 service) that does the processing and failure notificaiton.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
0

You are making this more complicated than it needs to be. If you just want to fire off another thread to do some work for you and not worry about it all you need to do is something list this:

public ActionResult PostPO(string shipmentid)
    {
        Task.Run(() => PostPOAsync(shipmentid));
        Return view();
    }
Jason Roell
  • 6,679
  • 4
  • 21
  • 28