Rendering A Single View Using Multiple ViewEngines

asp.net, asp.net mvc 0 comments suggest edit

One of the relatively obscure features of ASP.NET view rendering is that you can render a single view using multiple view engines.

Brad Wilson actually mentioned this in his monster blog post about Partial Rendering and View Engines in ASP.NET MVC, but the implications may have been lost amongst all that information provided.

One of the best features of this new system is that your partial views can use a different view engine than your views, and it doesn’t require any coding gymnastics to make it happen. It all comes down to how the new view system resolves which view engine renders which views.

Let’s dig into a brief example of this in action to understand the full story. Lately, I’ve been playing around with the Spark view engine lately and really like what I see there. Unlike NHaml which pretty gets rid of all angle brackets via a terse DSL for generating HTML, Spark takes the approach that HTML itself should be the “language” for defining the view.

This is not to say that one is specifically better than the other, I’m just highlighting the difference between the two.

Let’s take a look at a small snippet of Spark markup:

<ul>
  <li each='var p in ViewData.Model.Products'>
    ${p.Name} ${Html.ActionLink("Edit Product", "Edit")}
  </li>  
</ul>

Notice that rather than embedding a for loop in the code, you apply the each attribute to a piece of markup to denote that it should be repeated. This is much more declarative than using code nuggets to define a for loop.

As a demonstration, I thought I would take the default ASP.NET MVC project template and within the Index.aspx view, I would render a partial using the Spark view engine.

After referencing the appropriate assemblies from the Spark project, Spark.dll and Spark.Mvc.dll, I registered the spark view engine in Global.asax.cs like so:

protected void Application_Start() {
    ViewEngines.Engines.Add(new SparkViewFactory());
    RegisterRoutes(RouteTable.Routes);
}

I then created a small spark partial view…

<div class="spark-partial">
    <if condition='ViewData.ContainsKey("Title")'>
        <h1>${ViewData["Title"]}</h1>    
    </if>
    
    <p>${ViewData["Message"]}</p>
    <p>${Html.ActionLink("About Page", "About")}</p>
</div>

… and added it to the appropriate directory. I also added a bit of CSS to my default stylesheet in order to highlight the partial.

views-spark-partial

In my Index.aspx view, I added a call to the Html.RenderPartial helper method.

<p>This is a WebForm View.</p>
<p>But the bordered box below, is a partial rendered using Spark.</p>
<% Html.RenderPartial("SparkPartial"); %>

And the result…

spark partial view
result

When we tell the view to render the partial view named “SparkPartial”, ASP.NET MVC will ask each registered view engine, “Hey, yous happens to knows a partial who goes by the name of SparkPartial? I have some unfinished bidness wid this guy.”

Yes, our view infrastructure speaks like a low level mobster thug.

The first view engine that answers yes, gets to render that particular view or partial view. The benefit of this is that if you create a partial view using one view engine, you can reuse that partial on another site that might use a different view engine as its default.

If you want to try out the demo I created, download it and give it a twirl. It is built against ASP.NET MVC Beta.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

18 responses

  1. Avatar for Mike Brown
    Mike Brown November 16th, 2008

    I was wondering if this was possible. That's amazing. So does that mean I can leverage this to slowly migrate from webforms to MVC? Also, which do you recommend keep Webforms and host MVC inside or move to MVC and host Webforms inside?

  2. Avatar for haacked
    haacked November 16th, 2008

    @Mike Not sure how this helps in migrating from WebForms to MVC. The view engine I referred to is the WebFormViewEngine which is part of ASP.NET MVC.
    This view engine makes use of WebForms only to render views. You still don't get PostBack or ViewState etc... with this view engine. At least not in any supported fashion. :)

  3. Avatar for Ayende Rahien
    Ayende Rahien November 16th, 2008

    Haack,
    The problem is that while this is techincally interesting, in practice this isn't something that is used very often. Trying to introduce several view engines in a project is a rare edge case, because of the mental complexity involved.

  4. Avatar for Jonathan Carter
    Jonathan Carter November 16th, 2008

    Spark brings back bad memories of writing ColdFusion for a living.

  5. Avatar for ANaimi
    ANaimi November 16th, 2008

    Spark looks like the solution to all my spaghetti looking views.
    I did see and try Spark before, but I refused to use it for a real project because having a ".spark" iconless extension is just too strange. Is there a way to make VS2008 support .spark just as good as it supports .aspx? (with all the intellisense and everything).

  6. Avatar for huey
    huey November 16th, 2008

    @Ayende
    Not sure what you mean by problem. The first line of the post is:
    "One of the relatively obscure features of ASP.NET view rendering is that you can render a single view using multiple view engines."
    That seems to go hand in hand with what you said about not being used often in practice.

  7. Avatar for Josh
    Josh November 16th, 2008

    Interesting, but I don't really see where this would ever be used. I would think a development team would stick to one view engine. Unless there was some technical advantage in specific cases that would either require or make using a different view engine a valid.

  8. Avatar for Dan F
    Dan F November 16th, 2008

    This is mad cool Phil!
    Sure, many people might not use it, and you could potentially bend your brain using different view engines, but the fact that you *can* do it is hella cool. I'd like to think that the 4 people out there smart enough to work in more than one language at once are giving you high fives and toasting in your honour.

  9. Avatar for Sergio Pereira
    Sergio Pereira November 16th, 2008

    From what I've seen, another problem is the different ways the view passes data to the partials or how/if the partials have visibility to the view's local variables.
    I mean, it's very possible that you cannot just change the engine of the partial and leave the RenderPartial("partialname") untouched.
    Sidenote: Spark is interesting but, as @Jonathan said, above brings some cold-confusion with it. It's not spaghetti code, probably ravioli or tortelini code.

  10. Avatar for Mike Brown
    Mike Brown November 16th, 2008

    So this would be more useful in like a composite app scenario where one is using components made by different teams or vendors in their view engine of choice. So for example if someone had a nice forum application written with Spark, I would be able to combine it with a blog engine written with MVC to make a unified website.

  11. Avatar for haacked
    haacked November 16th, 2008

    @Mike exactly.

  12. Avatar for Eric
    Eric November 16th, 2008

    How specifically does it resolve the correct View Engine? Is it based on the physical file extension? Sounds like a bit of overhead to query the registered views for each Render() or RenderPartial() call. This almost feels like it should be something registered in a web.config file of a subdirectory if you're truly trying to accommodate the ability of "dropping" in application components (like a forums or blog module). That way your original web application which only uses ViewEngine XXX doesn't have to incur a penalty of resolving View Engines that it doesn't use. Maybe I have everything backwards?!

  13. Avatar for Louis DeJardin
    Louis DeJardin November 16th, 2008

    Haack, very cool. Maybe some simple standards will emerge for modular MVC site architecture. Use case for MEF?
    @ANaimi I looked into what it would take to provide a language extension for VS at one point. It's possible of course, but in the end will probably take more effort than writing a custom engine in the first place. Personally, I use the built-in xml editor.
    @Jonathan, @Sergio I've never seen cold fusion, but I've heard that reaction before. It's been compared to other template engines too, like Genshi (genshi.edgewall.org/.../xml-templates.html) and Kid (http://kid-templating.org/language.html)... Is that a bad thing? Most html template engines end up solving the same problems, so similarities are kind of unavoidable.

  14. Avatar for haacked
    haacked November 17th, 2008

    We give the view engines a view name, such as "Foo". The view engines are each responsible for figuring out whether or not they can render that view.
    In our case, we will implement caching to try and ensure high performance.

  15. Avatar for Steve
    Steve November 17th, 2008

    Very cool stuff - I do see where it could also be useful if a team decides to move to a new view engine, the changes could be incremental without a complete rewrite

  16. Avatar for Gauthier Segay
    Gauthier Segay November 17th, 2008

    Brillant, that's the CLR of view rendering pipeline :)
    @Ayende & all: I agree that in most cases it will not be used, but I can see a common usage for this: when you would share some views/parts between projects that don't necessarily use the same view engine, then you can mixin all theses stuff without rewrite

  17. Avatar for mikenz
    mikenz November 19th, 2008

    That is cool. It makes the decision to adopt a particular view engine not such a huge deal. For example you might write some pieces in nhaml and then discover down the track that it would be easier/more flexible/better to write other pieces in webformsview. I've not used nhaml but it would be interesting to try it, i like the concept.

  18. Avatar for Anoop
    Anoop June 10th, 2010

    Following the thought process, I just created a CompositeViewEngine that can render both aspx/ascx (by using the WebFormViewEngine) and *.view.tt files (using a custom T4View I wrote).
    Details: Creating a custom View Engine for ASP.NET MVC leveraging Text Template (T4) engine for rendering the view
    amazedsaint.blogspot.com/...