C# tip, MVC, Non-functional Requirements, Performance

Performance in ASP.net and C# – Bundling and Minification

Another quick post – a really useful feature of MVC that everyone has heard of…and then they seem to forget to do it in practice.

Don’t forget about Bundling and Minification – Rick Anderson explains here how to do it and why it’s important, and a picture tells a thousand words when you see network timings before and after switching on bundling.

Remember, if you don’t see bundling working on your MVC project:

  1. Make sure that the compilation element in your Web.config’s system.web node has the debug = "false";
  2. Check the RegisterBundles class and check if the BundleTable.EnableOptimizations value is set.
    • I don’t actually like this being in my RegisterBundles class – I’d prefer to set this through configuration and not have it embedded in my C# code;
  3. Make sure that the bundling/minification configuration that you’ve set up for your development environment isn’t being copied across to your other environments – you might have planned to debug locally, but you probably don’t want that preference copied across to your acceptance, demonstration or production environments.

This is a really quick and simple way to improve your site’s performance – try it!

.net, C# tip, Clean Code, MVC, nuget, Solid Principles, WebActivatorEx

MVC Tip – Use WebActivatorEx to clean up your boot-strapping logic

The code snippet below shows the Application_Start method inside Global.asax.cs for a default MVC4 implementation.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
 
    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterAuth();
}

In the default implementation, it looks alright – not too messy. But I’ve seen some implementations of this method which are much longer – code to manage NInject registrations, Automapper, and View Engines. So I’ve learned to see this method as somewhere that quickly starts to violate the Single Responsibility Principle.

WebActivatorEx

It’s actually really easy to keep your code clean using WebActivatorEx. This is available as a nuget package that allows a class to be called either just before (or just after) application start-up.

You can install it to your project using the command in the Package Manager Console:

Install-Package WebActivatorEx 

Let’s look at de-coupling Application_Start from the reference to AuthConfig.RegisterAuth(). If we prefix the namespace with a call to WebActivatorEx (as shown below) this method will be called before the Application_Start method.

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(MvcApplication1.AuthConfig), "RegisterAuth")]
namespace MvcApplication1
{
    public static class AuthConfig
    {
        public static void RegisterAuth()
        {
            // ...authorization logic here...
        }
    }
}

I love this pattern because it means that the logic for calling the method at start-up is contained within the same method’s class. We don’t need to call it from the Application_Start method, so we’ve cleanly de-coupled two the classes from each other.

.net, C# tip, Clean Code, MVC

MVC – Enhanced DropDownListFor – Part #2

In Part #1, I described a method signature for the Html.DropDownListFor static HtmlHelper method, which was:

@Html.DropDownListFor(m => m.UserId, m => m.UserNames, m => m.Id, m => m.Name)

In this part. I’ll write more about HtmlHelper extension method code to make this work.

That’s how you use it in Razor – but what does this method signature look like in the source code?

Each of the lambda expressions in the above method signature is an expression which is represented by Expression<Func<T1, T2>> expr. The first parameter will represent the name of the form field rendered, i.e. what the Id and Name values are for the Html <select> element. The second parameter represents the items in the <select> list. The third parameter is the property in the items from the above list which should be rendered in the value attribute of each of the <option> elements of the <select> list. The fourth parameter is the property in the items from the above list which should be rendered in the body, i.e. the innerHTML of each of the <option> elements of the <select> list. So the static extension method signature will have the this HtmlHelper<TModel> as the first parameter, with four expression parameters following, each representing one of the four lambdas in the code snippet above.

public static MvcHtmlString DropDownListFor<TModel, TListItemType, TItemId, TItemName, TSelectedValue>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TSelectedValue>> formFieldName,
            Expression<Func<TModel, List<TListItemType>>> items,
            Expression<Func<TListItemType, TItemId>> optionValueProperty,
            Expression<Func<TListItemType, TItemName>> optionInnerHTMLProperty)
        {
            ...
        }

Already this is starting to look quite complicated. But this is just a cleaner façade around something that is already possible. The body of this method really just gets the data required for the existing DropDownList function (which is within the System.Web.Mvc.Html.SelectExtensions namespace.) So we just need to code a conversion to the signature below.

return SelectExtensions.DropDownList(htmlHelper, formFieldName, selectList);

So let’s look at each of these parameters in turn, and how to populate them from our improved method signature. The HtmlHelper We already have this as a parameter to our overload, so we just pass it in without any modification.

The Form Field Name

Getting the property name as text is really easy – just use the ExpressionHelper on the formFieldName expression (in our example, this is m => m.UserId)

var formField = ExpressionHelper.GetExpressionText(formFieldName);

The Select List

It’s just as easy to get the selected model value from the formFieldName expression as well.

var formFieldValue = ModelMetadata.FromLambdaExpression(formFieldName, htmlHelper.ViewData).Model;

And we perform the same operation on the items expression, but just cast it as List<TListItemType>.

var itemsModel = ModelMetadata.FromLambdaExpression(items, htmlHelper.ViewData).Model as List<TListItemType>

So now we have the list, we need to convert it to a SelectList. To do this, we need to get the names of the methods used for the value and text fields. We can do this using the ExpressionHelper again.

var itemIdPropertyName = ExpressionHelper.GetExpressionText(optionValueProperty);
var itemNamePropertyName = ExpressionHelper.GetExpressionText(optionInnerHTMLProperty);

From this, populating the SelectList is a very simple operation:

var selectList = new SelectList(listItemsModel, itemIdPropertyName, itemNamePropertyName, selectedValueObject);

Final Things

The standard HTMLHelper extensions have some optional parameters, such as htmlAttributes. The DropDownList is no different – so I’ve added in the optionLabel and htmlAttributes parameters for completeness.

The Finished Code

/// <summary>
/// Returns a single-selection HTML &lt;select&gt; element for the expression <paramref name="name" />,
/// using the specified list items.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TListItemType">The type of the items in the list.</typeparam>
/// <typeparam name="TItemId">The type of the item identifier.</typeparam>
/// <typeparam name="TItemName">The type of the item name.</typeparam>
/// <typeparam name="TSelectedValue">The type of the selected value expression result.</typeparam>
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
/// <param name="formFieldName">Name of the form field.</param>
/// <param name="items">The items to put in the  HTML &lt;select&gt; element.</param>
/// <param name="optionValueProperty">The item identifier property.</param>
/// <param name="optionInnerHTMLProperty">The item name property.</param>
/// <param name="optionLabel">The text for a default empty item. Does not include such an item if argument is <c>null</c>.</param>
/// <param name="htmlAttributes">An <see cref="object" /> that contains the HTML attributes for the &lt;select&gt; element. Alternatively, an
/// <see cref="IDictionary{string, object}" /> instance containing the HTML attributes.</param>
/// <returns>A new MvcHtmlString containing the &lt;select&gt; element.</returns>
public static MvcHtmlString DropDownListFor<TModel, TListItemType, TItemId, TItemName, TSelectedValue>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TSelectedValue>> formFieldName,
    Expression<Func<TModel, List<TListItemType>>> items,
    Expression<Func<TListItemType, TItemId>> optionValueProperty,
    Expression<Func<TListItemType, TItemName>> optionInnerHTMLProperty,
    [Optionalstring optionLabel,
    [Optionalobject htmlAttributes)
{
    var formField = ExpressionHelper.GetExpressionText(formFieldName);
    var itemIdPropertyName = ExpressionHelper.GetExpressionText(optionValueProperty);
    var itemNamePropertyName = ExpressionHelper.GetExpressionText(optionInnerHTMLProperty);
 
    var listItemsModel = GetModelFromExpressionAndViewData(items, htmlHelper.ViewData) as List<TListItemType>;
 
    // if the list is null, initialize to an empty list so we display something
    if (listItemsModel == null)
    {
        listItemsModel = new List<TListItemType>();
    }
 
    var selectedValueObject = GetModelFromExpressionAndViewData(formFieldName, htmlHelper.ViewData);
 
    var selectList = new SelectList(listItemsModel, itemIdPropertyName, itemNamePropertyName, selectedValueObject);
 
    return SelectExtensions.DropDownList(htmlHelper: htmlHelper, name: formField, selectList: selectList, optionLabel: optionLabel, htmlAttributes: htmlAttributes);
}
 
/// <summary>
/// Gets the model from expression and view data.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TSelectedValue">The type of the selected value expression result.</typeparam>
/// <param name="expressionThatDefinesTheModel">The expression that defines the model.</param>
/// <param name="viewDataDictionary">The view data dictionary.</param>
/// <returns>System.Object.</returns>
private static object GetModelFromExpressionAndViewData<TModel, TSelectedValue>(Expression<Func<TModel, TSelectedValue>> expressionThatDefinesTheModel, ViewDataDictionary<TModel> viewDataDictionary)
{
    var metaData = ModelMetadata.FromLambdaExpression(expressionThatDefinesTheModel, viewDataDictionary);
 
    return metaData.Model;
}