An example of using Dynamic objects in your Razor views

@JohnBubriski posted a blog post that got me thinking of how the DynamicObject class, and a little elbow grease, can add some elegance to your MVC views.


Written on Thursday, November 10, 2011 by

My good friend @JohnBubriski put up a great post on his blog where he talks about accessing url route params in your MVC views.

John made a really good solution by adding an extension method to the HtmlHelper class which would return the {id} route param. This solution is simple, any developer can understand it at a glance, but I thought I would show how you might use DynamicObject and the features of .Net 4.0 to solve this problem.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Dynamic;

namespace System.Web.Mvc {

    public class DynamicUrlAccessor : DynamicObject {
        private ViewContext _context;
        
        public DynamicUrlAccessor(ViewContext context) {
            _context = context;
        }
        
        public override bool TryInvokeMember(
                InvokeMemberBinder binder, 
                object[] args, 
                out object result) {

            if (_context.RouteData.Values.ContainsKey(binder.Name)) {
                result = _context.RouteData.Values[binder.Name].ToString();
                return true;
            }

            // the dirty way too
            var querystring = HttpContext.Current.Request.QueryString;
            if (querystring.AllKeys.Contains(binder.Name)) {
                result = querystring[binder.Name].ToString();
                return true;
            }
            
            return base.TryInvokeMember(binder, args, out result);
        }
    }

    public static class ContextExtensions {

        public static dynamic RouteInfo(this System.Web.Mvc.HtmlHelper helper) {
            var accessor = new DynamicUrlAccessor(helper.ViewContext);
            return accessor;
        }
    }
}

Now you can use this code in your view like so:


<h2>About</h2>
<p>
     Hello @Html.RouteInfo().name()! You are in the @Html.RouteInfo().action() action, 
which is located in the @Html.RouteInfo().controller() controller.
</p>

When the RouteInfo() method is called our DynamicUrlAccessor object is retuned as a dynamic. This in turn will cause our overridden method TryInvokeMember to be called.

The binder object will contain the name of the method that was invoked, any arguments passed will be in the args[] collection. All we need to do at this point is check whether the ViewContext or the QueryString contains the requested parameter and set its value into the result variable.

So hopefully this shows you how a little work with DynamicObject can go a long way towards improving code readability and creating elegant solutions.

Back

Let's talk about this

 


The opinions expressed herein are my own and do not represent my employer's view in any way.


Creative Commons License