Blog Archives

I recently came across a interesting post from @ntcoding demonstrating the flexibility and power of FubuMvc’s HTML conventions. The post demonstrates the benefits of applying custom conventions, and provides examples such as displaying a dropdown list of Enums whenever a view model has a Enum property.

Applying these types of conventions really help to DRY-up your code base, and typically this is something that FubuMVC shines at. That said, if you’re stuck using ASP.NET MVC, not all is lost; There are some handy extension points you can use to keep things DRY.

Keeping the Context

Let’s keep Nick’s example view model, as it works for a nice comparison for the different approaches. As a reminder, we’re using a model called CreateBookInputModel that looks like this:

The great thing about Nick’s example is that it provides a nice variety of opportunities to demonstrate the application of conventions.

Editor Templates

The first variation I’m going to make from Nick’s Fubu MVC example is that rather than using Spark and listing out a label and input for each property on the model, I’ll call into ASP.NET MVC’s Editor Template Html helper to build up a view:

@Html.EditorForModel()

This helper will attempt to resolve a view for the model object. In this case, since there is no custom view for the CreateBookInputModel, ASP.NET MVC will use the default editor template for Object. Brad Wilson from the MVC team does a great job of summarizing the behavior and responsibilities of the default object template:

The Object template’s primary responsibility is displaying all the properties of a complex object, along with labels for each property. However, it’s also responsible for showing the value of the model’s NullDisplayText if it’s null, and it’s also responsible for ensuring that you only show one level of properties (also known as a “shallow dive” of an object).

Using the default ASP.NET MVC editor template this helper will render out an input for each of the properties on our model, wrapped in some additional markup to provide hooks for styling with css.

To keep the markup compariable, and to demostrate the first ASP.NET MVC extension point, let’s take a look at providing our own template:

The only deviation from the default template here, is that I’ve replace the "wrapper" markup to be a paragraph tag.

String Template

Much like Fubu MVC, simple strings work straight out of the box, providing a simple input box for the user. You can customize this default freely by dropping your own Editor Template for string into your views. The default string template looks something like this:

Shared/EditorTemplates/String.cshtml

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue)

Custom Conventions

The next interesting case Nick uses, is to override the default String convention to instead display a textarea for any property with a "_BigText" suffix. It is fairly typical in ASP.NET MVC so see a UIHintAttribute applied to each property that requires a custom view to be rendered:

[UIHint("BigText")] public String Description_BigText { get; set; }

By applying this attribute, ASP.NET MVC will try to find a view called "BigText" to use for this property, before falling back to the default String template:

This approach works just fine, however we now need to litter our model with this attribute for every property with a "_BigText" suffix – an approach that is a little too error prone for my liking. Lets see if we can do better.

ModelMetadataProvider

Using the UIHintAttribute is one way we can provide the ASP.NET MVC additional metadata to guide it to finding a view to render the view model property. ASP.NET MVC internally uses the DataAnnotationsModelMetadataProvider (by default) to provide all the information about a view model, including the metadata from the attributes that a view model may be decorated with. Although attributes provide a easy entry point for providing metadata, it’s easy enough to provide an overridden implementation to also include additional metadata, based on some custom convention:

By inheriting DataAnnotationsModelMetadataProvider, we continue to support custom attributes to add metadata about our model (such as UIHint), but I’ve added an addition step here to provide a "TemplateHint" to any property with the "_BigText" suffix. The TemplateHint tells ASP.NET MVC to try to find a view called "BigText" to use to render this property. If the view is not found, it will simply falling back to the default template for this object (String). The last requirement to use this metadata provider is that it will need to be either registered in ASP.NET MVC’s DependecyResolver, or in the static registration point ModelMetadataProviders.Current on application startup.

Getting smart with Enums

One particularly nice part in Nick’s post, is where he provides a convention such that if a view model property is an Enum, a select input will be provided with each of the Enum items.

Doing this with ASP.NET MVC isn’t too hard either mind you. Again, we can fall back on the ModelMetadataProvider extension point to apply this convention:

This is slightly more involved that the previous convention, but let me walk you though it. First of all, we only want to apply the convention if the model property is an Enum. If it is, provide a "TemplateHint" to tell ASP.NET MVC to try to find an appropriate view for the select list – lets call this view "SelectList" so that it’s discoverable by other developers. Next, retrieve the values for the select list, and use them to create SelectListItems. Finally, add the select list values as additional metadata for our model, so that it is available in the view.

Let’s wrap this up – Comparison and Final Thoughts

So we’ve pretty much covered off the building blocks necessary to apply a DRY-er, convention-driven approach to building MVC apps. But wait….what about file uploads and string collections – Nick provided these in his example! You’re right – I didn’t bother implementing these, mainly because they follow exactly the same pattern already laid out above. I’ll leave these as an exercise for the reader (and am happy to take pull requests).

What I do find interesting is that following this approach in ASP.NET MVC, a few of Nicks concerns are addressed:

What happens if the markup is complex and is not so easily created in code?

What happens if need to apply specific classes?

What about when I want to override conventions – what pitfalls await me?

As views can be used to specify the markup for our conventions, complex markup is not so much of an issue, as we have the full power of the MVC view engine at our disposal. Additionally, since the existing ASP.NET MVC extension points still apply, it is not too difficult to handle specific cases where the conventions should not apply. For example, we can override our convention for a given property by providing a UIHintAttribute – it will take precedence over the convention, and all is happy in the world.

I will mention however, that something much, much more favorable about using FubuMVC’s html conventions is that it is easier to break out out conventions into standalone, pluggable parts.

This gets rather tricky in ASP.NET MVC since the ModelMetadataProvider is a designed to be a singly registered component. Of course, as Nick points out, you can always just use fubu mvc’s html conventions in ASP.NET MVC ;)

I’m not going to go into any detail in this post as to why asynchronous actions may be beneficial to your application; other people have covered that in more detail than I’d care to go into. This post will however, try to show how implementing Async controllers can be made simpler, using the Task Parallel Library in .NET 4.0 and a little bit of MVC trickery.

Before I go too far, I’d like to point you to have a look at an introduction in using the TPL with MVC from Mike Hadlow. Mike’s post shows how you can use the TPL to simplify the consumption of Asynchronous services, from an Asp.Net Mvc AsyncController.

In Mike’s example, he ends up with the following AsyncController implementation:

As you can see, we unfortunately have to abandon the succinctness of the TPL syntax, and revert back to the Asynchronous Programming Model pattern of having a start method with a completion callback.

Mike points out that it would be rather nice if instead, we could write a controller action that returns a Task result instead – our resultant action would be nice and simple:

[HttpGet]
public Task<ViewResult> Index()
{
return from user in userService.GetCurrentUser()
from _ in userService.SendUserAMessage(user, "Hi From the MVC TPL experiment")
select View(user);
}

Even though this will compile (when using the TPL extension extras library), unfortunately, this will not run, as the default controller action invoker for running async actions (AsyncControllerActionInvoker) does not know how to handle Tasks…

Asp.Net Mvc Futures

The asp.net mvc futures project currently includes some more flexibility in its support for async patterns. Rather than being limited to supporting the “Async –> Completed” action pairs, the futures project contains the following options:

The Async Pattern (BeginFoo/EndFoo)

The event pattern (Foo/FooCompleted)

The Delegate Pattern (returning a Func<> that represents a continuation).

The most interesting of these techniques (to this example) is the Delegate Pattern:

[HttpGet]

public Func<int> Foo(int id)

{

return () => id * 2;

}

Using this approach, a controller can specify a delegate to provide a completion callback. It’s not too much of a leap to see the similarities with this, and the desired technique using Tasks.

So how does the Asp.Net Futures project add these additional features? Perhaps we can extend them to support TPL?

Hooking in to the Action Invoker

To support the additional async patterns using the futures project, a Controller must inherit the AsyncController from the futures assembly. This controller overrides a property from the base controller class in order to specify a new Action Invoker that can correctly identify actions that represent asynchronous methods. To identify these actions, the AsyncActionInvoker delegates to a AsyncActionMethodSelector that will reflect over the methods on a controller, and pick our asynchronous actions based on naming conventions, or the return type in the case of the delegate pattern. This seems like a good place to start looking to add our new feature.

Unfortunately for us, the AsyncActionMethodSelector does not delegate out to individual objects to identify and handle each type of asynchronous pattern, so supporting an additional pattern will involve some changes to this class. Following the Open/Closed principle could really have cleared up the design here…

Anyway, once we have extended to the AsyncActionMethodSelector to support our new pattern, we need to hook this back into the AsyncActionInvoker (which again, requires some code changes to this class – seriously, this code could’ve been much simpler if people followed SOLID principles!), and then we can use this new invoker from our Async Controller.

Using this new invoker, our controller can now support the use of Tasks for Asynchronous Actions!

Conclusion

As with other areas of the MVC framework, extending the framework to add new features like supporting Tasks to represent Asynchronous Controller Actions was a little bit more painful than it could have been, but in the end, it’s worth it to clean up the the required code to support asynchronous controller actions.

To check out the implementation of all this, you can get the full sample source from GitHub:

In all but the simplest of modern web applications, it’s not uncommon to find that our application depends on many web assets such as CSS and JavaScript files. While it’s generally good practice for maintainability to keep these files separated into small logical chunks, unfortunately practice has implications on the overall performance of our application when referencing these resources; an additional HTTP request will be made for each asset, in turn adding to the latency of the initial load of our application.

Whilst many developers are probably aware of various optimization techniques such as those proposed in the YSlow recommendations (like script combining, minification, caching, compression), implementing these techniques can be a bit of burden.

Further still, when we utilize the Master and Content page features of our view engine, we will often want to place core JavaScript (such as the JQuery library) and common component initialization in the Master Page, whilst the Content pages may have their own file sets and initialization scripts.

This set-up adds an additional complexity to managing our scripts; we need to ensure the scripts tags are all rendered first, regardless of where they are located in the page (Master Page/Content Page/User Control) or our application will start throwing JavaScript exceptions all over the place!

Help is at hand!

Several projects exist that attempt to address some, or all of the issues I’ve mentioned (page request optimization and asset management) – lets take a look at some of our options:

Telerik ScriptRegistrar

Probably one of the closest matches to our requirements, the Telerik ScriptRegistrar and its partner in crime the StylesheetRegistrar provide a simple mechanism to provide a range of optimizations to improve the performance of our applications. The ScriptRegistrar API is composed of a fluent interface allowing groups of scripts to be rendered at the bottom of our master page, whilst additional script dependencies and initialization can be registered in content pages. One small gotcha to look out for here is that partial views returned from Ajax requests will not have the scripts registered.

Overview

Resource combination (served by a IHttpHandler)

Grouping

Compression

Caching

Support for Content Delivery Networks (CDN)

Nice Fluent Interface for script registration and initialization

A Commercial License is required if you are building closed-source commercial products for redistribution (GPLv2 license).

Extra care is required for scripts registered in partial views rendered by Ajax calls (since these are not included by the ScriptRegistrar).

Minification of your scripts is not provided (although some support for selecting between pre-minified scripts and un-minified scripts in debug mode is provided)

Include Combiner

The Include Combiner project, which is included in the MvcContrib* solution as MvcContrib.IncludeHandling, tackles many of the aforementioned issues surrounding the optimization of asset management. It is not as complete as the Telerik implementation, and also suffers from the same complexity in registering scripts in partial views returned by ajax, however this tool is still worth a look for Asp.Net Mvc applications, especially for projects already consuming MvcContrib.

Overview

Resource combination (served by a custom controller)

Grouping

Resources grouped by page usage (rather than explicit sets) – scripts shared across pages must be re-downloaded for each page.

Treats JS and CSS separately, and therefore causes a minimum of 2 additional requests per page.

Extra care is required for scripts registered in partial views rendered by Ajax calls (since these are not included by the ScriptRegistrar).

Combres

Possibly the most complete libraries in terms of features, Combres is a strong choice for managing assets in your application. Combres requires that you define named resources sets which can then be combined, minified, compressed and sent to the browser as a single request. Interestingly, combres has an interesting extensibility model allowing developers to provide additional features, such as applying .less rules and replacing relative urls with absolute urls in css files. On the downside, the configuration model for Combres is very XML heavy, and not as nice to consume as the fluent API provided by other libraries. Unfortunately, the underlying implementation seems to wrap around the XML configuration too, so extending the library for easier consumption (applying your own conventions etc) might be tricky, especially when considered in conjunction with the fact that there are NO unit tests included in the source code (available on CodePlex).

Integrated with Asp.Net routing engine, and therefore also supports webforms development in addition to MVC

Extensible filtering support

XML heavy asset configuration model

Requires resource configuration upfront – as far as I can tell, there isn’t an easy way for a view component to quietly declare “I need this JS/CSS” and for it to be included if it isn’t already there

Conclusion

Optimizing our web applications and conforming to good practices like caching, combining and compressing our resources needn’t be a burden for developers. There are some great tools available to help us keep our applications nimble, whilst ensuring we aren’t distracted from delivering our customers value with technical implementation concerns. I’ve listed our some of the tools I’ve come across that bring us closer to achieving this goal.

Is there anything I’ve missed? Do you have any tools you use to optimize asset management? If so, let me know so I can check them out too!

*MvcContrib is a project designed to add functionality to and ease the application of Microsofts Asp.Net Mvc framework and really useful for developers looking to develop and test UI elements on top of MS Asp.Net Mvc. Check it out here.

In a newly created ASP.NET MVC application, Visual Studio is quite friendly to us, and provides us nice little menus for creating our controllers/views:

This menu does is not provided however, for any existing apps that we may want to migrate to using ASP.NET MVC.

How can we tell Visual Studio to treat this web app as an ASP.NET MVC app? I couldn’t find an immediately obvious way to do this, and it took me more than a simple google search to figure this one out, so here’s what to do:

The new menus should now be available! (you should probably now go ahead and add the Controllers and Views folders)

Hopefully this helps someone else too!

*disclaimer*This worked for me, but I place no guarantees that it will work for you too!! If your computer explodes, your cat passes away, or you end up getting a divorce, please don’t blame me! *disclaimer*