0

Hello i'm trying to implement an AsynController,

here is my code:

[NoCache]
public class GraphController : BaseAsyncController
{
    private readonly IReportsRepository _reportsRepository;
    private readonly ISqlQueryRepository _sqlQueryRepository;

    //Background worker
    private readonly BackgroundWorker _worker = new BackgroundWorker();

    public GraphController(ISqlQueryRepository sqlQueryRepository, IReportsRepository reportsRepository)
    {
        _sqlQueryRepository = sqlQueryRepository;
        _reportsRepository = reportsRepository;
    }

    public void Index()
    {
        AsyncManager.OutstandingOperations.Increment();

        _worker.DoWork += (sender, args) =>
        {
            AsyncManager.Parameters["message"] = "hello world";
            Thread.Sleep(3000);
        };

        _worker.RunWorkerCompleted += (sender, args) => AsyncManager.OutstandingOperations.Decrement();
        //run the worker
        _worker.RunWorkerAsync();
    }

    public ActionResult IndexCompleted(string message) //callback not being invoked
    {
        ViewData["message"] = message;
        return View();
    }
}

The question is why the completed callback is not being invoked?

Thanks in advance.

Jacob
  • 3,629
  • 3
  • 36
  • 44
hackp0int
  • 4,052
  • 8
  • 59
  • 95

1 Answers1

4

The name of your action is wrong. It should not be Index. It should be IndexAsync. Take a look at the following article which illustrates the usage of asynchronous controllers in ASP.NET MVC.

Note that BackgroundWorker is a Windows Form component. Don't use WinForms components in ASP.NET applications. They are not designed to be used in server applications. I'd recommend you TPL.

So:

[NoCache]
public class GraphController : BaseAsyncController
{
    private readonly IReportsRepository _reportsRepository;
    private readonly ISqlQueryRepository _sqlQueryRepository;

    public GraphController(ISqlQueryRepository sqlQueryRepository, IReportsRepository reportsRepository)
    {
        _sqlQueryRepository = sqlQueryRepository;
        _reportsRepository = reportsRepository;
    }

    public void IndexAsync()
    {
        AsyncManager.OutstandingOperations.Increment();
        Task.Factory.StartNew(() => 
        {
            // do the work
            Thread.Sleep(3000);

            // the work is finished => pass the results and decrement
            AsyncManager.Parameters["message"] = "hello world";
            AsyncManager.OutstandingOperations.Decrement();
        });
    }

    public ActionResult IndexCompleted(string message)
    {
        ViewData["message"] = message;
        return View();
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    @IamStalker, I'd recommend TPL. Manually spawning threads is never a good idea. It could be quite expensive to spawn a thread. By using TPL you will take better advantage of things like automatic thread pooling, task scheduling and distribution over the different available CPU cores, ... things that you should write hundreds of lines of code to achieve if you manually work with threads. Not to mention the upcoming .NET 4.5 release which is all based upon the concept of tasks. – Darin Dimitrov Mar 14 '12 at 08:00
  • thank you first of all, about the explanation, second i have i might say simple question, "why IndexAsync" does it matter what name of the Action? – hackp0int Mar 14 '12 at 08:04
  • @IamStalker, yes the name matters. You need 2 methods: the first is `XXXAsync` and the second is `XXXCompleted` where `XXX` is the name of your action as you would use in the url to query it: `/graph/xxx`. Please read the article I have linked to in my answer. All this is explained pretty well. – Darin Dimitrov Mar 14 '12 at 08:06