April 19, 2008

Creating Partial Views in ASP.Net MVC

Filed under: HowTo, DotNet, Development, ASP.Net MVC | Lindsay @ 6:56 pm

I have been coming up to speed with ASP.Net MVC recently and I have to say that it makes me very happy, warm and fuzzy. I had been out of the Microsoft camp of web development for almost a year and a half and using Ruby on Rails in the mean time. Now that I’m “back in the saddle again” with Microsoft technologies, I’m ecstatic that I can use ASP.Net without WebForms, Postbacks and ViewState. The MVC framework is so much cleaner and easier to follow in my opinion. Yeah, it might not be popular with a lot of ASP.Net developers because you have to do more HTML from “scratch” and don’t have the crutch of server controls but that gives you so much more control over what’s going on and takes the “magic” out of it. And it’s also much easier to test (TDD, baby!) and debug when you really understand what’s going on under the hood because you wrote the engine.

So anyway, I’m playing with ASP.Net MVC which is still only in a “Preview 2“, meaning there’s lots more to come. But I want to use it now and there was some functionality missing that I really wanted: the ability to render a view in a view, basically to have the ability to do a Rails-style partial view. I figured out a way to do it by creating an extension on the ViewPage class, though there’s a bit of a hack involving getting the view directory route.

using System;
using System.Linq.Expressions;
using System.Web.Mvc;

namespace Lindsay
{
        public static class Extensions
        {
                public static void RenderPartial<T>(this ViewPage vwp, Expression<Action<T>> action) where T : Controller
                {
                    T controller = Activator.CreateInstance<T>();
                    System.Web.Routing.RouteData rd = new System.Web.Routing.RouteData();
                    // must include the controller name without "Controller" to match
                    // the Views subfolder name there has to be a cleaner way to do this…
                    string viewFolderName = controller.GetType().Name.Replace(“Controller”, “”);
                    rd.Values.Add(“Controller”,viewFolderName);
                    controller.ControllerContext = new ControllerContext(new RequestContext(vwp.ViewContext.HttpContext, rd), controller) ;
                    var ex = action.Compile();
                    ex.Invoke(controller);
                }
        }
}

I know there’s probably a way to use ViewLocator, or maybe some way to figure out which route to use and avoid the controller name hack but I haven’t been able to do that yet and this works for my standard circumstances. If anyone knows a better way please let me know!

To use this, put the code above in it’s own class and then use the namespace in your view to call it from. The call should look similar to this:

<% @Import Namespace=“Lindsay” %>
<% @Import Namespace=“MyMVCApp.Controllers” %>

<div>
         <% this.RenderPartial<MyController>((mc => mc.MyAction(myData))); %>
</div>

Partials are a hotly debated topic, but personally, I don’t see how you can really create an Ajax website without them. There is an implementation of “View Components” using ComponentControllers in the current ASP.Net MVC, but it requires you to use a specialized controller and also put your views in a special folder structure. I want to keep my controller code for an entity in one controller as well as all my views in one place and be able to use them as pieces of a page (through Ajax) or a whole page if I prefer. Creating the RenderPartial extension does that for me. Maybe someone else will find it useful as well.

In the spirit of full disclosure: I had the idea to create this extension when I found this solution to fix a bug with RenderComponent. Ironically, modifying that for RenderPartial allowed me to no longer have to use my view components!

» » » »
, , ,

4 Responses to “Creating Partial Views in ASP.Net MVC”

  1. Rik Hemsley Says:

    Looks very useful, will try it out, thanks!

  2. Rik Hemsley Says:

    An error is being thrown when posting a comment. Might want to check that out…

  3. Lindsay Says:

    Hmm… I wasn’t able to reproduce the comment error. Any specifics about what browser you were using or other helpful debug info?

  4. G. Barr Says:

    Hi,
    I am old programmer from the days of COBOL, FORTRAN and asembler and I still hand knit my code. So I am grateful the Microsoft for reverting back towards the days of allowing programmers to code rather than using code generations techniques. It is truely the only way to know what is under the hood, and when practiced correctly reduced the need for debugging.

    regards
    George

Leave a Reply