Skip to content

Jimmy Bogard
Syndicate content
Strong opinions, weakly held
Updated: 4 hours 23 min ago

Conventional HTML in ASP.NET MVC: Client-side templates

Thu, 08/14/2014 - 22:21

Other posts in this series:

In our last post, we brought everything together to build composable blocks of tags driven off of metadata. We did this to make sure that when a concept exists in our application, it’s only defined once and the rest of our system builds off of this concept. This reduces logic duplication across several layers, ensuring that we don’t have to “remember” to do repetitive tasks, like a required field needing an asterisk and data attributes.

All of this works great because we’ve got all the information at our disposal on the server-side, and we can push the completed product down to the client (browser). But what if we’re building a SPA, using Angular or Knockout or Ember or Backbone? Do we have to revert back to our old ways of duplication? Or can we have the best of both worlds?

There tend to be three general approaches:

  • Just hard code it and accept the duplication
  • Include metadata in your JSON API calls, through hypermedia or other means
  • Build intelligence into templates

I’ve done all three, and each have their benefits and drawbacks. Most teams I talk to go with #1, and some go with #2. Very few teams I meet even think about #3.

What I’d like to do is have the power of my original server-side Razor templates, with the strongly-typed views and intelligent expression-based helpers, but instead of complete HTML templates, have these be Angular views or Ember templates:

image

When we deliver our templates to the client as part of our SPA, we’ll serve up a special version of them, one that’s been parsed by our Razor engine. Normally, the Razor engine performs two tasks:

  • HTML generation
  • Binding model data

Instead, we’ll only generate our template, and the client will then bind the model to our template.

Serving templates, Ember style

Normally, the MVC view engine runs the Razor parser. But we’re not going that path, we’re going to parse the templates ourselves. The result of parsing will be placed inside our script tags. This part is a little long, so I’ll just link to the entire set of code.

HtmlHelperExtensions

A couple key points here. First, the part that runs the template through the view engine to render an HTML string:

builder.AppendLine("<script type=\"text/x-handlebars\" data-template-name=\"" + fullTemplateName + "\">");
var controllerContext = new ControllerContext(helper.ViewContext.HttpContext, new RouteData(), helper.ViewContext.Controller);
controllerContext.RouteData.Values["controller"] = string.IsNullOrEmpty(relativeDirName) ? "Home" : Path.GetDirectoryName(relativeDirName);
var result = ViewEngine.FindView(controllerContext, subtemplateName, null, false);
var stringWriter = new StringWriter(builder);
var viewContext = new ViewContext(controllerContext, result.View, new ViewDataDictionary(), new TempDataDictionary(), stringWriter);
result.View.Render(viewContext, stringWriter);

builder.AppendLine("</script>");

We render the view through our normal Razor view engine, but surround the result in a script tag signifying this is a Handlebars template. We’ll place the results in cache of course, as there’s no need to perform this step more than once. In our context objects we build up, we simply leave our ViewData blank, so that there isn’t any data bound to input elements.

We also make sure our templates are named correctly, using the folder structure to match Ember’s conventions. In our one actual MVC action, we’ll include the templates in the first request:

@Scripts.Render("~/bundles/ember")
@Scripts.Render("~/bundles/app")

@Html.Action("Enumerations", "Home")
@Html.RenderEmber()

Now that our templates are parsed and named appropriately, we can focus on building our view templates.

Conventional Handlebars

At this point, we want to use our HTML conventions to build out the elements needed for our Ember templates. Unfortunately, we won’t be able to use our previous tools to do so, as Ember uses Handlebars as its templating language. If we were using Angular, it might be a bit easier to build out our directives, but not by much. Client-side binding using templates or directives requires special syntax for binding to scope/model/controller data.

We don’t have our convention model, or even our HtmlTag library to use. Instead, we’ll have to use the old-fashioned way – building up a string by hand, evaluating rules as we go. I could have built a library for creating Ember view helpers, but it didn’t seem to be worth it in my case.

Eventually, I want to get to this:

@Html.FormBlock(m => m.FirstName)

But have this render this:

<div class="form-group">
    <label class="required control-label col-md-2"
       {{bind-attr for="view.firstName.elementId"}}>
       First Name
    </label>
    <div class="col-md-10">
        {{view TextField class="required form-control" 
               data-key="firstName" 
               valueBinding="model.firstName" 
               viewName="firstName" 
               placeholder="First"
        }}
    </div>
</div>

First, let’s start with our basic input and just cover the very simple case of a text field.

public static MvcHtmlString Input<TModel, TValue>(this HtmlHelper<TModel> helper,
    Expression<Func<TModel, TValue>> expression,
    IDictionary<string, object> htmlAttributes)
{
    var text = ExpressionHelper.GetExpressionText(expression).ToCamelCase();
    var modelMetadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
    var unobtrusiveAttributes = GetUnobtrusiveValidationAttributes(helper, expression);

    var builder = new StringBuilder("{{view");

    builder.Append(" TextField");

    if (unobtrusiveAttributes.ContainsKey("data-val-required"))
    {
        builder.Append(" class=\"required\"");
    }

    builder.AppendFormat(" data-key=\"{0}\"", text);

    builder.AppendFormat(" valueBinding=\"model.{0}\"", text);
    builder.AppendFormat(" viewName=\"{0}\"", text);

    if (!string.IsNullOrEmpty(modelMetadata.NullDisplayText))
        builder.AppendFormat(" placeholder=\"{0}\"", modelMetadata.NullDisplayText);

    if (htmlAttributes != null)
    {
        foreach (var item in htmlAttributes)
        {
            builder.AppendFormat(" {0}=\"{1}\"", item.Key, item.Value);
        }
    }

    builder.Append("}}");

    return new MvcHtmlString(builder.ToString());
}

We grab the expression text and model metadata, and begin building up our Handlebars snippet. We apply our conventions manually for each required attribute, including any additional attributes we need based on the MVC-style mode of passing in extra key/value pairs as a dictionary.

Once we have this in place, we can layer on our label helper:

public static MvcHtmlString Label<TModel, TValue>(
    this HtmlHelper<TModel> helper, 
    Expression<Func<TModel, TValue>> expression)
{
    var text = ExpressionHelper.GetExpressionText(expression);
    var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
    var unobtrusiveAttributes = GetUnobtrusiveValidationAttributes(helper, expression);

    var builder = new StringBuilder("<label ");
    if (unobtrusiveAttributes.ContainsKey("data-val-required"))
    {
        builder.Append(" class=\"required\"");
    }
    builder.AppendFormat(" {{{{bind-attr for=\"view.{0}.elementId\"}}}}", text.ToCamelCase());
    builder.Append(">");

    string labelText = metadata.DisplayName ?? (metadata.PropertyName == null
        ? text.Split(new[] {'.'}).Last()
        : Regex.Replace(metadata.PropertyName, "(\\B[A-Z])", " $1"));

    builder.Append(labelText);
    builder.Append("</label>");

    return new MvcHtmlString(builder.ToString());
}

It’s very similar to the code in the MVC label helper, with the slight tweak of defaulting label names to the property names with spaces between words. Finally, our input block combines these two together:

public static MvcHtmlString FormBlock<TModel, TValue>(
    this HtmlHelper<TModel> helper,
    Expression<Func<TModel, TValue>> expression)
{
    var builder = new StringBuilder("<div class='form-group'>");
    builder.Append(helper.Label(expression));
    builder.Append(helper.Input(expression));
    builder.Append("</div>");
    return new MvcHtmlString(builder.ToString());
}

Now, our views start to become a bit more sane, and it takes a keen eye to see that it’s actually a Handlebars template. We still get strongly-typed helpers, metadata-driven elements, and synergy between our client-side code and our server-side models:

@model MvcApplication.Models.AccountCreateModel
{{title 'Create account'}}

<form {{action 'create' on='submit'}}>
    <fieldset>
        <legend>Account Information</legend>
        @Html.FormBlock(m => m.Username)
        @Html.FormBlock(m => m.Password)
        @Html.FormBlock(m => m.ConfirmPassword)
    </fieldset>

We’ve now come full-circle, leverage our techniques that let us be ultra-productive building out pages on the server side, but not losing that productivity on the client-side. A concept such as “required field” lives in exactly one spot, and the rest of our system reads and reacts to that information.

And that, I think, is pretty cool.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

Conventional HTML in ASP.NET MVC: Building larger primitives

Fri, 07/25/2014 - 16:52

Other posts in this series:

We’ve taken our individual form elements quite far now, adopting a variety of conventions in our output to remove the boring, duplicated code around deciding how to display those individual elements. We have everything we need to extend and alter the conventions around those single elements.

And that’s a good thing – we want to keep using those primitives around individual elements. But what if we peeked a little bit larger? Are there larger common patterns in play that we can start incorporating? Let’s look at the basic input template, from Bootstrap:

<div class="form-group">
    @Html.Label(m => m.Password)
    <div class="col-md-10">
        @Html.Input(m => m.Password)
        @Html.ValidationMessageFor(m => m.Password, ""
          , new { @class = "text-danger" })
    </div>
</div>

Starting with the most basic element, the input tag, let’s look at gradually increasing scope of our building block:

  • Input
  • Input and validation
  • Input, validation in a div
  • Label and the div input
  • Form group

The tricky part here is that at each level, I want to be able to affect the resulting tags, some or all. Our goal here is to create building blocks for each level, so that we can establish a set of reusable components with sensible defaults along the way. This is a similar exercise as building a React class or Angular directive – establish patterns early and standardize your approach.

From the above list of items, I’ll likely only want to create blocks around increasing scopes of DOM elements, so let’s whittle this down to 3 elements:

  • Input
  • Input Block
  • Form Block

We already have our original Input method, let’s create the first input block.

Basic input block

Because we have our HtmlTag primitive, it’s trivial to combine elements together. This is a lot easier than working with strings or MvcHtmlStrings or the less powerful TagBuilder primitive. We’ll return the outer div tag, but we still need ways of altering the inner tags. This includes the Label, the Input, and Validator. Here’s our input block:

public static HtmlTag InputBlock<T>(this HtmlHelper<T> helper,
    Expression<Func<T, object>> expression,
    Action<HtmlTag> inputModifier = null,
    Action<HtmlTag> validatorModifier = null) where T : class
{
    inputModifier = inputModifier ?? (_ => { });
    validatorModifier = validatorModifier ?? (_ => { });

    var divTag = new HtmlTag("div");
    divTag.AddClass("col-md-10");

    var inputTag = helper.Input(expression);
    inputModifier(inputTag);

    var validatorTag = helper.Validator(expression);
    validatorModifier(validatorTag);

    divTag.Append(inputTag);
    divTag.Append(validatorTag);

    return divTag;
}

We create an Action<HtmlTag> for the input/validator tags. If someone wants to modify those two elements directly, instead of wonky anonymous-objects-as-dictionaries, we allow them full access to the tag via a callback, similar to jQuery. Next, we default those two modifiers to no-op if they are not supplied.

We then build up our input block, which consists of the outer div with the input tag and validator tag as children. In our view, we can replace the input block:

<div class="form-group">
    @Html.Label(m => m.Email)
    @Html.InputBlock(m => m.Email)
</div>
<div class="form-group">
    @Html.Label(m => m.Password)
    <div class="col-md-10">
        @Html.Input(m => m.Password)
        @Html.Validator(m => m.Password)
    </div>
</div>

Just to contrast, I included the non-input-blocked version. Now that we have this piece, let’s look at building the largest primitive, the form block.

Form input block

In the same tradition of Angular directives, React classes and Ember views, we can build larger components out of smaller ones, reusing the smaller components as necessary. This also ensures our larger component automatically picks up changes from the smaller ones. Here’s our FormBlock method:

public static HtmlTag FormBlock<T>(this HtmlHelper<T> helper,
    Expression<Func<T, object>> expression,
    Action<HtmlTag> labelModifier = null,
    Action<HtmlTag> inputBlockModifier = null,
    Action<HtmlTag> inputModifier = null,
    Action<HtmlTag> validatorModifier = null
    ) where T : class
{
    labelModifier = labelModifier ?? (_ => { });
    inputBlockModifier = inputBlockModifier ?? (_ => { });

    var divTag = new HtmlTag("div");
    divTag.AddClass("form-group");

    var labelTag = helper.Label(expression);
    labelModifier(labelTag);

    var inputBlockTag = helper.InputBlock(
        expression, 
        inputModifier, 
        validatorModifier);
    inputBlockModifier(inputBlockTag);

    divTag.Append(labelTag);
    divTag.Append(inputBlockTag);

    return divTag;
}

It’s very similar to our input block method, where we provide defaults for our initializers, create the outer div tag, build the child tags, apply child modifiers, and append those child tags to the outer div. Going back to our view, it becomes quite simplified:

@Html.FormBlock(m => m.Email)
@Html.FormBlock(m => m.Password)
<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <div class="checkbox">
            @Html.Input(m => m.RememberMe).RemoveClasses()
            @Html.Label(m => m.RememberMe).RemoveClasses()
        </div>
    </div>
</div>

We have one outlier, our “remember me” checkbox, which I try to avoid at all costs. Let’s look at a couple of other examples. Here’s our register view:

@Html.ValidationSummary("", new { @class = "text-danger" })
@Html.FormBlock(m => m.Email)
@Html.FormBlock(m => m.Password)
@Html.FormBlock(m => m.ConfirmPassword)
<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <input type="submit" class="btn btn-default" value="Register" />
    </div>
</div>

And here’s our reset password view:

@Html.ValidationSummary("", new { @class = "text-danger" })
@Html.Input(m => m.Code)
@Html.FormBlock(m => m.Email)
@Html.FormBlock(m => m.Password)
@Html.FormBlock(m => m.ConfirmPassword)
<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <input type="submit" class="btn btn-default" value="Reset" />
    </div>
</div>

Much more simplified, with conventions around the individual input elements and HtmlHelper extensions around larger blocks. I would likely go an additional step and create an HtmlHelper extension around the buttons as well, since Bootstrap buttons have a very predictable, standardized set of HTML to build out.

We’ve removed a lot of our boilerplate HTML, but still allowed customization as needed. We also still expose the smaller components through InputBlock and Input, so that if the HTML varies a lot we can still keep the smaller building blocks. There’s still a bit of magic going on, but it’s only a click away to see what “FormBlock” actually does. Finally, what conventions really allow us to do is stop focusing on the minutiae of the HTML we have to include on every display/input block of HTML.

We remove bike shedding arguments and standardize our approach, allowing us to truly hone in on what is interesting, challenging or different. This is the true power of conventions – stop pointless and wasteful arguments about things that truly don’t matter through a standardized, but extensible, approach built on conventions.

In our next (and final) post, we’ll look at how we can extend these approaches for client-side templates built in Angular, Ember and more.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

Conventional HTML in ASP.NET MVC: Validators

Thu, 07/24/2014 - 20:33

Other posts in this series:

We’re marching towards our goal of creating conventional components, similar to React classes or Angular directives, but there’s one last piece we need to worry about before we get there: validators.

Validators can be a bit tricky, since they largely depend on the validation framework you’re trying to use. My validation framework of choice is still Fluent Validation, but you can use others as well. Since the data annotation validators are fairly popular, this example will use that as the starting point.

First, we have to figure out what our validation HTML should look like, and how it should affect the rest of our output. But we don’t have a “Validator” convention, we only have “Label”, “Editor”, and “Display” as our possibilities.

Luckily, underneath the covers these Label etc. conventions are only categories of elements, and we can easily create a new category of conventions for our own purposes. The Label/Editor/Display properties are only convenience methods. In our base convention class, let’s create a new category of conventions via a similar property:

public class OverrideHtmlConventions : DefaultHtmlConventions
{
    protected ElementCategoryExpression Validators
    {
        get
        {
            var builderSet = Library
                .For<ElementRequest>()
                .Category("Validator")
                .Defaults;
            return new ElementCategoryExpression(builderSet);
        }
    }

    public OverrideHtmlConventions()
    {
        Editors.Always.AddClass("form-control");
        Labels.Always.AddClass("control-label");
        Labels.Always.AddClass("col-md-2");

This will allow us to append additional conventions to a Validator category of element requests. With a custom builder, we can create a default version of our validator span (without any validation messages):

public class SpanValidatorBuilder : IElementBuilder
{
    public HtmlTag Build(ElementRequest request)
    {
        return new HtmlTag("span")
            .AddClass("field-validation-error")
            .AddClass("text-danger")
            .Data("valmsg-for", request.ElementId);
    }
}

And add it to our default conventions:

public OverrideHtmlConventions()
{
    Validators.Always.BuildBy<SpanValidatorBuilder>();

    Editors.Always.AddClass("form-control");
    Labels.Always.AddClass("control-label");
    Labels.Always.AddClass("col-md-2");

The last part is actually generating the HTML. We need to do two things -

  • Determine if the current field has any validation errors
  • If so, build out the tag with the correct error text

The first part is actually fairly straightforward – ha ha just kidding, it’s awful. Getting validation messages out of ASP.NET MVC isn’t easy, but the source is available so we can just copy what’s there.

public static HtmlTag Validator<T>(this HtmlHelper<T> helper,
    Expression<Func<T, object>> expression) where T : class
{
    // MVC code don't ask me I just copied
    var expressionText = ExpressionHelper.GetExpressionText(expression);
    string fullHtmlFieldName 
        = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(expressionText);

    if (!helper.ViewData.ModelState.ContainsKey(fullHtmlFieldName))
        return new NoTag();

    ModelState modelState = helper.ViewData.ModelState[fullHtmlFieldName];
    ModelErrorCollection modelErrorCollection = modelState == null 
        ? null 
        : modelState.Errors;
    ModelError error = modelErrorCollection == null || modelErrorCollection.Count == 0 
        ? null 
        : modelErrorCollection.FirstOrDefault(m => !string.IsNullOrEmpty(m.ErrorMessage)) 
        ?? modelErrorCollection[0];
    if (error == null)
        return new NoTag();
    // End of MVC code

    var tagGeneratorFactory = DependencyResolver.Current.GetService<ITagGeneratorFactory>();
    var tagGenerator = tagGeneratorFactory.GeneratorFor<ElementRequest>();
    var request = new ElementRequest(expression.ToAccessor())
    {
        Model = helper.ViewData.Model
    };

    var tag = tagGenerator.Build(request, "Validator");

    tag.Text(error.ErrorMessage);

    return tag;
}

Ignore what’s going on in the first section – I just grabbed it from the MVC source. The interesting part is at the bottom, where I grab a tag generator factory, create a tag generator, and build an HtmlTag using the Validator category for the given ElementRequest. This is what our Label/Editor/Display methods do underneath the covers, so I’m just emulating their logic. It’s a bit clunkier than I want, but I’ll amend that later.

Finally, after building the base validator tag, we set the inner text to the error message we determined earlier. We only use the first error message – too many and it becomes difficult to read. The validation summary can still be used for multiple errors. Our view is now:

<div class="form-group">
    @Html.Label(m => m.Email)
    <div class="col-md-10">
        @Html.Input(m => m.Email)
        @Html.Validator(m => m.Email)
    </div>
</div>
<div class="form-group">
    @Html.Label(m => m.Password)
    <div class="col-md-10">
        @Html.Input(m => m.Password)
        @Html.Validator(m => m.Password)
    </div>
</div>

Since we know that every validation message will need that “text-danger” class applied, applying it once to our conventions means that we’ll never have to copy-paste that portion around ever again. And much easier to develop against than the MVC templates, which quite honestly, are quite difficult to develop against.

We could go a step further and modify our Label conventions to pick up on the “Required” attribute and show an asterisk or bold required field labels.

Now that we have quite a bit of consistency in our groups of form elements, in the next post we’ll look at tackling grouping multiple tags into a single input/form component.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

Conventional HTML in ASP.NET MVC: Data-bound elements

Wed, 07/23/2014 - 19:03

Other posts in this series:

We’re now at the point where our form elements replace the existing templates in MVC, extend to the HTML5 form elements, but there’s still something missing. I skipped over the dreaded DropDownList, with its wonky SelectListItem objects.

Drop down lists can be quite a challenge. Typically in my applications I have drop down lists based on a few known sets of data:

  • Static list of items
  • Dynamic list of items
  • Dynamic contextual list of items

The first one is an easy target, solved with the previous post and enums. If a list doesn’t change, just create an enum to represent those items and we’re done.

The second two are more of a challenge. Typically what I see is attaching those items to the ViewModel or ViewBag, along with the actual model. It’s awkward, and combines two separate concerns. “What have I chosen” is a different concern than “What are my choices”. Let’s tackle those last two choices separately.

Dynamic lists

Dynamic lists of items typically come from a persistent store. An administrator goes to some configuration screen to configure the list of items, and the user picks from this list.

Common here is that we’re building a drop down list based on set of known entities. The definition of the set doesn’t change, but its contents might.

On our ViewModel, we’d handle this in our form post with an entity:

public class RegisterViewModel
{
    [Required]
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }

    public string ConfirmPassword { get; set; }

    public AccountType AccountType { get; set; }
}

We have our normal registration data, but the user also gets to choose their account type. The values of the account type, however, come from the database (and we use model binding to automatically bind up in the POST the AccountType you chose).

Going from a convention point of view, if we have a model property that’s an entity type, let’s just load up all the entities of that type and display them. If you have an ISession/DbContext, this is easy, but wait, our view shouldn’t be hitting the database, right?

Wrong.

Luckily for us, our conventions let us easily handle this scenario. We’ll take the same approach as our enum drop down builder, but instead of using type metadata for our list, we’ll use our database.

Editors.Modifier<EnitityDropDownModifier>();

// Our modifier
public class EnitityDropDownModifier : IElementModifier
{
    public bool Matches(ElementRequest token)
    {
        return typeof (Entity).IsAssignableFrom(token.Accessor.PropertyType);
    }

    public void Modify(ElementRequest request)
    {
        request.CurrentTag.RemoveAttr("type");
        request.CurrentTag.TagName("select");
        request.CurrentTag.Append(new HtmlTag("option"));

        var context = request.Get<DbContext>();
        var entities = context.Set(request.Accessor.PropertyType)
            .Cast<Entity>()
            .ToList();
        var value = request.Value<Entity>();

        foreach (var entity in entities)
        {
            var optionTag = new HtmlTag("option")
                .Value(entity.Id.ToString())
                .Text(entity.DisplayValue);

            if (value != null && value.Id == entity.Id)
                optionTag.Attr("selected");

            request.CurrentTag.Append(optionTag);
        }
    }
}

Instead of going to our type system, we query the DbContext to load all entities of that property type. We built a base entity class for the common behavior:

public abstract class Entity
{
    public Guid Id { get; set; }
    public abstract string DisplayValue { get; }
}

This goes into how we build our select element, with the display value showed to the user and the ID as the value. With this in place, our drop down in our view is simply:

<div class="form-group">
    @Html.Label(m => m.AccountType)
    <div class="col-md-10">
        @Html.Input(m => m.AccountType)
    </div>
</div>

And any entity-backed drop-down in our system requires zero extra effort. Of course, if we needed to cache that list we would do so but that is beyond the scope of this discussion.

So we’ve got dynamic lists done, what about dynamic lists with context?

Dynamic contextual list of items

In this case, we actually can’t really depend on a convention. The list of items is dynamic, and contextual. Things like “display a drop down of active users”. It’s dynamic since the list of users will change and contextual since I only want the list of active users.

It then comes down to the nature of our context. Is the context static, or dynamic? If it’s static, then perhaps we can build some primitive beyond just an entity type. If it’s dynamic, based on user input, that becomes more difficult. Rather than trying to focus on a specific solution, let’s take a look at the problem: we have a list of items we need to show, and have a specific query needed to show those items. We have an input to the query, our constraints, and an output, the list of items. Finally, we need to build those items.

It turns out this isn’t really a good choice for a convention – because a convention doesn’t exist! It varies too much. Instead, we can build on the primitives of what is common, “build a name/ID based on our model expression”.

What we wound up with is something like this:

public static HtmlTag QueryDropDown<T, TItem, TQuery>(this HtmlHelper<T> htmlHelper,
    Expression<Func<T, TItem>> expression,
    TQuery query,
    Func<TItem, string> displaySelector,
    Func<TItem, object> valueSelector)
    where TQuery : IRequest<IEnumerable<TItem>>
{
    var expressionText = ExpressionHelper.GetExpressionText(expression);
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var selectedItem = (TItem)metadata.Model;

    var mediator = DependencyResolver.Current.GetService<IMediator>();
    var items = mediator.Send(query);
    var select = new SelectTag(t =>
    {
        t.Option("", string.Empty);
        foreach (var item in items)
        {
            var htmlTag = t.Option(displaySelector(item), valueSelector(item));
            if (item.Equals(selectedItem))
                htmlTag.Attr("selected");
        }

        t.Id(expressionText);
        t.Attr("name", expressionText);
    });

    return select;
}

We represent the list of items we want as a query, then execute the query through a mediator. From the results, we specify what should be the display/value selectors. Finally, we build our select tag as normal, using an HtmlTag instance directly. The query/mediator piece is the same as I described back in my controllers on a diet series, we’re just reusing the concept here. Our usage would look something like:

<div class="col-md-10">
    @Html.QueryDropDown(m => m.User,
        new ActiveUsersQuery(),
        t => t.FullName,
        t => t.Id)
</div

If the query required contextual parameters – not a problem, we simply add them to the definition of our request object, the ActiveUsersQuery class.

So that’s how we’ve tackled dynamic lists of items. Depending on the situation, it requires conventions, or not, but either way the introduction of the HtmlTag library allowed us to programmatically build up our HTML without resorting to strings.

We’ve tackled the basics of building input/output/label elements, but we can go further. In the next post, we’ll look at building higher-level components from these building blocks that can incorporate things like validation messages.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

Conventional HTML in ASP.NET MVC: Replacing form helpers

Tue, 07/22/2014 - 17:51

Other posts in this series:

Last time, we ended at the point where we had a baseline behavior for text inputs, labels and outputs. We don’t want to stop there, however. My ultimate goal is to eliminate (as much as possible) using any specific form helper from ASP.NET MVC. Everything we need to determine what/how to render input elements is available to us on metadata, we just need to use it.

Our first order of business is to catalog the expected elements we wish to support:

  • Button (no)
  • Checkbox (yes)
  • Color (yes)
  • Date (yes)
  • DateTime (yes)
  • DateTime Local (yes)
  • Email (Yes)
  • File (No)
  • Hidden (Yes)
  • Image (No)
  • Month (No)
  • Number (Yes)
  • Password (Yes)
  • Radio (Yes)
  • Range (No)
  • Reset (No)
  • Search (No)
  • Telephone (Yes)
  • Text (Yes)
  • Time (Yes)
  • Url (Yes)

And the other two input types that don’t use the <input> element, <select> and <textarea>. This is where convention-based programming and the object model of HtmlTags really shines. Instead of us needing to completely replace a template as we do in MVC, we only need to extend the individual tags, and leave everything else alone. We know that we want to have a baseline style on all of our inputs. We also want to configure this once, which our HTML conventions allow.

So how do we want to key into our conventions? I like to follow a progression:

  • Member type
  • Member name
  • Member attributes

We can infer a lot from the type of a member. Boolean? That’s a checkbox. Nullable bool? That’s not a checkbox, but a select, and so on. Let’s look at each type of input and see what we can infer to build our conventions.

Labels

Labels can be a bit annoying, you might need localization and so on. What I’d like to do is provide some default, sensible behavior. If we look at a login view model:

public class LoginViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }
}

We have a ton of display attributes, all basically doing nothing. These labels key into a couple of things:

  • Label text
  • Validation errors

We’ll get to validation in a future post, but first let’s look at the labels. What can we provide as sensible defaults?

  • Property name
  • Split PascalCase into separate words
  • Booleans get a question mark
  • Fallback to the display attribute if it exists

A sensible label convention would get rid of nearly all of our “Label” attributes. The default conventions get us the first two, we just need to modify for the latter two:

Labels.ModifyForAttribute<DisplayAttribute>((t, a) => t.Text(a.Name));
Labels.IfPropertyIs<bool>()
    .ModifyWith(er => er.CurrentTag.Text(er.OriginalTag.Text() + "?"));

With this convention, our Display attributes go away. If we have a mismatch between the view model property and the label, we can use the Display attribute to specify it explicitly. I only find myself using this when a model is flattened. Otherwise, I try and keep the label I show the users consistent with how I model the data behind the scenes.

Checkbox

This one’s easy. Checkboxes represent true/false, so that maps to a boolean:

Editors.IfPropertyIs<bool>().Attr("type", "checkbox");

// Before
@Html.CheckBoxFor(m => m.RememberMe)
@Html.LabelFor(m => m.RememberMe)

// After
@Html.Input(m => m.RememberMe)
@Html.Label(m => m.RememberMe)

Not very exciting, we just tell Fubu for bools, make the “type” attribute a checkbox. The existing MVC template does a few other things, but I don’t like any of them (like an extra hidden etc).

Color

With some model binding magic, we can handle this by merely looking at the type:

Editors.IfPropertyIs<Color>().Attr("type", "color");

Date/Time/DateTime/Local DateTime

This one is a little bit more difficult, since the BCL doesn’t have a concept of a Date. However, NodaTime does, so we can use that type and key off of it instead:

Editors.IfPropertyIs<LocalDate>().Attr("type", "date");
Editors.IfPropertyIs<LocalTime>().Attr("type", "time");
Editors.IfPropertyIs<LocalDateTime>().Attr("type", "datetime-local");
Editors.IfPropertyIs<OffsetDateTime>().Attr("type", "datetime");

Email

Email could go a number of different ways. There’s not really an Email type in .NET, so we can’t key off the property type. The MVC version uses an attribute to opt-in to an Email template, but I think that’s redundant. In my experience, every property with “Email” in the name is an email address. Why not key off this?

Editors.If(er => er.Accessor.Name.Contains("Email"))
    .Attr("type", "email");

This one could go both ways, but if I want to also/instead go off the DataType attribute, it’s just as easy. I don’t like being too explicit or too confusing, so you’ll have to base this on what you actually find in your systems.

Hidden

Hiddens can be a bit funny. If I’m being sensible with Guid identifiers, I know right off the bat that any Guid type should be hidden. It’s not always the case, so I’d like to support the attribute if needed.

Editors.IfPropertyIs<Guid>().Attr("type", "hidden");
Editors.IfPropertyIs<Guid?>().Attr("type", "hidden");
Editors.IfPropertyHasAttribute<HiddenInputAttribute>().Attr("type", "hidden");

Number

Number inputs are a bit complicated. I actually tend to avoid them, as I find they’re not really that usable. However, I do want to provide some hints to the user as well as some rudimentary client-side validation with the “pattern” attribute.

Editors.IfPropertyIs<decimal?>().ModifyWith(m =>
    m.CurrentTag
    .Data("pattern", "9{1,9}.99")
    .Data("placeholder", "0.00"));

I’d do similar for other numeric types (integer/floating point).

Password

We’ll use the same strategy as our hidden input – key off the name if we can, otherwise check for an attribute.

Editors.If(er => er.Accessor.Name.Contains("Password"))
    .Attr("type", "password");
Editors.If(er =>
{
    var attr = er.Accessor.GetAttribute<DataTypeAttribute>();
    return attr != null && attr.DataType == DataType.Password;
}).Attr("type", "password");

We had to get a little fancy with our attribute check, but nothing too crazy.

Radio

Radio buttons represent a selection of a group of items. In my code, this is represented with an enum. Since radio buttons are a bit more complicated than just an input tag, we’ll need to build out the list of elements manually. We can either build up our select element from scratch, or modify the defaults. I’m going to go the modification route, but because it’s a little more complicated, I’ll use a dedicated class instead:

Editors.Modifier<EnumDropDownModifier>();

// Our modifier
public class EnumDropDownModifier : IElementModifier
{
    public bool Matches(ElementRequest token)
    {
        return token.Accessor.PropertyType.IsEnum;
    }

    public void Modify(ElementRequest request)
    {
        var enumType = request.Accessor.PropertyType;

        request.CurrentTag.RemoveAttr("type");
        request.CurrentTag.TagName("select");
        request.CurrentTag.Append(new HtmlTag("option"));
        foreach (var value in Enum.GetValues(enumType))
        {
            var optionTag = new HtmlTag("option")
                .Value(value.ToString())
                .Text(Enum.GetName(enumType, value));
            request.CurrentTag.Append(
                optionTag);
        }
    }
}

Element modifiers and builders follow the chain of responsibility pattern, where any modifier/builder that matches a request will be called. We only want enums, so our Matches method looks at the accessor property type. Again, this is where our conventions show their power over MVC templates. In MVC templates, you can’t modify the matching algorithm, but in our example, we just need to supply the matching logic.

Next, we use the Modify method to examine the incoming element request and make changes to it. We replace the tag name with “select”, remove the “type” attribute, but leave the other attributes alone. We append a child option element, then loop through all of the enum values to build out name/value options from our enum’s metadata.

Why use this over EnumDropDownListFor? Pretty easy – it gets all of our other conventions, like the Bootstrap CSS classes. In a system with dozens or more enumerations shown, that’s not something I want to repeat all over the place.

Telephone

We’ll treat the telephone just like our password element – check for a property name, and fall back to an attribute.

Editors.If(er => er.Accessor.Name.Contains("Phone"))
    .Attr("type", "tel");
Editors.If(er =>
{
    var attr = er.Accessor.GetAttribute<DataTypeAttribute>();
    return attr != null && attr.DataType == DataType.PhoneNumber;
}).Attr("type", "tel");

If we want to enforce a specific pattern, we’d use the appropriate data-pattern attribute.

Text

This is the default, so nothing to do here!

Url

Just like our password, we’ll look at the property name, then an attribute:

Editors.If(er => er.Accessor.Name.Contains("Url"))
    .Attr("type", "url");
Editors.If(er =>
{
    var attr = er.Accessor.GetAttribute<DataTypeAttribute>();
    return attr != null && attr.DataType == DataType.Url;
}).Attr("type", "url");

If we get tired of typing that attribute matching logic out, we can create an extension method:

public static class ElementCategoryExpressionExtensions
{
    public static ElementActionExpression HasAttributeValue<TAttribute>(
        this ElementCategoryExpression expression, Func<TAttribute, bool> matches)
        where TAttribute : Attribute
    {
        return expression.If(er =>
        {
            var attr = er.Accessor.GetAttribute<TAttribute>();
            return attr != null && matches(attr);
        });
    }
}

And our condition becomes a bit easier to read:

Editors.If(er => er.Accessor.Name.Contains("Url"))
    .Attr("type", "url");
Editors
    .HasAttributeValue<DataTypeAttribute>(attr => attr.DataType == DataType.Url)
    .Attr("type", "url");

Wrapping up

We knocked out most of the HTML5 input element types, leaving out ones that didn’t make too much sense. We can still create conventions for those missing elements, likely using property names and/or attributes to determine the right convention to use. Quite a bit more powerful than the MVC templates!

Next up, we’ll look at more complex element building example where we might need to hit the database to get a list of values for a drop down.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

Conventional HTML in ASP.NET MVC: Baseline behavior

Thu, 07/17/2014 - 16:11

Other posts in this series:

Now that we’ve got the pieces in place for building input/display/label conventions, it’s time to circle back and figure out what exactly we want our default behaviors to be for each of these components. Because it’s so easy to modify the tags generated programmatically, we can establish some pretty decent site-wide behavior for our system.

First, in order to establish a baseline, we need to examine what our current implicit standards are. Right now I’m solely focused on only the input/label/display elements, and not how these elements are typically composed together (label + input etc.). Looking at several of our inputs, we see a prevalent pattern. All of the input elements (ALL of them) have a CSS class appended to them for Bootstrap, “form-control”. Appending this in our normal method of the MVC templated helpers is actually quite difficult and esoteric. For us, it’s a snap.

First, let’s create our own HtmlConventions class that inherits from the default:

public class OverrideHtmlConventions 
    : DefaultHtmlConventions {
}

We’ll then redirect our container configuration to use this convention library instead:

public class FubuRegistry : Registry
{
    public FubuRegistry()
    {
        var htmlConventionLibrary 
             = new HtmlConventionLibrary();
        var conventions
             = new OverrideHtmlConventions();
        htmlConventionLibrary.Import(.Library);
        For<HtmlConventionLibrary>().Use(htmlConventionLibrary);

The OverrideHtmlConventions class is where we’ll apply our own conventions on top of the existing ones. The base conventions class lets us apply conventions to several classes of items:

  • Displays
  • Editors
  • Labels

And a couple of things I won’t cover as I’ve never used them:

  • Forms
  • Templates

There’s no real difference between the Displays/Editors/Templates conventions – it’s just a way to segregate strategies and conventions for building different kinds of HTML elements.

Conventions work by pairing a filter and a behavior. The filter is “whom to apply” and the behavior is “what to do”. You have many different levels of applying filters:

  • Always (global)
  • Attribute existence (w/ filtering on value)
  • Property metadata

The last one is interesting – you have the entire member metadata to work with. You can look at the property name, the property type and so on.

From there, your behaviors can be as simple or complex as you need. You can:

  • Add/remove CSS classes
  • Add/remove HTML attributes
  • Add/remove data attributes
  • Replace the entire HTML tag with a new, ground-up version
  • Modify the HTML tag and its children

You have a lot of information to work with, the original value, new value, containing model and more. It’s pretty crazy, and a lot easier to work with than the MVC metadata (which goes through this ModelMetadata abstraction).

I want to set up our “Always” conventions first, which means really only adding CSS classes. The input elements are easy:

Editors.Always.AddClass("form-control");

Our input elements become a bit simpler now:

@*Before*@
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
@*After*@
@Html.Input(m => m.Email)

Our labels are a bit more interesting. Looking across the app, it appears that all labels have two CSS classes applied, one pertaining to styling a label, and one pertaining to width. At this point we need to make a judgment call. Do we standardize that all labels are a certain width? Or do we force all of our views to explicitly set this class?

Luckily, we can still adopt a site-wide convention and replace this CSS class as necessary. Personally, I’d rather standardize on how screens should look rather than each new screen becoming a point of discussion on how wide/narrow things are. Standardize, but allow deviation. Our label configuration now becomes:

Editors.Always.AddClass("form-control");
Labels.Always.AddClass("control-label");
Labels.Always.AddClass("col-md-2");

Then in our HTML, we can replace our labels with our convention-based version:

<div class="form-group">
    @Html.Label(m => m.Email)
    <div class="col-md-10">
        @Html.Input(m => m.Email)
    </div>
</div>
<div class="form-group">
    @Html.Label(m => m.Password)
    <div class="col-md-10">
        @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
    </div>
</div>
<div class="form-group">
    @Html.Label(m => m.ConfirmPassword)
    <div class="col-md-10">
        @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
    </div>
</div>

It turns out in this app so far we’re not using display elements, but we could go a similar path (surrounding the element with a span tag etc).

So what about those other methods, the “PasswordFor” and so on? In the next article, we’ll look at replacing all of the form helpers with our version, based solely on metadata that already exists on our view models.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

Conventional HTML in ASP.NET MVC: Adopting Fubu conventions

Fri, 07/11/2014 - 17:42

Other posts in this series:

Now that we’ve established a base for programmatically building out HTML, we can start layering on top more intelligent model-centric conventions for both displaying and editing data. Eventually, I want to get to the point of not just supporting simple conventions like “DateTime = date picker” and “bool = checkbox” but much more powerful ones. Things like “a property named ‘Comments’ should be a textarea” or “a property of an entity type should make its dropdown options the list of items from the database”. These are all things that are universal to the metadata found on those properties.

On top of that, I still want to enable customization, but at the HTML tag level. Ultimately, these builders build one or more tags, but nothing bigger than that. I don’t want to use templating for this – complex logic inside a template is difficult to do, which is why you have concepts like Ember views or Angular directives. I want to build an equivalent to those, but for MVC.

I built a rather lousy, but functional version, years ago, but missed the concept of an object model to build HTML tags. That lousy version was ported to MVC Contrib, and should not be used by anybody under any circumstances. Instead, I’ll pull in what FubuMVC already built, which turns out is built on top of the HtmlTags library.

I’m not going to use any of the other pieces of FubuMVC – just the part that conventionally builds HTML tags. First things first, we’ll need to get the Fubu MVC conventions and related packages up and running in our app.

Integrating Fubu Conventions

First, we’ll need to install the correct packages. For this, we’ll just need a couple:

  • FubuMVC.Core.UI
  • FubuMVC.StructureMap3

These two pull down a number of other packages. To make things easier on ourselves, we’ll also install the StructureMap package for integrating with MVC 5:

  • StructureMap.MVC5

Once that’s done, we have StructureMap plugged in to MVC, and the components ready for plugging FubuMVC into ASP.NET MVC. We’ll need to make sure that the correct assemblies are loaded into StructureMap for scanning:

Scan(
    scan => {
        scan.AssemblyContainingType<IFubuRequest>();
        scan.AssemblyContainingType<ITypeResolver>();
        scan.AssemblyContainingType<ITagGeneratorFactory>();
        scan.AssemblyContainingType<IFieldAccessService>();
        scan.AssemblyContainingType<StructureMapFubuRegistry>();

        scan.TheCallingAssembly();
        scan.WithDefaultConventions();
        scan.LookForRegistries();
    });

We just make sure we add the default conventions (IFoo –> Foo) for the Fubu assemblies we referenced as part of the NuGet packages. Next, we need to configure the pieces that normally are done through FubuMVC configuration, but because we’re not pulling all of Fubu, we need to do through container configuration:

public class FubuRegistry : Registry
{
    public FubuRegistry()
    {
        var htmlConventionLibrary = new HtmlConventionLibrary();
        htmlConventionLibrary.Import(new DefaultHtmlConventions().Library);
        For<HtmlConventionLibrary>().Use(htmlConventionLibrary);

        For<IValueSource>().AddInstances(c =>
        {
            c.Type<RequestPropertyValueSource>();
        });
        For<ITagRequestActivator>().AddInstances(c =>
        {
            c.Type<ElementRequestActivator>();
            c.Type<ServiceLocatorTagRequestActivator>();
        });
        For<HttpRequestBase>().Use(c => c.GetInstance<HttpRequestWrapper>());
        For<HttpContextBase>().Use(c => c.GetInstance<HttpContextWrapper>());
            
        For<HttpRequest>().Use(() => HttpContext.Current.Request);
        For<HttpContext>().Use(() => HttpContext.Current);

        For<ITypeResolverStrategy>().Use<TypeResolver.DefaultStrategy>();
        For<IElementNamingConvention>().Use<DotNotationElementNamingConvention>();
        For(typeof(ITagGenerator<>)).Use(typeof(TagGenerator<>));
        For(typeof(IElementGenerator<>)).Use(typeof(ElementGenerator<>));
    }
}

There’s a bit here. First, we create an HtmlConventionLibrary, import default conventions, and register this instance with the controller. We’re going to modify this in the future but for now we’ll use the defaults. This class tells FubuMVC how to generate HtmlTag instances based on element requests (more on that soon). Next, we register a value source, which is analogous to a ValueProvider in MVC. The ITagRequestActivator is for filling in extra details around a tag request (again, normally filled in with FubuMVC configuration).

Since FubuMVC still has pieces that bridge into ASP.NET, we need to register the HttpContext/Request classes based on HttpContext.Current. In the future ASP.NET version, this registration would go away in favor of Web API’s RequestContext.

The ITypeResolverStrategy determines how to resolve a type based on an instance. I included this because, well, something required it so I registered it. Much of this configuration was a bit of trial-and-error until pieces worked. Not a knock on Fubu, since this is what you deal with bridging two similar frameworks together. Still much cleaner than bridging validation frameworks together *shudder*.

The IElementNamingConvention we’re using tells Fubu to use the MVC-style notation for HTML element names (foo[0].FirstName). Finally, we register the open generic tag/element generators. Even though the naming convention is IFoo->Foo, StructureMap doesn’t automatically register open generics.

This is the worst, ugliest part of integrating Fubu into ASP.NET MVC. If you can get past this piece, you’re 100 yards from the marathon finish line.

Now that we have Fubu MVC configured for our application, we need to actually use it!

Supplanting the helpers

Because the EditorFor and DisplayFor are impossible to completely replace, we need to come up with our own methods. FubuMVC exposes similar functionality in InputFor/DisplayFor/LabelFor methods. We need to build HtmlHelper extensions that call into FubuMVC element generators instead:

public static class FubuAspNetTagExtensions
{
    // Similar methods for Display/Label
    public static HtmlTag Input<T>(this HtmlHelper<T> helper, 
        Expression<Func<T, object>> expression)
        where T : class
    {
        var generator = GetGenerator<T>();

        return generator.InputFor(expression, model: helper.ViewData.Model);
    }

    private static IElementGenerator<T> GetGenerator<T>() where T : class
    {
        var generator = DependencyResolver.Current.GetService<IElementGenerator<T>>();
        return generator;
    }
}

We build an extension method for HtmlHelper that accepts an expression for the model member you’re building an input for. Next, we use the dependency resolver (service location because MVC) to request an instance of an IElementGenerator based on the model type. Finally, we call the InputFor of IElementGenerator to generate an HtmlTag based our expression and model. Notice there’s no ModelState involved (yet). We’ll get to validation in the future.

Finally, we need to use these Label and Input methods in our forms. Here’s one example from the Register.cshtml view from the default MVC template:

<div class="form-group">
    @Html.Label(m => m.Email).AddClass("col-md-2 control-label")
    <div class="col-md-10">
        @Html.Input(m => m.Email).AddClass("form-control")
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
    <div class="col-md-10">
        @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
    </div>
</div>

I left the second alone to contrast our version. So far not much is different. We do get a more elegant way of modifying the HTML, instead of weird anonymous classes, we get targeted, explicit methods. But more than that, we now have a hook to add our own conventions. What kinds of conventions? That’s what we’ll go into the next few posts.

Ultimately, our goal is not to build magical, self-assembling views. That’s not possible or desirable. What we’re trying to achieve is standardization and intelligence around building model-driven input, display, and label elements. If you’re familiar with Angular directives or Ember views, that’s effectively what our conventions are doing – encapsulating, with intelligent, metadata-driven HTML elements.

Next up: applying our own conventions.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs

Survey of two large MVC projects

Wed, 06/25/2014 - 17:17

A large-ish MVC project in which I led the architecture is hitting a milestone of 12 months in development (though released to production for some months now). It’s a similar project to the one where AutoMapper came from, but this time targeting a more focused domain, and subject of the How We Do MVC post.

Much of the patterns discussed come from a certain context, especially on optimizations I look at for accelerating delivery that don’t necessarily apply to other systems. Some comparison stats between these two projects:

Project A

  • ~6 years of continuous development at various pace
  • Over 100 deployments to customers statewide
  • 352 Controllers
  • 1079 Actions
  • 3 actions/controller

Project B

  • 12 months of continuous development at continuous pace
  • At least one deployment to a customer, a few more planned this year, then dozens the next
  • 71 Controllers
  • 534 Actions
  • 7.5 actions/controller

So while B only has 20% of the controllers of A, it has half the actions. This is for a couple of reasons:

  • 6 years ago AJAX was difficult for accessibility. Not the case any more, so AJAX plays a much bigger role
  • Task-based UIs mean a lot more contextual actions take place on one screen, depending a large number of factors

All these “put XYZ” on a diet talks, preferring slices over layers, and in general wanting new features to only add classes and files and not modify them is because of the scope of projects I generally deal with. I have to come up with tools and techniques to address design challenges of this scope, so tools like AutoMapper, the mediator pattern, feature folders, HTML conventions, slices over layers, no convoluted project structure and so on are critical to allow this sort of project to continue at a pace without slowing down under its own weight.

In this project, we had no repositories. No layered project structure. No abstractions over dependencies. No vegetable-based architectures. The last 12 months had roughly 250 working days, which averages out to a new controller every 3.5 days and a little over 2 new controller actions every single day. That sort of pace can only come from a laser focus on highly cohesive code, where each new feature only added requisite classes for feature where pieces differed, and allowing conventions to fill in mundane details that we intended to be consistent site-wide.

I’ve already covered our designs in our controllers, next, I’ll pick up the conventional HTML post that allowed us to create a highly streamlined process for building out our views (and how we extended this concept to client-side templates).

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

Categories: Blogs