I CAN HAS CODE?!?

Archive for May, 2009

Code Quickie : ExtJS JsonReader With Mapping Support For Use In AIR

Wednesday, May 20th, 2009

So, yesterday I decided to play around with Adobe AIR, which I’m not familiar with, in conjunction with Ext JS, which I am familiar with.  Overall, if you are familiar with Ext JS on the web, you’re familiar with it in Adobe AIR … except for a number of unique issues due to Adobe AIR’s default sandbox, mostly revolving around the sandbox and what you can and can’t do in it.  Well, I ran into an issue tonight where I needed to use a JsonReader and use Record mappings with dot notation (i.e. binding a field to a child object in the JSON data).  My guess is that, as is the case with eval, new Function(…), which is what the default implementation of getJsonAccessor uses, is blocked by the sandbox.  I fixed it by extending the default JsonReader and providing a new implementation of getJsonAccessor using some code I created a while back for form binding in JavaScript.

JsonReader = Ext.extend(Ext.data.JsonReader, {
    exprToPath: function(expr) {
        var parts = expr.split(".");
        var path = [];
        Ext.each(parts, function(item, index, list) {
            var match = item.match(/([a-zA-Z0-9_]+)\[([^\]]+)\]/);
            if (match)
            {
                path.push(match[1]);
                if (/^\d+$/.test(match[2]))
                    path.push(parseInt(match[2]));
                else
                    path.push(match[2]);
            }
            else
            {
                path.push(item);
            }
        });
        return path;
    },  

    getDataValue: function(o, path) {
        var current = o;
        var rPath = path.slice().reverse();
        while (current && rPath.length > 0)
        {
            var key = rPath.pop();
            if (typeof current[key] !== 'undefined') current = current[key]; else return null;
        }

        return current;
    },

    getJsonAccessor: function(expr) {
        var self = this;
        var path = this.exprToPath(expr);
        return function(obj) {
            return self.getDataValue(obj, path);
        };
    }
});

It’s probably a bit of overkill for what is needed, but it does work well.

Simple Ruby on Rails respond_to Functionality In ASP.NET MVC

Monday, May 18th, 2009

In Ruby on Rails (RoR) there is a method on the controller class called respond_to which, simply put, allows one to easily tailor the response format based on the requested mime type format (through the Accept header or as an extension on the URL) of the request.  There are many reasons why you would to do this, but one of the main ones, in my mind, is that you want to have your controllers be able to work with ‘service’ type calls instead of only requests for pages.  The same controller and action could be used to serve up HTML when a normal request comes through, but when a JSON request (i.e. application/json) comes through, instead of using the standard view and layout, only valid JSON data would be returned.

Now there are a number of ways to implement this functionality but I find the RoR method to be quite clean and succinct, and because of that, when I needed to do something similar with ASP.NET MVC, I modeled my approach after RoR’s.  So, without further ado, let’s jump into the code shall we?

I started with a very simple extension method for the HttpRequestBase class that simply checks to see if one or more strings are in the HTTP Accept header.

public static class HttpRequestBaseExtensions
{
    public static bool CanAccept(this HttpRequestBase request, string[] types, bool exact)
    {
        return Array.Exists(
            request.AcceptTypes, 
            a => (a == "*/*" && exact == false) || Array.Exists(
                types, 
                t => t.Equals(a, StringComparison.OrdinalIgnoreCase)
            )
        );
    }
}

Now, there a number of ways to optimize this, but the above is very strait forward and simple.  We iterate over the values in the Accept header, if the header can accept anything, i.e. ‘*/*’, and we don’t need an exact match, we are done and the request can accept the supplied types.  Otherwise, we look over our supplied types, for a matching one.  Easy. 

Since we can now easily check whether or not a given request can accept a supplied type, it’s time to move onto the meat of the code.  Instead of using a strait comparison between the requested and supplied mime types, I opted to use a more extensible approach.  I figure we could make all of our content ‘checks’ predicates so not only could we check for a given mime type, but we could also check to see if the request was an ajax call, or really anything else we want. 

public static class RequestFormat
{        
    public static Predicate<ControllerContext> Html = (c) => 
        c.HttpContext.Request.CanAccept(new [] { "text/html" }, false);
    public static Predicate<ControllerContext> HtmlAsync = (c) => 
        c.HttpContext.Request.CanAccept(new[] { "text/html" }, false) && c.HttpContext.Request.IsAjaxRequest();
    public static Predicate<ControllerContext> Json = (c) => 
        c.HttpContext.Request.CanAccept(new[] { "application/json" }, true);
    public static Predicate<ControllerContext> Xml = (c) => 
        c.HttpContext.Request.CanAccept(new[] { "application/xml" }, true);        
}

I chose to use ControllerContext as the parameter to the predicate instead of HttpRequestBase because by doing so we can access the route values among other things which would let us check for the format in the URL, for example.

public static class RequestExtension
{
    public static Predicate<ControllerContext> Html = (c) => 
        String.IsNullOrEmpty(c.RouteData.Values["format"] as string);
    public static Predicate<ControllerContext> Json = (c) => 
        "json".Equals(c.RouteData.Values["format"] as string, StringComparison.OrdinalIgnoreCase);
    public static Predicate<ControllerContext> Xml = (c) => 
        "xml".Equals(c.RouteData.Values["format"] as string, StringComparison.OrdinalIgnoreCase);
}

Let’s move to the class that does the majority of the work, the RequestFormatResponder.

public class RequestFormatResponder
{
    protected class SupportedFormat
    {
        public Predicate<ControllerContext> Predicate { get; set; }
        public Func<ActionResult> Result { get; set; }
    }

    protected List<SupportedFormat> Supported { get; set; }

    public RequestFormatResponder()
    {
        Supported = new List<SupportedFormat>();
    }

    public Func<ActionResult> this[Predicate<ControllerContext> predicate]
    {
        set { Supported.Add(new SupportedFormat { Predicate = predicate, Result = value }); }
    }

    public ActionResult Respond(ControllerContext context)
    {
        var match = Supported.LastOrDefault(s => s.Predicate(context));

        if (match != null)
            return match.Result();

        return null;
    }

    public Func<ActionResult> Html { set { this[RequestFormat.Html] = value; } }
    public Func<ActionResult> HtmlAsync { set { this[RequestFormat.HtmlAsync] = value; } }
    public Func<ActionResult> Json { set { this[RequestFormat.Json] = value; } }
    public Func<ActionResult> Xml { set { this[RequestFormat.Xml] = value; } }
}  

There’s really not too much to go over.  We have a child class, SupportedFormat, that contains a supplied predicate and function to return an ActionResult, which is the resultant value should a an acceptable match be found.  On top of that, we have a list to store the formats that are acceptable (order is important), we have a couple ways of setting those supported formats, and we have the function that does all of our processing, Respond.  I’ll get to the two ways of setting supported values in a bit, but it is worth noting that the Respond method implies that the order of the supported formats should be least specific to most specific.

Now, we are almost ready to use our nifty new respond_to implementation.  There is only one more thing to do and that is provide our method on the controller.  I prefer to create a controller class which all of my controllers inherit from in an application (called ApplicationController no less … a hold over from my time with RoR) so I’m going to place our very own RespondTo method there.

public class ApplicationController : Controller
{
    protected ActionResult RespondTo(Action<RequestFormatResponder> block)
    {
        var responder = new RequestFormatResponder();

        if (block != null)
            block(responder);

        var result = responder.Respond(ControllerContext);
        if (result != null)
            return result;           

        throw new HttpException(400, "Unable to respond to requested format.");
    }
}

Overall, it’s pretty simple.  We accept a delegate parameter to which we will pass our responder instance.  We create our responder, call the block, and let our responder do its work.  If the result is non null, we return and go about our way, otherwise we through an exception to return an HTTP status code of 400 (bad request) since the request was for a format we don’t support.

It’s now time for the fun part … putting our code to use!  I merely created a basic ASP.NET MVC project for this part.

public class HomeController : ApplicationController
{
    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome to ASP.NET MVC!";

        return RespondTo(format =>
        {
            format.Html = () => View();
            format.Json = () => Json(new { message = "hello world" });              
        });            
    }

    public ActionResult About()
    {
        return RespondTo(format =>
        {
            format[RequestExtension.Html] = () => View();
            format[RequestExtension.Json] = () => Json(new { message = "about" });
        });
    }
}
/* route to support extension based format */
routes.MapRoute(
    "Default-Extension",                                              
    "{controller}/{action}.{format}/{id}",                  
    new { controller = "Home", action = "Index", id = "" }  
);

Bam!  Here you can see we call our RespondTo method and pass in a lambda expression in which we will tell the responder what formats we support.  In the Index action, I’m using the property setters defined at the bottom of our RequestFormatResponder class which, as you can see, look fairly similar to the RoR method.  The only downside is that you have to add all of the formats that you will support to your responder, but in most cases, that won’t be a big deal.  I the About action, instead of using the property setters, we use the index setter.  It’s pretty similar, though not as clean, in my opinion.  However, you don’t need to extend your responder class at all to add more types.  You could even just specify a new predicate right there if you needed to. 

The rest of that code block should be pretty easy to read.  When a request comes in for HTML, we are simply telling it to return our View, and when a request comes in for JSON, we are telling it to return a JSON serialized object.  The reason we have to use the lambda expressions as values instead of the functions themselves is because we don’t want the actual function executed the correct format has been determined.  If we didn’t do this, both View and Json would be executed, and then the correct one to return would be determined. 

Well, there you have it.  Ruby on Rails like respond_to functionality in an ASP.NET MVC world.  We’ve been using this approach in a project at work and, so far, it’s worked out quite well.  I hope you find it just as useful.

What A Long, Strange Trip It’s Been

Sunday, May 17th, 2009

Yes, I just quoted a WoW achievement, and a Grateful Dead song, apparently, but in the span of time since my last post, I do find it oddly fitting, in a good way.  Just what have I been up to you ask?  Well, I’m glad you asked :)   Probably the biggest event was that my wife and I had our first child.  Definitely a life altering an amazing experience that words cannot adequately describe.  In the work sphere, I’ve been taking on a bit more responsibility here and there and have been learning a lot as well.  I’ve become quite well acquainted with Ext JS and jQuery and enjoy working with them both.  Also, I’ve been working a good bit with ASP.NET MVC lately and I’ll definitely say that, overall, I’m impressed with their implementation, though I do still enjoy MonoRail.  On the side, I’ve also been writing an MVC framework for PHP, yes, another one, and it’s been a fun experience.  Look forward to some posts regarding that in the near future … and some on ASP.NET MVC in the immediate future. 

Overall, it’s been a really good 10 months and I’m definitely looking forward to the next 10 months … hopefully with a few more blog posts.