SingingEels : Development Community & Resource

Login

Articles

  • ADO.NET (2)
  • ASP.NET (36)
  • LINQ (5)
  • Security (2)
  • Silverlight (3)
  • SQL (7)
  • Standards (5)
  • WCF (2)

Syndication

  • Articles RSS
  • Blogs RSS

Contribute

  • Our Authors List
  • Member Sign-Up
  • Suggestions Box

Creating a Custom View Engine in ASP.NET MVC

(Nov 27 2008 - 06:09:52 AM by Timothy Khouri) - [print article]

ASP.NET is an awesome web development platform that many developers wouldn't ever want to part with. However, if given the option, there are definitely parts of the package that you may want to swap out. This article will show you how easy it can be to break away from the "inline-ASP" or "Web Forms" world, and delve into your own custom ViewEngine.

It's true that much of the ASP.NET framework has been pluggable for a while (example: Membership and Profiles). Also, we have always had a choice of server-side language from the start (example: C# or VB). But only recently with the birth of ASP.NET MVC do we have a clean and straight forward solution to swap out the "ASP" language for our own.

By the end of this article, we will have made our own language (called "HoTMeaT"), we will have registered our custom ViewEngine and we will notice just how easy it is to swap out this seemingly 'fixed' area of ASP.NET. At the end of the article, you can download the entire demo project - including the source code for the language.

It's important to note that we have always had the option of writing a custom HttpHandler. But that meant that we have to take over all aspects of the request life-cycle. But with ASP.NET MVC's custom "ViewEngine" capabilities, we are *ONLY* tapping into the slice of the cycle that takes a file and outputs HTML. The "controller" will still function the same; security will still be enforced, etc.

A Sneak Peek Into the Language

Before we get into a "step-by-step" of how to write our own ViewEngine, I want to show you how amazing this new "HoTMeaT" language is going to look. Since I'm currently on a WPF kick, I'm going to copy some of that great functionality by taking "binding" to the next level.

Here's the code for the Customers/List page. We won't need to do anything different in our code, because really, the "Controller" doesn't care about how "View" will look. It's only responsible for getting the data.

public ActionResult List()
{
   ViewData["People"] = new Person[]
   {
       new Person{FirstName="Timothy", LastName="Khouri"},
       new Person{FirstName="Jonathan", LastName="Carter"},
       new Person{FirstName="Travis", LastName="Sheppard"},
   };

   return View();
}

Now, how would you display a list of those people in your own custom HTML template? Well, if you were using WebForms (traditional ASP.NET), you would probably use a Repeater and then do data binding in the code behind. If you are using ASP.NET MVC, you would probably just write a for-loop with sloppy inline ASP. But, with HoTMeaT...

<ul>
   <listView source="{ViewData People}">
       <itemTemplate>
           <li>{Binding LastName}, {Binding FirstName}</li>
       </itemTemplate>
   </listView>
</ul>

And here's the HTML that it generates:

<ul>
   <li>Khouri, Timothy</li>
   <li>Carter, Jonathan</li>
   <li>Sheppard, Travis</li>
</ul>

Now that's pretty cool. But before we go on, there is a myth that needs to be dispelled. I've heard multiple people say that if you use / build a custom ViewEngine that you'll suffer some great performance hit. That is completely not true. The HoTMeaT view engine (which parses the HTML for custom tags, and performs data binding at runtime for each request) runs at 0.00015 seconds. That means that it can handle hundreds of requests per second from my laptop. So no, there are no performance concerns (unless of course you're a bad programmer).

Creating and Registering your Custom ViewEngine

ASP.NET MVC was built to allow developers to change certain parts of the pipe-line in a similar way. For example, creating and registering a ViewEngine is much like creating your own custom model binder and then registering it at runtime. We'll create a class that inherits from "IViewEngine". Then (just like with registering a ModelBinder) we'll register our custom ViewEngine in the Global.asax file. Here's the code:

protected void Application_Start()
{
   //... other things up here.


   // I want to REMOVE the ASP.NET ViewEngine...

   ViewEngines.Engines.Clear();

   // and then add my own :)

   ViewEngines.Engines.Add(new HoTMeaTViewEngine());
}

Inside of our ViewEngine class we only have to provide the functionality for two methods - CreateView and CreatePartialView. Those methods will return an instance of a class that implements "IView". The View class has one method in it - Render.

While it's true that your custom ViewEngine only needs to implement the IViewEngine interface, I went a small step further and implemented the "VirtualPathProviderViewEngine" class. That class implements IViewEngine, but it also provides a little extra functionality that helps us tell MVC where to look for our View files.

Here's the code for our ViewEngine:

public class HoTMeaTViewEngine : VirtualPathProviderViewEngine
{
   public HoTMeaTViewEngine()
   {
       // This is where we tell MVC where to look for our files. This says

       // to look for a file at "Views/Controller/Action.html"

       base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.html" };
       
       base.PartialViewLocationFormats = base.ViewLocationFormats;
   }

   protected override IView CreateView(ControllerContext context, string viewPath, string masterPath)
   {
       return new HoTMeaTView(viewPath, masterPath);
   }

   protected override IView CreatePartialView(ControllerContext context, string partialPath)
   {
       return new HoTMeaTView(partialPath, "");
   }
}

How Do I Build my View?

So now that we've created our ViewEngine and registered it in the Global.asax, we have to actually do something in our View class. As was mentioned above, the only method that we have to implement is "Render", which passes in the viewContext (which gives us the Controller, ViewData, RouteData, etc) and a TextWriter for us to render to. So, if you wanted to make a *very* basic view engine that simply shells out a static file, you could do this:

public class MyView : IView
{
   public HoTMeaTView(string viewPath)
   {
       this.ViewPath = viewPath;
   }

   public string ViewPath { get; private set; }

   public void Render(ViewContext viewContext, TextWriter writer)
   {
       string filePath = viewContext.HttpContext.Server.MapPath(this.ViewPath);

       string fileContents = File.ReadAllText(filePath);

       writer.Write(File.ReadAllText(fileContents);
   }
}

And that's really it! We've just made our own ViewEngine which creates a simple View that writes out the contents of a file. Now, you may be wondering what happened to my great new "HoTMeaT" language where we could do all that great data-binding right in our HTML. If you want to see all that code, then you can download the source project and take a look at the code yourself. That code is intentionally left that so as not to detract from the main point of the article. So here's the full demo project with all of the code including the "HotMeatViewEngine": SingingEels_CustomMvcViewEngine.zip

So What Is "HoT MeaT"?

Back in college I had a very "build it yourself to learn it" mentality (and really I still do today). So, I wanted to understand Sockets and client/server programming, so I made my own "web server". All it did was shell out static HTML files. Then for some reason, my friend and I decided that we would make our own language: HTMT ("Hyper Text Meta Transformation" - aka "HoT MeaT"). I think we were bored in C++ 101, and bordom leads to invention! We got to the point of displaying the time on the server and basically stopped there. So that's the story behind the name.

  • Jan 02 2009 - 09:42:28 AM rmmason

    Nice article. Downloaded the source code so looking forward to taking a look at your view engine.

  • Feb 17 2009 - 10:56:33 AM jamison777

    Informative article, thanks. For any who are interested... here's a good implementation of the <a href="http://code.google.com/p/string-template-view-engine-mvc/">custom view engine</a> functionality using the StringTemplate engine, and a walkthrough of <a href="http://websitelogic.net/articles/MVC/stringtemplate-viewengine-asp-net-mvc/">how to use it</a>.

You must be logged in to add comments. If you have not already done so, you can create an account here. If you already are a member, you first need to login before you can comment.

Developer / Architect / Author

People to Follow

Experts in the categories related to this article.

  • Jonathan Carter

Related Blogs

These are the most recent blog posts related to this article.

  • Follow up to Self Sorting GridView
  • A Change to the MVC "ActionSelectionAttribute"?
  • How to Handle "Side Content" in ASP.NET MVC
  • LINQ to SQL - Am I Hitting The Database?
  • ASP.NET MVC - Issue with CSS Class Name on ActionLinks

Related Ads

SingingEels.com as of Mar 15 2010 - 03:20:05 PM - (0.07813)