Monday, December 6, 2010

Using AsyncController with NServiceBus

With NServiceBus sometimes you do not want to allow a web request to complete until you have received some response from your message handler. For example, suppose you have defined the following message handler that returns a response code on success:

public class TestMessageHandler :
    IHandleMessages<TestMessage>
{
    public IBus Bus { get; set; }

    public void Handle(TestMessage message)
    {
        //Do something interesting...
        Bus.Return(0);
    }
}

This is a perfect scenario for using the asynchronous page API. It allows you to execute a potentially long-running operation on a separate thread outside of the IIS thread pool. While this thread is executing, the original request thread is returned to the thread pool. As a result, the asynchronous page API is great for I/O bound operations, since you keep threads in the thread pool ready to service requests and the new thread spends most of its time blocked on I/O. NServiceBus supports the asynchronous page API out of the box:

Bus.Send(new TestMessage()).RegisterWebCallback(callback, state);

Unfortunately, RegisterWebCallback does not work with ASP.NET MVC. If you are using ASP.NET MVC, you can use AsyncController, which was introduced in ASP.NET MVC 2. The following code illustrates how you might use AsyncController to wait for a response the message handler:

public class TestController : AsyncController
{
    private IBus bus;

    public TestController(IBus bus)
    {
        this.bus = bus;
    }

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

        bus.Send(new TestMessage()).Register(Callback);
    }
    public ActionResult IndexCompleted()
    {
        return View();
    }
    
    private void Callback(int responseCode)
    {
        AsyncManager.OutstandingOperations.Decrement();
    }
}

As you can see, the AsyncController API is a little awkward (though it is an improvement over the asynchronous page API, in my opinion), but it is a small price to pay for scalability.

5 comments:

  1. Hi,
    I'm trying to do the same but cant make it works.. it executes the Async method, servicebus process the message correctly but it never executes the callback (and the completed method). On top of that, after 3 times IIS app pool crash. Check the event log but nothing relevant in it. Did you have the same problems? are you now using it in production somehow?
    Thanks

    ReplyDelete
  2. Unfortunately, no, I haven't experienced the same problem. Without knowing more specifics, it would be hard to offer any suggestions.

    ReplyDelete
  3. I've partially figured it out.. basically if nservibus and IIS are running under the same account, it works. Otherwise, nservicebus complains it cannot impersonate the sender. I tried different configurations found in Google but even if you try a simple example with console apps running under different windows account, it doesnt work!! I hope is a limitation of the developer edition or I'm doing something wrong.. thank you

    ReplyDelete
  4. Have you tried turning off the impersonate sender setting?

    ReplyDelete
  5. @radafanas @michael I'm hitting exactly the same problem you mentioned. did you find what was going on? (I've tried setting ImpersonateSender to false that doesn't seem to fix it)

    Thanks!

    ReplyDelete