Question

I'm attempting to build a framework for real-time delivery of messages (using MSMQ at the moment) to be displayed on a webpage that will serve as an informational display. As soon as a message lands in the queue, I would like the message to display on the page.

Controller:

public class MessageController : AsyncController
{
    public void IndexAsync()
    {
        AsyncManager.OutstandingOperations.Increment(1);
        Task<string>.Factory.StartNew(() =>
            {
                var queue = new MessageQueue(@".\private$\path-to-queue");
                while (true)
                {
                    var message = string.Empty;
                    var result = queue.BeginReceive();
                    queue.Formatter = new XmlMessageFormatter(new[] {typeof (string)});
                    queue.ReceiveCompleted += delegate(object sender, ReceiveCompletedEventArgs args) { message = args.Message.Body.ToString(); };
                    queue.EndReceive(result);
                    return message;
                }
            }).ContinueWith(t =>
                {
                    AsyncManager.Parameters["message"] = t.Result;
                    AsyncManager.OutstandingOperations.Decrement();
                }
            );
    }

    public JsonResult IndexCompleted(string message)
    {
        return Json(message, JsonRequestBehavior.AllowGet);
    }
}

When I call the action from a browser, the browser waits for a message to show up on the queue. When I add a message onto the queue, the browser continues with the request, but I end up with a blank string instead of the contents of the message.

Alternately, I tried substituting

message = args.Message.Body.ToString();

within the delegate with

return args.Message.Body.ToString();

but I ended up with a compiler error telling me that the return type is void.

Admittedly, I am still very new to delegates, but I'd greatly appreciate a push in the right direction.

Thanks--


Edit 11/25/2012 @ 22:29

I arrived at a working solution... not sure it's the best method, which is why I'm leaving this open for some peer review.

public class MessageController : AsyncController
{
    public void IndexAsync()
    {
        AsyncManager.OutstandingOperations.Increment(1);
        Task<Message>.Factory.StartNew(() =>
            {
                var queue = new MessageQueue(@".\private$\path-to-queue");
                while (true)
                {
                    var result = queue.BeginReceive();
                    queue.Formatter = new XmlMessageFormatter(new[] {typeof (string)});
                    var message = queue.EndReceive(result);
                    return message;
                }
            }).ContinueWith(t =>
                {
                    AsyncManager.Parameters["message"] = t.Result.Body.ToString();
                    AsyncManager.OutstandingOperations.Decrement();
                }
            );
    }

    public JsonResult IndexCompleted(string message)
    {
        return Json(message, JsonRequestBehavior.AllowGet);
    }
}
Was it helpful?

Solution

As stated in edit to original question, I discovered I didn't need the delegate after all:

public class MessageController : AsyncController
{
    public void IndexAsync()
    {
        AsyncManager.OutstandingOperations.Increment(1);
        Task<Message>.Factory.StartNew(() =>
            {
                var queue = new MessageQueue(@".\private$\path-to-queue");
                while (true)
                {
                    var result = queue.BeginReceive();
                    queue.Formatter = new XmlMessageFormatter(new[] {typeof (string)});
                    var message = queue.EndReceive(result);
                    return message;
                }
            }).ContinueWith(t =>
                {
                    AsyncManager.Parameters["message"] = t.Result.Body.ToString();
                    AsyncManager.OutstandingOperations.Decrement();
                }
            );
    }

    public JsonResult IndexCompleted(string message)
    {
        return Json(message, JsonRequestBehavior.AllowGet);
    }
}

One thing I will note, though... I didn't consider that there would be multiple instances of the controller polling the queue for messages, so you end up with a situation where the browser sessions are competing for messages. One browser will get the first message, other browser will get the second, etc. I ended up switching this implementation over to SignalR-- just waiting for the .NET client to move into release phase.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top