SingingEels : Development Community & Resource

Login

Articles

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

Syndication

  • Articles RSS
  • Blogs RSS

Contribute

  • Our Authors List
  • Member Sign-Up
  • Suggestions Box
ASP.NET Hosting with MS SQL 2008 – Click Here!

Building Custom ASP.NET MVC Controls

(Aug 01 2008 - 05:31:04 PM by Timothy Khouri) - [print article]
ASP.NET Hosting with MS SQL 2008 – Click Here!

Most .NET web developers have built at least one custom control (or user control) in their time. But MVC is a completely different beast. There's no ViewState, Page Life-Cycle, no code behind (not the way you think of it). In this article, we'll see how to create 'custom controls' in ASP.NET MVC.

The first obstacle to overcome is all of that wonderful Web Forms (traditional ASP.NET) knowledge that is in your head. We're not going to be building some 'OOP' style controls that tap into OnInit, OnLoad, OnRender and the like. The key here is to remember that ultimately our custom control will only perform some sort of 'heavy processing' for the purpose of returning a string of HTML back to the browser. Absolutely no 'functionality' should be done in the code of the control itself other than rendering.

Before going on, let's take a look at some of the controls we are going to build. We'll build two fairly straight forward controls. The first one is purely for getting us started, and then the second is actually a useful control:

  • Marquee - A simple control that takes a message and displays it to the world in a marquee!
  • RollUpGridView - A basic HTML table (like a GridView), but with the added feature of being able to display "groups" of data together.

Extending the HtmlHelper Class

When it comes to creating your own custom control logic in ASP.NET MVC, you actually have a couple of different paths you can go down. You can provide the functionality in the form of a method call by extending the HtmlHelper class... example:

<%= this.Html.Marquee("Hello MVC") %>

or you can create your own declarative controls (more like what you would do in traditional Web Forms)... example:

<mvc:GridView dataSourceController="CarsController" dataSourceAction="ListCars" />

There is already an excellent example out there of how to make your own controls in a declarative way after building your own custom view engine by Stephen Walther, so we won't go into that here. Instead, this article will use extension methods to add functionality to the HtmlHelper class just like ASP.NET MVC does right now.

If you are not familiar with extension methods (new to C#3 and VB9), then you can take a quick look here, but it's not vital for this article. The main focus here is how to create our controls, pass data to the controls and receive our desired results back.

Building a Simple Control

To get started with creating our controls, we're going to create an MVC Web Application project in Visual Studio, and we'll create a Class Library project that will house our controls. Lastly, we'll add a reference to our class library and update the web.config file to include our namespace where our controls will live. Example:

<pages>
   <controls>
       <add tagPrefix="my" namespace="SingingEels.Web.Mvc" assembly="My_MVC_Controls" />
   </controls>

   <namespaces>
       <add namespace="SingingEels.Web.Mvc"/>
   </namespaces>
</pages>

Now we'll create our easy "Marquee" control by extending the HtmlHelper class. The control will take a 'message' and return our HTML finished product. Here's our marquee control:

using System.Web.Mvc;

namespace SingingEels.Web.Mvc
{
   public static class MarqueeExtensions
   {
       public static string Marquee(this HtmlHelper html, string awesomeMessage)
       {
           return string.Format("<marquee>{0}</marquee>", awesomeMessage);
       }
   }
}

Then, to call our control:

<div>
   <%= this.Html.Marquee("WOW, what an AWESOME and useful Custom MVC Control!!!"); %>
</div>

And finally, here is our end result:

A screen shot of a custom MVC 'Marquee' control

Now, on to a slightly more useful and complex control - the RollUpGridView.

Building a GridView in ASP.NET MVC

The principal behind easy controls and complex controls are the same. We're still going to create a method that extends the HtmlHelper class. But this time, our method is going to be generic, accepting an IEnumerable data-source, and the option to set your own HTML attributes on the rendered control.

To allow the users to choose between using the 'GridView' functionality or the 'RollUpGridView' functionality, we'll create multiple overloads to accommodate both functions - one that takes an IEnumerable (for the GridView part) and one that takes an IGrouping (for the RollUpGridView part). Because there will be a good amount of code, I'll only show the important parts of it from here on. You can download the entire source for the project and the end of this article.

First, here are our overloaded methods:

// This method will act as our basic GridView.
public static string RollUpGridView(this HtmlHelper html,
   IEnumerable dataSource, object htmlAttributes) { ... }

// This method will act as our RollUpGridView.

public static string RollUpGridView<TKey, TSource>(this HtmlHelper html,
   IEnumerable<IGrouping<TKey, TSource>> dataSource,
   string rollupRowCssClass,
   object htmlAttributes) { ... }

The only difference between the GridView and the RollUpGridView is that for the 'group key' we will add a row that spans all columns and displays the current group. Inside each function is basically a StringBuilder and a foreach loop that builds the HTML <table> and then returns the final result. To use the last parameter in both functions (htmlAttributes), we use reflection to pull out the properties as name-value pairs, and insert them inside of the <table> tag.

I'm not actually doing the reflection myself. If you'll look into the MVC class libraries, you'll see that they solved this need to create an HTML attribute string from an object, so I stole that functionality. They *SHOULD* just make the function public, but instead, they made it internal.

This type of behavior has always frustrated me to say the least. If you (the developer at Microsoft who made the function) thought it was necessary to have that function, why mark it "internal" so that the rest of the world has to solve the problem for themselves?

Here is what our GridView control will look like:

A screen shot of a custom MVC 'GridView' control

Conclusion

Creating custom MVC controls is not difficult as long as you stick to the main rule - MVC controls are for presentation only. This is not to say that you can't extend the functionality of your MVC applications, but any additional functionality that is not for the explicit use of rendering should be done in your own 'helper' classes and methods. The idea of a control that does presentation, data access and business logic is strictly a Web Forms thing, and doesn't belong in MVC apps.

Here's the source code for the article. It was compiled for ASP.NET MVC Preview 4: SingingEels_MVC_CustomControls.zip

  • Aug 01 2008 - 09:01:04 PM swalther

    Great article! I thought the Things_I_Had_To_Steal.cs class in the download was very funny.

    -- best,

    Stephen Walther

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.

  • 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
  • Site Updates, Bug Fixes and Syndication in .NET 3.5

Related Ads

SingingEels.com as of Jan 05 2009 - 08:33:56 PM - (0.0624984)