Site Meter
 
 

Monthly Archives: April 2008

Model-based Client-side Validation for ASP.NET MVC

For quite a while, I was unsure how to go about doing validation in ASP.NET MVC. By default, it’s incompatible with the ASP.NET <asp:XyzValidator> server controls, so this gives us an opportunity to come up with something newer and better.

There have been a couple of great efforts from the community, including Juergen Baeurle’s MVC Validator Toolkit, and Matt Hawley’s MVC UI Validation Framework (now part of MVC Contrib). I wasn’t really satisfied with either, because they take validation out of the domain model and into the application’s UI (no offense guys, what you’ve done is cool).

So, check out my first ever screencast – 6 thrilling minutes of non-stop coding action, in which you get to add both server-side and breathtakingly fit client-side validation to an ASP.NET MVC application, while keeping all the validation rules right in the domain model. Whoo!

Oh noes! Either your feed reader has removed the screencast, or you haven’t enabled Javascript and Flash. You’re missing out!

For those of you that don’t have time for screencasts (like me, normally), here’s how to get the client-side validation goodness in your ASP.NET MVC application. I’m using Castle Validator for the server-side bits, and Live Validation for the client-side bits, fused into one terrifying alien beast hell-bent on ultimate data purity.

Instructions

1. Download and reference MvcValidator.dll and Castle.Components.Validator.dll (from the Castle project). In your master page, add a reference to the Live Validation script (preferably a local copy of it):

<script src="http://www.livevalidation.com/javascripts/src/1.3/livevalidation_standalone.compressed.js"></script>

2. Add validation attributes to your model object.

public class Person
{
    [ValidateNonEmpty("Please enter a name")]
    public string Name { get; set; }
 
    [ValidateNonEmpty("Please enter an email address")] [ValidateEmail]
    public string Email { get; set; }
 
    [ValidateNonEmpty("Please enter an age")] [ValidateInteger]
    public int? Age { get; set; }
}

3. Drop an Html.ClientSideValidation into your view:

<% using(Html.Form("Home", "SubmitPerson", FormMethod.Post)) { %>
    <p>Name: <%= Html.TextBox("MyPrefix.Name", ViewData.Name) %></p>
    <p>Email: <%= Html.TextBox("MyPrefix.Email", ViewData.Email)%></p>
    <p>Age: <%= Html.TextBox("MyPrefix.Age", ViewData.Age)%></p>
 
    <%= Html.ClientSideValidation(ViewData, s => "MyPrefix." + s) %>
    <%= Html.SubmitButton() %>
<% } %>

4. Strut, pose, be smug. You’re done!

Optional steps:

5. Add server-side validation keyed off the same validation attributes, using Castle Validator’s ValidatorRunner (the screencast shows this in action before the client-side validation).

6. Add CSS rules to get the red/green border effect as shown in the screenshot.

Downloads

Thoughts

I’d really love to see something along these lines baked into the official MVC framework, perhaps following Castle’s example of having a pluggable system for emitting Javascript for particular validation checks, so folks could integrate it with client-side validation libraries of their choice. (In my version, I’ve just hard-coded it to work with Live Validator.)

kick it on DotNetKicks.com

(Server controls vs. Inline code) = (What vs. How)

When each developer first learns about ASP.NET MVC, their immediate reaction to MVC view pages is to be shocked and appalled by the mixture of HTML markup and C# code (“inline code”).

What about separating presentation from logic??” they’ll cry, and of course you’ll explain the bigger picture of separation of concerns: domain logic from application logic from UI logic, and how MVC adds scope for testability and cleaner code and how foreach loops beat databinding any day, and so on, mercilessly kicking WebForms’s elderly butt.

And of course you’re right. But each time I have to type out view code like this:

<table cellspacing="0">
    <thead>
        <tr>
            <th>ID</th>
            <th>Product</th>
            <th>Category</th>
            <th align="right">Price</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        <% foreach(var item in ViewData.Products) { %>
            <tr>
                <td><%= item.ProductID %></td>
                <td><%= item.Name %></td>
                <td><%= item.Category %></td>
                <td align="right"><%= item.Price.ToString("c") %></td>
                <td><%= Html.ActionLink("Details", "Show", new { ProductID = item.ProductID }) %></td>
            </tr>
        <% } %>
    </tbody>
</table>

… I can’t help thinking that something’s slightly not right here (and honestly, I try to suppress that dark thought!). Oh don’t get me wrong, I’m a big fan of the new MVC framework, and I’d take it rather than WebForms any day, but software development technology normally progresses like this:

  • Old technology: Specify exactly what you want the computer to do
  • New technology: Specify what end result you want, but let the computer work out the details

Great examples of the latter bullet point are query languages like SQL or even LINQ, and many of C#’s newer features (e.g. type inference). And how about:

  • Classic ASP: Specify exactly what HTML markup you want
  • WebForms: Specify what end result you want (e.g. a grid), and let the framework figure out what HTML markup is required
  • ASP.NET MVC: Um, specify exactly what HTML markup you want

My experience is that WebForms was a great idea, for its time, but in practice it just didn’t work so well. For demoware, it’s an awesome platform, but try to build a 3-person-year project with it and it will all end in tears (but not tiers).

So, with MVC, we think again and take stock of where we are. HTML is still a real concern, WebForms’s abstraction layer *didn’t* save us from browser incompatibilities, and HTTP is still a stateless protocol. Time for a change of plan, back to basics and all that, but do we really have to go back to writing <TABLE><THEAD><TR><TH>… etc.? It’s not hard, it’s just verbose. Do we need a better DSL for HTML? Is that what alternate view engines could provide?

The framework’s built-in HTML helpers really do help us, but they only produce individual HTML tags, not related groups of tags. Maybe we should add some new ones, e.g. Html.Table, so you could just write:

<%= Html.Table(ViewData.Products, new { cellspacing = 0 })
    .AddColumn("ID", i => i.ProductID)
    .AddColumn("Product", i => i.Name)
    .AddColumn("Category", i => i.Category)
    .AddColumn("Price", i => i.Price.ToString("c"), new { align = "right" })
    .AddColumn("", i => Html.ActionLink("Details", "Show", new { ProductID = i.ProductID }))
%>

In case you do think that’s a good idea, here’s the code needed to implement it. Sorry it’s a bit long, but each method has a few overrides to give you more flexibility in how you supply parameters:

namespace StevenSanderson.Mvc.HtmlHelpers
{
    public static class TableHelper
    {
        public static HtmlTable<t> Table<t>(this HtmlHelper html, IEnumerable<t> data)
        {
            return html.Table<t>(data, null);
        }
        public static HtmlTable<t> Table<t>(this HtmlHelper html, IEnumerable<t> data, object htmlAttributes)
        {
            return html.Table<t>(data, htmlAttributes.ToPropertyList());
        }
        public static HtmlTable<t> Table<t>(this HtmlHelper html, IEnumerable<t> data, IDictionary<string, string> htmlAttributes)
        {
            return new HtmlTable<t> { Data = data, HtmlAttributes = htmlAttributes };
        }
 
        public class HtmlTable<t>
        {
            public IEnumerable<t> Data;
            public IDictionary<string, string> HtmlAttributes;
            private IList<htmlTableColumn> columns = new List<htmlTableColumn>();
 
            public HtmlTable<t> AddColumn(string headerText, Func<t, object> itemText)
            {
                return this.AddColumn(headerText, itemText, null);
            }
 
            public HtmlTable<t> AddColumn(string headerText, Func<t, object> itemText, object htmlAttributes)
            {
                return this.AddColumn(headerText, itemText, htmlAttributes.ToPropertyList());
            }
 
            public HtmlTable<t> AddColumn(string headerText, Func<t, object> itemText, IDictionary<string, string> htmlAttributes)
            {
                columns.Add(new HtmlTableColumn
                {
                    HeaderText = headerText,
                    ItemText = itemText,
                    HtmlAttributes = htmlAttributes
                });
                return this;
            }
 
            private void RenderAttributes(HtmlTextWriter writer, IDictionary<string, string> attribs)
            {
                if (attribs != null)
                    foreach (var attrib in attribs)
                        writer.AddAttribute(attrib.Key, attrib.Value.ToString(), true);
            }
 
            public override string ToString()
            {
                using (StringWriter sw = new StringWriter())
                {
                    HtmlTextWriter writer = new HtmlTextWriter(sw);
 
                    // <table>
                    RenderAttributes(writer, this.HtmlAttributes);
                    writer.RenderBeginTag(HtmlTextWriterTag.Table);
 
                    // Headers
                    writer.RenderBeginTag(HtmlTextWriterTag.Thead);
                    RenderTableRow(writer, HtmlTextWriterTag.Th, col => col.HeaderText);
                    writer.RenderEndTag(); // </thead>
 
                    // Rows
                    writer.RenderBeginTag(HtmlTextWriterTag.Tbody);
                    foreach (T row in Data)
                        RenderTableRow(writer, HtmlTextWriterTag.Td, col => col.ItemText(row).ToString());
                    writer.RenderEndTag(); // </tbody>
 
                    writer.RenderEndTag(); // </table>
                    return sw.ToString();
                }
            }
 
            private void RenderTableRow(HtmlTextWriter writer, HtmlTextWriterTag cellTag, Func<htmlTableColumn, string> cellValue)
            {
                writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                foreach (var col in columns)
                {
                    RenderAttributes(writer, col.HtmlAttributes);
                    writer.RenderBeginTag(cellTag);
                    writer.Write(cellValue(col));
                    writer.RenderEndTag(); // </th>
                }
                writer.RenderEndTag(); // </tr>
            }
 
            class HtmlTableColumn
            {
                public string HeaderText { get; set; }
                public Func<t, object> ItemText { get; set; }
                public IDictionary<string, string> HtmlAttributes { get; set; }
            }
        }
 
        private static IDictionary<string, string> ToPropertyList(this object obj)
        {
            return obj == null ? null
                : obj.GetType().GetProperties().ToDictionary(p => p.Name, p => p.GetValue(obj, null).ToString());
        }
    }
}

Note that, to use this, you need to add <%@ Import Namespace="StevenSanderson.Mvc.HtmlHelpers" %> to the top of your view page (probably changing the namespace to something more suitable for your project), or add the namespace to your web.config in the system.web/pages/namespaces node.

Improve scalability in ASP.NET MVC using Asynchronous requests

ASP.NET applications run with a fixed-size thread pool. By default, they have 200 (or 250? I forget…) threads available to handle requests. You can make the thread pool bigger if you want, but it’s not usually helpful: more contention and overhead from thread switching will eventually actually reduce the server’s throughput. But what if most of your threads are actually sitting around doing nothing, because they’re actually waiting for some external I/O operation to complete, such as a database query or a call to an external web service? Surely things could be more efficient…

Well yes, actually. Ever since Windows NT 4 we’ve had a notion of I/O Completion Ports (IOCP) which are a mechanism for waiting for I/O to complete without causing thread contention in the meantime. .NET has a special thread pool reserved for threads waiting on IOCP, and you can take advantage of that in your ASP.NET MVC application.

image

The IHttpAsyncHandler, first introduced in ASP.NET 2.0, splits request processing into two. Instead of handling an entire request in one thread (expensive I/O and all), it first does some processing in the normal ASP.NET thread pool, as per any normal request, then when it’s time for I/O, it transfers control to the I/O thread, releasing the original ASP.NET thread to get on with other requests. When the I/O signals completion (via IOCP), ASP.NET claims another, possibly different thread from its worker pool to finish off the request. Thus, the ASP.NET thread pool doesn’t get ‘clogged up’ with threads that are actually just waiting for I/O.

Adding asynchronous processing to ASP.NET MVC

The MVC framework doesn’t (yet) come with any built-in support for asynchronous requests. But it’s a very extensible framework, so we can add support quite easily. First, we define AsyncController:

public class AsyncController : Controller
{
    internal AsyncCallback Callback { get; set; }
    internal IAsyncResult Result { get; set; }
    internal Action<iasyncResult> OnCompletion { get; set; }
 
    protected void RegisterAsyncTask(Func<asyncCallback, IAsyncResult> beginInvoke, Action<iasyncResult> endInvoke)
    {
        OnCompletion = endInvoke;
        Result = beginInvoke(Callback);
    }
}

It’s just like a normal Controller, except it manages some internal state to do with asynchronous processing, and has the RegisterAsyncTask() method that lets you manage transitions across the gap between the two halves of IHttpAsyncHandler processing. Note: it doesn’t implement IHttpAsyncHandler itself; that’s the job of the IRouteHandler we have to set up. Unfortunately I had to reproduce most of the code from the framework’s MvcHandler, because I couldn’t just override any individual method and still get at the controller:

public class AsyncMvcRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new AsyncMvcHandler(requestContext);
    }
 
    class AsyncMvcHandler : IHttpAsyncHandler, IRequiresSessionState
    {
        RequestContext requestContext;
        AsyncController asyncController;
        HttpContext httpContext;
 
        public AsyncMvcHandler(RequestContext context)
        {
            requestContext = context;
        }
 
        // IHttpHandler members
        public bool IsReusable { get { return false; } }
        public void ProcessRequest(HttpContext httpContext) { throw new NotImplementedException(); }
 
        // IHttpAsyncHandler members
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            // Get the controller type
            string controllerName = requestContext.RouteData.GetRequiredString("controller");
 
            // Obtain an instance of the controller
            IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
            IController controller = factory.CreateController(requestContext, controllerName);
            if (controller == null)
                throw new InvalidOperationException("Can't locate the controller " + controllerName);
            try
            {
                asyncController = controller as AsyncController;
                if (asyncController == null)
                    throw new InvalidOperationException("Controller isn't an AsyncController.");
 
                // Set up asynchronous processing
                httpContext = HttpContext.Current; // Save this for later
                asyncController.Callback = cb;
                (asyncController as IController).Execute(new ControllerContext(requestContext, controller));
                return asyncController.Result;
            }
            finally
            {
                factory.DisposeController(controller);
            }
        }
 
        public void EndProcessRequest(IAsyncResult result)
        {
            CallContext.HostContext = httpContext; // So that RenderView() works
            asyncController.OnCompletion(result);
        }
    }
}

It handles requests by supplying an AsyncMvcHandler, which implements IHttpAsyncHandler. Note that during the first half of the processing, i.e. during BeginProcessRequest(), it makes a record of the current HttpContext object. We have to restore that later, during EndProcessRequest(), because we’ll be in a new thread context by then and HttpContext will be null (and that breaks various ASP.NET facilities including WebForms view rendering).

Using AsyncController

It’s now very easy to handle a request asynchronously. Define a route using AsyncMvcRouteHandler, instead of MvcRouteHandler:

routes.Add(new Route("Default.aspx", new AsyncMvcRouteHandler())
{
    Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),
});

Then set up an AsyncController. In this example, we’re calling an external web service using the WebRequest class and its BeginGetResponse() method. That uses an IOCP, so won’t consume an ASP.NET worker thread while it waits:

public class HomeController : AsyncController
{
    public void Index()
    {
        WebRequest req = WebRequest.Create("http://www.example.com");
        req.Method = "GET";
 
        RegisterAsyncTask(cb => req.BeginGetResponse(cb, null), delegate(IAsyncResult result) {
            WebResponse response = req.EndGetResponse(result);
            // Do something with the response here if you want
            RenderView("Index");
        });
    }
}

And that’s it. The web request gets set up and started in the first half of the async processing model, then the thread gets released to serve other requests. When the web request signals completion, ASP.NET takes a different thread from its pool, and gets it to run the code inside the anonymous delegate, inheriting the request context from the first thread so it can send output to the visitor.

Just remember that you should only use async requests when you’re waiting for some operation on an IOCP. Don’t use it if you just going to call one of your own delegates asynchronously (e.g. using QueueUserWorkItem()) because that will come out of the ASP.NET worker thread pool and you’ll get exactly zero benefit (but more overhead).