Maarten Balliauw {blog}

Web development, NuGet, Microsoft Azure, PHP, ...

NAVIGATION - SEARCH

ASP.NET MVC - Upcoming preview 4 release

ScottGu just posted that there's an upcoming preview 4 release of the ASP.NET MVC framework. What I immediately noticed, is that there are actually some community concepts being integrated in the framework, yay! And what's even cooler: 2 of these new features are things that I've already contributed to the community (the fact that it these are included in the MVC framework now could be coincidence, though...).

Thank you, ASP.NET MVC team! This preview 4 release seems like a great step in the evolution of the ASP.NET MVC framework. Thumbs up!

kick it on DotNetKicks.com

Article on ASP.NET MVC in .NET magazine #21

.NET magazine 21 Yesterday, I received the new Dutch edition of .NET magazine containing my article on the ASP.NET MVC framework. Since the article was written quite a while ago, soucre code is no longer up-to-date. Readers who are interested (or anyone else interested in ASP.NET MVC) can download up-to-date code examples on the ASP.NET MVC guestbook page.

kick it on DotNetKicks.com

Extending ASP.NET MVC OutputCache ActionFilterAttribute - Adding substitution

In my previous blog post on ASP.NET MVC OutputCache, not all aspects of "classic" ASP.NET output caching were covered. For instance, substitution of cached pages. Allow me to explain...

When using output caching you might want to have everything cached, except, for example, a user's login name or a time stamp. When caching a full HTTP response, it is not really possible to inject dynamic data. ASP.NET introduced the Substitution control, which allows parts of a cached response to be dynamic. The contents of the Substitution control are dynamically injected after retrieving cached data, by calling a certain static method which returns string data. Now let's build this into my OutputCache ActionFilterAttribute...

UPDATE: Also check Phil Haack's approach to this: http://haacked.com/archive/2008/11/05/donut-caching-in-asp.net-mvc.aspx

1. But... how?

Schematically, the substitution process would look like this:

ASP.NET MVC OutputCache

When te view is rendered, it outputs a special substitution tag (well, special... just a HTML comment which will be recognized by the OutputCache). The OutputCache will look for these substitution tags and call the relevant methods to provide contents. A substitution tag will look like <!--SUBSTITUTION:CLASSNAME:METHODNAME-->.

One side note: this will only work with server-side caching (duh!). Client-side could also be realized, but that would involve some Ajax calls.

2. Creating a HtmlHelper extension method

Every developer loves easy-to-use syntax, so instead of writing an error-prone HTML comment like <!--SUBSTITUTION:CLASSNAME:METHODNAME-->. myself, let's do that using an extension method which allows syntax like <%=Html.Substitution<MvcCaching.Views.Home.Index>("SubstituteDate")%>. Here's an example view:

[code:c#]

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
    AutoEventWireup="true" CodeBehind="Index.aspx.cs"
    Inherits="MvcCaching.Views.Home.Index" %>
<%@ Import Namespace="MaartenBalliauw.Mvc.Extensions" %>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%= Html.Encode(ViewData["Message"]) %></h2>

    <p>
        Cached timestamp: <%=Html.Encode(DateTime.Now.ToString())%>
    </p>

    <p>
        Uncached timestamp (substitution):
        <%=Html.Substitution<MvcCaching.Views.Home.Index>("SubstituteDate")%>
    </p>
</asp:Content>

[/code]

The extension method for this will look quite easy. Create a new static class containing this static method:

[code:c#]

public static class CacheExtensions
{
    public static string Substitution<T>(this HtmlHelper helper, string method)
    {
        // Check input
        if (typeof(T).GetMethod(method, BindingFlags.Static | BindingFlags.Public) == null)
        {
            throw new ArgumentException(
                string.Format("Type {0} does not implement a static method named {1}.",
                    typeof(T).FullName, method),
                        "method");
        }

        // Write output
        StringBuilder sb = new StringBuilder();

        sb.Append("<!--");
        sb.Append("SUBSTITUTION:");
        sb.Append(typeof(T).FullName);
        sb.Append(":");
        sb.Append(method);
        sb.Append("-->");

        return sb.ToString();
    }
}

[/code]

What happens is basically checking for the existance of the specified class and method, and rendering the appropriate HTML comment. Our example above will output <!--SUBSTITUTION:MvcCaching.Views.Home.Index:SubstituteDate-->.

One thing to do before substituting data though: defining the SubstituteDate method on the MvcCaching.Views.Home.Index: view codebehind. The signature of this method should be static, returning a string and accepting a ControllerContext parameter. In developer language: static string MyMethod(ControllerContext context);

Here's an example:

[code:c#]

public partial class Index : ViewPage
{
    public static string SubstituteDate(ControllerContext context)
    {
        return DateTime.Now.ToString();
    }
}

[/code]

3. Extending the OutputCache ActionFilterAttribute

Previously, we did server-side output caching by implementing 2 overrides of the ActionFilterAttribute, namely OnResultExecuting and OnResultExecuted. To provide substitution support, we'll have to modify these 2 overloads a little. Basically, just pass all output through the ResolveSubstitutions method. Here's the updated OnResultExecuted overload:

[code:c#]

public override void OnResultExecuted(ResultExecutedContext filterContext)
{
    // Server-side caching?
    if (CachePolicy == CachePolicy.Server || CachePolicy == CachePolicy.ClientAndServer)
    {
        if (!cacheHit)
        {
            // Fetch output
            string output = writer.ToString();

            // Restore the old context
            System.Web.HttpContext.Current = existingContext;

            // Fix substitutions
            output = ResolveSubstitutions(filterContext, output);

            // Return rendered data
            existingContext.Response.Write(output);

            // Add data to cache
            cache.Add(
                GenerateKey(filterContext),
                writer.ToString(),
                null,
                DateTime.Now.AddSeconds(Duration),
                Cache.NoSlidingExpiration,
                CacheItemPriority.Normal,
                null);
        }
    }
}

[/code]

Now how about this ResolveSubstitutions method? This method is passed the ControllerContext and the unmodified HTML output. If no substitution tags are found, it returns immediately. Otherwise, a regular expression is fired off which will perform replaces depending on the contents of this substitution variable.

One thing to note here is that this is actually a nice security hole! Be sure to ALWAYS Html.Encode() dynamic data, as users can inject these substitution tags easily in your dynamic pages and possibly receive useful error messages with context information...

[code:c#]

private string ResolveSubstitutions(ControllerContext filterContext, string source)
{
    // Any substitutions?
    if (source.IndexOf("<!--SUBSTITUTION:") == -1)
    {
        return source;
    }

    // Setup regular expressions engine
    MatchEvaluator replaceCallback = new MatchEvaluator(
        matchToHandle =>
        {
            // Replacements
            string tag = matchToHandle.Value;

            // Parts
            string[] parts = tag.Split(':');
            string className = parts[1];
            string methodName = parts[2].Replace("-->", "");

            // Execute method
            Type targetType = Type.GetType(className);
            MethodInfo targetMethod = targetType.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public);
            return (string)targetMethod.Invoke(null, new object[] { filterContext });
        }
    );
    Regex templatePattern = new Regex(@"<!--SUBSTITUTION:[A-Za-z_\.]+:[A-Za-z_\.]+-->", RegexOptions.Multiline);

    // Fire up replacement engine!
    return templatePattern.Replace(source, replaceCallback);
}

[/code]

How easy was all that? You can download the full soure and an example here.

kick it on DotNetKicks.com

Creating an ASP.NET MVC OutputCache ActionFilterAttribute

In every web application, there are situations where you want to cache the HTML output of a specific page for a certain amount of time, because underlying data and processing isn't really subject to changes a lot. This cached response is stored in the web server's memory and offers very fast responses because no additional processing is required.

Using "classic" ASP.NET, one can use the OutputCache directive on a .aspx page to tell the ASP.NET runtime to cache the response data for a specific amount of time. Optionally, caching may vary by parameter, which results in different cached responses depending on the parameters that were passed in the URL.

As an extra feature, one can also send some HTTP headers to the client and tell him to load the page from  the web browser's cache until a specific amount of time has passed. Big advantage of this is that your web server will receive less requests from clients because they simply use their own caching.

Using the ASP.NET MVC framework (preview 3, that is), output caching is still quite hard to do. Simply specifying the OutputCache directive in a view does not do the trick. Luckily, there's this thing called an ActionFilterAttribute, which lets you run code before and after a controller action executes. This ActionFilterAttribute class provides 4 extensibility points:

  • OnActionExecuting occurs just before the action method is called
  • OnActionExecuted occurs after the action method is called, but before the result is executed (before the view is rendered)
  • OnResultExecuting occurs just before the result is executed (before the view is rendered)
  • OnResultExecuted occurs after the result is executed (after the view is rendered)

Let's use this approach to create an OutputCache ActionFilterAttribute which allows you to decorate any controller and controller action, i.e.:

[code:c#]

[OutputCache(Duration = 60, VaryByParam = "*", CachePolicy = CachePolicy.Server)]
public ActionResult Index()
{
    // ...
}

[/code]

We'll be using an enumeration called CachePolicy to tell the OutputCache attribute how and where to cache:

[code:c#]

public enum CachePolicy
{
    NoCache = 0,
    Client = 1,
    Server = 2,
    ClientAndServer = 3
}

[/code]

1. Implementing client-side caching

Actually, this one's really easy. Right before the view is rendered, we'll add some HTTP headers to the response stream. The web browser will receive these headers and respond to them by using the correct caching settings. If we pass in a duration of 60, the browser will cache this page for one minute.

[code:c#]

public class OutputCache : ActionFilterAttribute
{
    public int Duration { get; set; }
    public CachePolicy CachePolicy { get; set; }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // Client-side caching?
        if (CachePolicy == CachePolicy.Client || CachePolicy == CachePolicy.ClientAndServer)
        {
            if (Duration <= 0) return;

            HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
            TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);

            cache.SetCacheability(HttpCacheability.Public);
            cache.SetExpires(DateTime.Now.Add(cacheDuration));
            cache.SetMaxAge(cacheDuration);
            cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
        }
    }
}

[/code]

2. Implementing server-side caching

Server-side caching is a little more difficult, because there's some "dirty" tricks to use. First of all, we'll have to prepare the HTTP response to be readable for our OutputCache system. To do this, we first save the current HTTP context in a class variable. Afterwards, we set up a new one which writes its data to a StringWriter that allows reading to occur:

[code:c#]

existingContext = System.Web.HttpContext.Current;
writer = new StringWriter();
HttpResponse response = new HttpResponse(writer);
HttpContext context = new HttpContext(existingContext.Request, response)
{
    User = existingContext.User
};
System.Web.HttpContext.Current = context;

[/code]

Using this in a OnResultExecuting override, the code would look like this:

[code:c#]

public override void OnResultExecuting(ResultExecutingContext filterContext)
{
    // Server-side caching?
    if (CachePolicy == CachePolicy.Server || CachePolicy == CachePolicy.ClientAndServer)
    {
        // Fetch Cache instance
        cache = filterContext.HttpContext.Cache;

        // Fetch cached data
        object cachedData = cache.Get(GenerateKey(filterContext));
        if (cachedData != null)
        {
            // Cache hit! Return cached data
            cacheHit = true;
            filterContext.HttpContext.Response.Write(cachedData);
            filterContext.Cancel = true;
        }
        else
        {
            // Cache not hit.
            // Replace the current context with a new context that writes to a string writer
            existingContext = System.Web.HttpContext.Current;
            writer = new StringWriter();
            HttpResponse response = new HttpResponse(writer);
            HttpContext context = new HttpContext(existingContext.Request, response)
            {
                User = existingContext.User
            };

            // Copy all items in the context (especially done for session availability in the component)
            foreach (var key in existingContext.Items.Keys)
            {
                context.Items[key] = existingContext.Items[key];
            }

            System.Web.HttpContext.Current = context;
        }
    }
}

[/code]

By using this code, we can retrieve an existing item from cache and set up the HTTP response to be read from. But what about storing data in the cache? This will have to occur after the view has rendered:

[code:c#]

public override void OnResultExecuted(ResultExecutedContext filterContext)
{
    // Server-side caching?
    if (CachePolicy == CachePolicy.Server || CachePolicy == CachePolicy.ClientAndServer)
    {
        if (!cacheHit)
        {
            // Restore the old context
            System.Web.HttpContext.Current = existingContext;

            // Return rendererd data
            existingContext.Response.Write(writer.ToString());

            // Add data to cache
            cache.Add(
                GenerateKey(filterContext),
                writer.ToString(),
                null,
                DateTime.Now.AddSeconds(Duration),
                Cache.NoSlidingExpiration,
                CacheItemPriority.Normal,
                 null);
        }
    }
}

[/code]

Now you noticed I added a VaryByParam property to the OutputCache ActionFilterAttribute. When caching server-side, I can use this to vary cache storage by the parameters that are passed in. The GenerateKey method will actually generate a key depending on controller, action and the VaryByParam value:

[code:c#]

private string GenerateKey(ControllerContext filterContext)
{
    StringBuilder cacheKey = new StringBuilder();

    // Controller + action
    cacheKey.Append(filterContext.Controller.GetType().FullName);
    if (filterContext.RouteData.Values.ContainsKey("action"))
    {
        cacheKey.Append("_");
        cacheKey.Append(filterContext.RouteData.Values["action"].ToString());
    }

    // Variation by parameters
    List<string> varyByParam = VaryByParam.Split(';').ToList();

    if (!string.IsNullOrEmpty(VaryByParam))
    {
        foreach (KeyValuePair<string, object> pair in filterContext.RouteData.Values)
        {
            if (VaryByParam == "*" || varyByParam.Contains(pair.Key))
            {
                cacheKey.Append("_");
                cacheKey.Append(pair.Key);
                cacheKey.Append("=");
                cacheKey.Append(pair.Value.ToString());
            }
        }
    }

    return cacheKey.ToString();
}

[/code]

There you go! Now note that you can add this OutputCache attribute to any controller and any controller action you  have in your application. The full source code is available for download here: MvcCaching.zip (211.33 kb) (full sample) or OutputCache.zip (1.59 kb) (only attribute).

UPDATE: Make sure to read part 2, available here.

kick it on DotNetKicks.com

The devil is in the details (Visual Studio Team System test policy)

Have you ever been in a difficult situation where a software product is overall very good, but a small detail is going wrong? At least I've been, for the past week...

Team System allows check-in policies to be enforced prior to checking in your code. One of these policies is the unit testing policy, which allows you to enforce a specific test list to be run prior to checking in your code.

How it is...

Now here's the catch: what if you have a Team Project with 2 solutions in it? How can I enforce the check-in policy to run tests from solution A only when something in solution A is checked in, tests from solution B with solution B changes, ...

How it should be...

Creating a custom check-in policy

To be honest, there actually are quite enough examples on creating a custom check-in policy and how to install them. So I'll keep it short: here's the source code of my solution (VS2008 only).

kick it on DotNetKicks.com

Code based ASP.NET MVC GridView

ASP.NET MVC GridViewEarlier this week a colleague of mine asked me if there was such thing as a  DataGrid or GridView or something like that in the ASP.NET MVC framework. My first answer was: "Nope!". I advised him to look for a nice foreach implementation or using ExtJS, Dojo or similar. Which made me think... Why not create a simple GridView extension method which generates a nice looking, plain-HTML grid with all required features like paging, editing, deleting, alternating rows, ...?

The idea was simple: an extension method to the HtmlHelper class would be enough. Required parameters: a header and footer template, item template, edit item template, ... But how to pass in these templates using a simple C# parameter... Luckily,  C# 3.0 introduced lambdas! Why? They are super-flexible and versatile! For instance, take the following code:

[code:c#]

// C# code:
public void RenderPerson(Person p, Action<T> renderMethod) {
    renderMethod(p);
}

// ASP.NET code:
<% RenderPerson(new Person(), person => { %>
    Hello! You are <%=person.Name%>.
<% } %>

[/code]

It translates nicely into:

[code:c#]

Response.Write("Hello! You are Maarten.");

[/code]

Creating a GridView extension method should not be that hard! And it sure isn't.

Live demo

Perhaps I should put this last in my blog posts, but there are always people who are only reading the title and downloading an example:

1. The GridView extension method

Quite short and quite easy:

[code:c#]

public static class GridViewExtensions
{
    public static void GridView<T>(
        this HtmlHelper html,
        GridViewData<T> data,
        Action<GridViewData<T>> headerTemplate,
        Action<T, string> itemTemplate,
        string cssClass,
        string cssAlternatingClass,
        Action<T> editItemTemplate,
        Action<GridViewData<T>> footerTemplate)
    {
        headerTemplate(data);

        int i = 0;
        foreach (var item in data.PagedList)
        {
            if (!item.Equals(data.EditItem))
            {
                itemTemplate(item, (i % 2 == 0 ? cssClass : cssAlternatingClass));
            }
            else
            {
                editItemTemplate(item);
            }

            i++;
        }

        footerTemplate(data);
    }
}

[/code]

2. GridViewData

Of couse, data will have to be displayed. And we'll need a property which sets the current item being edited. Here's my Model I'll be passing to the View:

[code:c#]

public class GridViewData<T>
{
    public PagedList<T> PagedList { get; set; }

    public T EditItem { get; set; }
}

[/code]

By the way, the PagedList<T> I'm using is actually a shameless copy from Rob Conery's blog a while ago.

3. The View

Of course, no rendered HTML without some sort of View. Here's a simplified version in which I pass the GridView<T> extension method the required data, header template, item template, edit item template and footer template. Also noice the alternating rows are simply alternating CSS styles (item and item-alternating).

[code:c#]

<%Html.GridView<Employee>(
    this.ViewData.Model,
    data => { %>
        <table class="grid" cellpadding="0" cellspacing="0">
    <% },
    (item, css) => { %>
        <tr class="<%=css%>">
            <td><%=Html.ActionImage<HomeController>(c => c.Edit(item.Id), "~/Content/edit.gif", "Edit", null)%></td>
            <td><%=Html.ActionImage<HomeController>(c => c.Delete(item.Id), "~/Content/delete.gif", "Delete", null)%></td>
            <td>&nbsp;</td>
            <td><%=item.Name%></td>
            <td><%=item.Email%></td>
        </tr>
    <% },
    "item",
    "item-alternating",
    item => { %>
        <%using (Html.Form<HomeController>(c => c.Save(item.Id), FormMethod.Post, new { id = "editForm" })) {%>
            <tr class="item-edit">
                <td><%=Html.SubmitImage("save", "~/Content/ok.gif", new { alt = "Update" })%></td>
                <td><%=Html.ActionImage<HomeController>(c => c.Index(), "~/Content/cancel.gif", "Cancel", null)%></td>
                <td>&nbsp;</td>
                <td><%=Html.TextBox("Name", item.Name)%></td>
                <td><%=Html.TextBox("Email", item.Email)%></td>
            </tr>
        <% } %>
    <% },
    data => { %>
        </table>
<% });%>

[/code]

4. The Controller

The Controller is perhaps the hardest part: it contains all methods that handle actions which are requested by the View. I have a Show action which simply shows the View with current data. Also, I have implemented an Edit and Save action. Make sure to check my example code download for the full example (earlier in this post).

[code:c#]

// ...

public ActionResult Show(int? page)
{
    CurrentPage = page.HasValue ? page.Value : CurrentPage;
    GridViewData<Employee> viewData = new GridViewData<Employee>
    {
        PagedList = Employees.ToPagedList<Employee>(CurrentPage, 4)
    };

    return View("Index", viewData);
}

public ActionResult Edit(int id)
{
    GridViewData<Employee> viewData = new GridViewData<Employee>
    {
        PagedList = Employees.ToPagedList<Employee>(CurrentPage, 4),
        EditItem = Employees.Where( e => e.Id == id).FirstOrDefault()
    };

    return View("Index", viewData);
}

public ActionResult Save(int id)
{
    BindingHelperExtensions.UpdateFrom(
        Employees.Where(e => e.Id == id).FirstOrDefault(),
        Request.Form
    );
    return RedirectToAction("Show");
}

// ...

[/code]

Note: based on ASP.NET MVC preview 3

kick it on DotNetKicks.com 

Detailed code metrics with NDepend

A while ago, I blogged about code performance analysis in Visual Studio 2008. Using profiling and hot path tracking, I measured code performance and was able to react to that. Last week, Patrick Smacchia contacted me asking if I wanted to test his project NDepend. He promised me NDepend would provide more insight in my applications. Let's test that!

After downloading, extracting and starting NDepend, an almost familiar interface shows up. Unfortunately, the interface that shows up after analyzing a set of assemblies is a little bit overwhelming... Note that this overwhelming feeling fades away after 15 minutes: the interface shows the information you want in a very efficient way! Here's the analysis of a personal "wine tracking" application I wrote 2 years ago.

Am I independent?

Let's start with the obvious... One of the graphs NDepend generates, is a dependency map. This diagram shows all dependencies of my "WijnDatabase" project.

Dependencies mapped

One thing I can see from this, is that there probably is an assembly too much! WijnDatabase.Classes could be a candidate for merging into WijnDatabase, the GUI project. These dependencies are also shown in the dependency window.

Dependencies mapped

You can see (in the upper right corner) that 38 methods of the WijnDatabase assembly are using 5 members of WijnDatabase.Classes. Left-click this cell, and have more details on this! A diagram of boxes clearly shows my methods in a specific form calling into WijnDatabase.Classes.

More detail on dependencies

In my opinion, these kinds of views are really useful to see dependencies in a project without reading code! The fun part is that you can widen this view and have a full dependency overview of all members of all assemblies in the project. Cool! This makes it possible to check if I should be refactoring into something more abstract (or less abstract). Which is also analysed in the next diagram:

Is my application in the zone of pain?

What you can see here is the following:

  • The zone of pain contains assemblies which are not very extensible (no interfaces, no abstract classes, nor virtual methods, stuff like that). Also, these assemblies tend to have lots of dependent assemblies.
  • The zone of uselessness is occupied by very abstract assemblies which have almost no dependent assemblies.

Most of my assemblies don't seem to be very abstract, dependencies are OK (the domain objects are widely used so more in the zone of pain). Conclusion: I should be doing some refactoring to make assemblies more abstract (or replacable, if you prefer it that way).

CQL - Code Query Language

Next to all these graphs and diagrams, there's another powerful utility: CQL, or Code Query Language. It's sort of a "SQL to code" thing. Let's find out some things about my application...

 

Methods poorly commented

It's always fun to check if there are enough comments in your code. Some developers tend to comment more than writing code, others don't write any comments at all. Here's a (standard) CQL query:

[code:c#]

// <Name>Methods poorly commented</Name>
WARN IF Count > 0 IN SELECT TOP 10 METHODS WHERE PercentageComment < 20 AND NbLinesOfCode > 10  ORDER BY PercentageComment ASC
// METHODS WHERE %Comment < 20 and that have at least 10 lines of code should be more commented.
// See the definition of the PercentageComment metric here http://www.ndepend.com/Metrics.aspx#PercentageComment

[/code]

This query searches the top 10 methods containing more than 10 lines of code where the percentage of comments is less than 20%.

CQL result 

Good news! I did quite good at commenting! The result of this query shows only Visual Studio generated code (the InitializeComponent() sort of methods), and some other, smaller methods I wrote myself. Less than 20% of comments in a method consisting of only 11 lines of code (btnVoegItemToe_Click in the image) is not bad!

Quick summary of methods to refactor

Another cool CQL query is the "quick summary of methods to refactor". Only one method shows up, but I should probably refactor it. Quiz: why?

CQL result

Answer: there are 395 IL instructions in this method (and if I drill down, 57 lines of code). I said "probably", because it might be OK after all. But if I drill down, I'm seeing some more information that is probably worrying: cyclomatic complexity is high, there are many variables used, ... Refactoring is indeed the answer for this method!

Methods that use boxing/unboxing

Are you familiar with the concept of boxing/unboxing? If not, check this article. One of the CQL queries in NDepend is actually finding all methods using boxing and unboxing. Seems like my data access layer is boxing a lot! Perhaps some refactoring could be needed in here too.

CQL result

Conclusion

Over the past hour, I've been analysing only a small tip of information from my project. But there's LOTS more information gathered by NDepend! Too much information, you think? Not sure if a specific metric should be fitted on your application? There's good documentation on all metrics as well as short, to-the-point video demos.

In my opinion, each development team should be gathering some metrics from NDepend with every build and do a more detailed analysis once in a while. This detailed analysis will give you a greater insight on how your assemblies are linked together and offer a great review of how you can improve your software design. Now grab that trial copy!

kick it on DotNetKicks.com

ASP.NET MVC framework preview 3 released!

Don't know how I do it, but I think this blog post is yet again the first one out there mentioning a new release of the ASP.NET framework (preview 3) Cool

The official installation package can be downloaded from the Microsoft site. Source code is also available from CodePlex.

Update instructions from preview 2 to preview 3 are contained in the download. If you created a project based on the "preview-preview" version, here's what you'll have to update:

  • Controller
    The return of a controller action is no longer returned using RenderView(...), but View(...). Alternative return values are View (returns a ViewResult instance), Redirect (redirects to the specified URL and returns a RedirectResult instance), RedirectToAction, RedirectToRoute, Json (returns a JsonResult instance) and Content (which sends text content to the response and returns a ContentResult instance)
  • View
    I had to update my ViewData calls as the ViewData property of ViewPage<T> is no longer replaced by T. Instead, you'll have to access your model trough ViewData.Model (where Model is of T).
  • Routing
    Routes can now be created using the RouteCollection's extension method "MapRoute". Also, a new constraint has been added to routing where you can allow/disallow specific HTTP methods (i.e. no GET).
  • Version of assemblies
    The versions of the System.Web.Abstractions and System.Web.Routing assemblies that are included with the MVC project template have been changed to version 0.0.0.0 to make sure no conflict occurs with the latest .NET Framework 3.5 SP1 Beta release.

kick it on DotNetKicks.com

Creating a custom ViewEngine for the ASP.NET MVC framework

Have you ever seen a presentation of ScottGu about the ASP.NET MVC framework? There is one particular slide that keeps coming back, stating that every step in the ASP.NET MVC life cycle is pluggable. Let's find out if replacing one of these components is actually easy by creating a custom ViewEngine and corresponding view.

 ASP.NET MVC life cycle

Some background

After a route has been determined by the route handler, a Controller is fired up. This Controller sets ViewData, which is afterwards passed into the ViewEngine. In short, the ViewEngine processes the view and provides the view with ViewData from the Controller. Here's the base class:

[code:c#]

public abstract class ViewEngineBase {
     public abstract void RenderView(ViewContext viewContext);
}

[/code]

By default, the ASP.NET MVC framework has a ViewEngine named WebFormsViewEngine. As the name implies, this WebFormsViewEngine is used to render a view which is created using ASP.NET web forms.

The MvcContrib project contains some other ViewEngine implementations like NVelocity, Brail, NHaml, XSLT, ...

What we are going to build...

Rendered viewIn this blog post, we'll build a custom ViewEngine which will render a page like you see on the right from a view with the following syntax:

[code:c#]

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Custom ViewEngine Demo</title>
</head>
<body>
    <h1>{$ViewData.Title}</h1>
    <p>{$ViewData.Message}</p>
    <p>The following fruit is part of a string array: {$ViewData.FruitStrings[1]}</p>
    <p>The following fruit is part of an object array: {$ViewData.FruitObjects[1].Name}</p>
    <p>Here's an undefined variable: {$UNDEFINED}</p>
</body>
</html>

[/code]

What do we need?

First of all, download the current ASP.NET MVC framework from CodePlex. After creating a new ASP.NET MVC web site, tweak some stuff:

  • Remove /Views/*.*
  • Remove /Content/*.* (unless you want to keep the default CSS files)
  • Add a folder /Code

In order to create a ViewEngine, we will have to do the following:

  • Create a default IControllerFactory which sets the ViewEngine we will create on each Controller
  • Edit Global.asax.cs and register the default controller factory
  • Create a ViewLocator (this one will map a controller + action to a specific file name that contains the view to be rendered)
  • Create a ViewEngine (the actual purpose of this blog post)

Let's do some coding!

1. Creating and registering the IControllerFactory implementation

Of course, ASP.NET MVC has a default factory which creates a Controller instance for each incoming request. This factory takes care of dependency injection, including Controller initialization and the assignment of a ViewEngine. Since this is a good point of entry to plug our own ViewEngine in, we'll create an inherited version of the DefaultControllerFactory:

[code:c#]

public class SimpleControllerFactory : DefaultControllerFactory
{
    protected override IController CreateController(RequestContext requestContext, string controllerName)
    {
        Controller controller = (Controller)base.CreateController(requestContext, controllerName);
        controller.ViewEngine = new SimpleViewEngine(); // <-- will be implemented later in this post
        return controller;
    }
}

[/code]

In order to make this SimpleControllerFactory the default factory, edit the Global.asax.cs file and add the following line of code in the Application_Start event:

[code:c#]

ControllerBuilder.Current.SetControllerFactory(typeof(SimpleControllerFactory));

[/code]

2. Create a ViewLocator

In order for the ViewEngine we'll build to find the correct view for each controller + action combination, we'll have to implement a ViewLocator too:

[code:c#] 

public class SimpleViewLocator : ViewLocator
{
    public SimpleViewLocator()
    {
        base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.htm",
                                                  "~/Views/{1}/{0}.html",
                                                  "~/Views/Shared/{0}.htm",
                                                  "~/Views/Shared/{0}.html"
        };
        base.MasterLocationFormats = new string[] { "" };
    }
}

[/code]

We are actually providing the possible application paths where a view can be stored.

3. Create a ViewEngine

The moment you have been waiting for! The IViewEngine interface requires the following class structure:

[code:c#]

public class SimpleViewEngine : IViewEngine
{
    // ...
    // Private member: IViewLocator _viewLocator = null;
    // Public property: IViewLocator ViewLocator
    // ...

    #region IViewEngine Members

    public void RenderView(ViewContext viewContext)
    {
        string viewLocation = ViewLocator.GetViewLocation(viewContext, viewContext.ViewName);
        if (string.IsNullOrEmpty(viewLocation))
        {
            throw new InvalidOperationException(string.Format("View {0} could not be found.", viewContext.ViewName));
        }

        string viewPath = viewContext.HttpContext.Request.MapPath(viewLocation);
        string viewTemplate = File.ReadAllText(viewPath);

        IRenderer renderer = new PrintRenderer();
        viewTemplate = renderer.Render(viewTemplate, viewContext);

        viewContext.HttpContext.Response.Write(viewTemplate);
    }

    #endregion
}

[/code]

Note that we first locate the view using the ViewLocator, map it to a real path on the server and then render contents directly to the HTTP response. The PrintRenderer class maps {$....} strings in the view to a real variable from ViewData. If you want to see the implementation, please check the download of this example.

Conclusion

Conclusions Replacing the default ViewEngine with a custom made version is actually quite easy! The most difficult part in creating your own ViewEngine implementation will probably be the parsing of your view. Fortunately, there are some examples around which may be a good source of inspiration (see MvcContrib).

If someone wants to use the code snippets I posted to create their own PHP Smarty, please let me know! Smarty is actually quite handy, and might also be useful in ASP.NET MVC.

And yes, it has been a lot of reading, but I did not forget. Download the example code from this blog post: CustomViewEngine.zip (213.17 kb)

kick it on DotNetKicks.com

ASP.NET MVC custom ActionResult (ImageResult)

The ASP.NET MVC framework introduces the concept of returning an ActionResult in Controllers since the "preview preview" release on CodePlex. The purpose of this concept is to return a generic ActionResult object for each Controller method, allowing different child classes returning different results.

An example ActionResult (built-in) is the RenderViewResult. Whenever you want to render a view, you can simply return an object of this class which will render a specific view in its ExecuteResult method. Another example is the HttpRedirectResult which will output an HTTP header (Location: /SomethingElse.aspx).

In my opinion, this is a great concept, because it allows you to develop ASP.NET MVC applications more transparently. In this blog post, I will build a custom ActionResult class which will render an image to the HTTP response stream.

ASP.NET MVC Custom ActionResultAs an example, let's create a page which displays the current time as an image.

One option for implementing this would be creating an ASP.NET HttpHandler which renders this image and can be used inline with a simple HTML tag: <img src="DisplayTime.ashx" />

Wouldn't it be nice to be able to do something more ASP.NET MVC-like? Let's consider the following: <%=Html.Image<HomeController>(c => c.DisplayTime(), 200, 50, "Current time")%>

1. Creating the necessary HtmlHelper extension methods

The above example code is not available in standard ASP.NET MVC source code. We'll need an extension method for this, which will map a specific controller action, width, height and alternate text to a standard HTML image tag:

[code:c#]

public static class ImageResultHelper
{
    public static string Image<T>(this HtmlHelper helper, Expression<Action<T>> action, int width, int height)
        where T : Controller
    {
        return ImageResultHelper.Image<T>(helper, action, width, height, "");
    }

    public static string Image<T>(this HtmlHelper helper, Expression<Action<T>> action, int width, int height, string alt)
        where T : Controller
    {
        string url = helper.BuildUrlFromExpression<T>(action);
        return string.Format("<img src=\"{0}\" width=\"{1}\" height=\"{2}\" alt=\"{3}\" />", url, width, height, alt);
    }

[/code]

2. The custom ActionResult class

Our new ImageResult class will inherit the abstract class ActionResult and implement its ExecuteResult method. This method basically performs communication over the HTTP response stream.

[code:c#]

public class ImageResult : ActionResult
{
    public ImageResult() { }

    public Image Image { get; set; }
    public ImageFormat ImageFormat { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        // verify properties
        if (Image == null)
        {
            throw new ArgumentNullException("Image");
        }
        if (ImageFormat == null)
        {
            throw new ArgumentNullException("ImageFormat");
        }

        // output
        context.HttpContext.Response.Clear();

        if (ImageFormat.Equals(ImageFormat.Bmp)) context.HttpContext.Response.ContentType = "image/bmp";
        if (ImageFormat.Equals(ImageFormat.Gif)) context.HttpContext.Response.ContentType = "image/gif";
        if (ImageFormat.Equals(ImageFormat.Icon)) context.HttpContext.Response.ContentType = "image/vnd.microsoft.icon";
        if (ImageFormat.Equals(ImageFormat.Jpeg)) context.HttpContext.Response.ContentType = "image/jpeg";
        if (ImageFormat.Equals(ImageFormat.Png)) context.HttpContext.Response.ContentType = "image/png";
        if (ImageFormat.Equals(ImageFormat.Tiff)) context.HttpContext.Response.ContentType = "image/tiff";
        if (ImageFormat.Equals(ImageFormat.Wmf)) context.HttpContext.Response.ContentType = "image/wmf";

        Image.Save(context.HttpContext.Response.OutputStream, ImageFormat);
    }
}

[/code]

3. A "DisplayTime" action on the HomeController

We'll add a DisplayTime action on the HomeController class, which will return an instance of the newly created class ImageResult:

[code:c#]

public ActionResult DisplayTime()
{
    Bitmap bmp = new Bitmap(200, 50);
    Graphics g = Graphics.FromImage(bmp);

    g.FillRectangle(Brushes.White, 0, 0, 200, 50);
    g.DrawString(DateTime.Now.ToShortTimeString(), new Font("Arial", 32), Brushes.Red, new PointF(0, 0));

    return new ImageResult { Image = bmp, ImageFormat = ImageFormat.Jpeg };
}

[/code]

And just to be complete, here's the markup of the index view on the HomeController:

[code:c#]

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<%@ Import Namespace="MvcApplication1.Code" %>
<%@ Import Namespace="MvcApplication1.Controllers" %>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <p>
        <%=Html.Image<HomeController>(c => c.DisplayTime(), 200, 50, "Current time")%>
    </p>
</asp:Content>

[/code]

Want the source code? Download it here! You can use it with the current ASP.NET MVC framework source code drop.

kick it on DotNetKicks.com