Saturday, February 13, 2010

MVC 2.0 Simple Async Index Method Example

I was playing around with the Async controller functionality in MVC 2.0. It took me awhile to understand it, and even longer to realize that most of my problems came from incorrectly naming methods (IndexAsycn and IndexComplete instead of IndexAsync and IndexCompleted.

There are various examples out there already, though not as many as I would think, but DucDigital put me on the right path. This Steve Sanderson post suggests that using the async pattern to deal with concurrent visits doesn't really make sense until you have a great deal of traffic, something most sites will never see. However, I don't think it addresses the much more common, and relevant to smaller sites, issue of multiple blocking synchronous calls in constructing a page (call Steve Sanderson's rss feed, reformat and replace his name with mine, call Scott Guthrie's rss feed, reformat and replace his name with mine, etc., output page. In this scenario the async framework (presumably, I'm too lazy to test at the moment) has a lot to offer.

In any case, here is a very quick implementation calling three rss feeds (not including the scraping and impersonating). This is done in MVC 2.0, using the Home controller only. Nothing changed in the global.cs or any place else. I make no claims as to the efficiency of this code. Only that it works on my machine (thanks Hanselman):

 public class HomeController : AsyncController {


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

            Func doFeedHander1 = GetFeedAsync;
            var feed1 = "http://community.bartdesmet.net/blogs/bart/rss.aspx";
            Func doFeedHander2 = GetFeedAsync;
            var feed2 = "http://feeds.feedburner.com/ScottHanselman";
            Func doFeedHander3 = GetFeedAsync;
            var feed3 = "http://feeds.codethinked.com/codethinked";

            doFeedHander1.BeginInvoke(feed1, ar => {
                var handler = (Func)ar.AsyncState;
                AsyncManager.Parameters["feed1"] = handler.EndInvoke(ar);
                AsyncManager.OutstandingOperations.Decrement();
                }, doFeedHander1);

            doFeedHander2.BeginInvoke(feed2, ar => {
                var handler = (Func)ar.AsyncState;
                AsyncManager.Parameters["feed2"] = handler.EndInvoke(ar);
                AsyncManager.OutstandingOperations.Decrement();
            }, doFeedHander2);

            doFeedHander3.BeginInvoke(feed3, ar => {
                var handler = (Func)ar.AsyncState;
                AsyncManager.Parameters["feed3"] = handler.EndInvoke(ar);
                AsyncManager.OutstandingOperations.Decrement();
            }, doFeedHander3);
          
        }

        public XElement GetFeedAsync(string feedUrl) {
            try {
                return XElement.Load(feedUrl);
            } catch (Exception ex) {
                return null;
            }

        }

        public ActionResult IndexCompleted(XElement feed1, XElement feed2, XElement feed3) {
            ViewData["feed1"] = feed1;
            ViewData["feed2"] = feed2;
            ViewData["feed3"] = feed3;
            return View("index");

        }
}

No comments:

Post a Comment