Tag Archives: Validation

Database driven Asp.net MVC Model Binding, Validation, and Metadata

One of classic MVC paradigms is that you can bind class models to a view, and with attribute based annotations, you can have synchronized server and client side validations on them. This concept is absolutely brilliant! Code once and you don’t have to worry about duplicating your server side logic in the untrustworthy browser.

This is all fine and dandy if your validation logic and your models don’t change often. Consider the scenario that you are developing an application that will likely change over time. Or perhaps, you need to develop your app such that the client has put it in the requirements that they need to have control over the content long after you have completed the app. If they need to control the content and the form fields (inputs), those inputs will still need to be validated.

Enter database driven model validation, binding and metadata.

I have successfully developed implementations of the following, which accomplish exactly what I need:

ModelBinder
ModelValidationProvider
ModelMetadataProvider

My implementations heavily leverage the power of the extensible MVC DataAnnotations providers which read the attribute based metadata that you can decorate your classes with.

The code that I have written is currently in a state that is tightly bound to the database schema of the project I am currently working on. My plan is to extract the juice from the project so that the code is reusable to all.

I’m sorry to say that at this point, I have no code examples, but they will surely follow!

An exploration of HTML5 Editor Templates with MVC

It occurred to me that we should be using the input type = email in our WebCenter 6 project.  I thought editor templates would be the right way to do this.

If you download the rtm sources for asp.net who will find the MVC 3 Futures source.  This has 2 interesting folders, DisplayTemplates and EditorTemplates inside a folder called DefaultTemplates.  Whenever you use Html.DisplayFor or Html.EditorFor, these templates are used.   You don’t have to download these templates for editor for or default for to work, the code for these is actually packed inside a resource file inside the mvc assembly.  You also might want to check out the source for these.

Default Templates Folder

I wanted to check to see if there was a template for an EmailAddress.  Interestingly, I found a Display template, but not an Editor template.

Display Templates

The display template for email looks like this:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<a href="mailto:<%= Html.AttributeEncode(Model) %>"><%= Html.Encode(ViewData.TemplateInfo.FormattedModelValue) %></a>

You can see that all it does is add a mailto link.

I started first by creating an EditorTemplates folder inside of our root Views/Shared folder.  Then I created a partial view control named EmailAddress.  I names it email address because editor and display templates are used according to the following rules:

http://scottonwriting.net/sowblog/archive/2011/11/22/using-templates-to-display-boolean-values-as-yes-no-options.aspx?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+ScottOnWriting+%28Scott+on+Writing%29

Specifically, the Html.DisplayFor and Html.EditorFor methods consult the following metadata in this order:

  1. The UIHint attribute – specifies the name of the template to use.
  2. The DataType attribute
  3. The data type

The data type is set from the DataAnnotations attribute:

        [DataType(DataType.EmailAddress)]

The partial view will be exactly the same as the editor template for a string except that the type will be changed.

Here is the string control:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line" }) %>

But my email address control is going to do this with razor:

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", type = "email" }) %>

Here is what validation looks like before I saved this template:

WebCenter 6 Your Profile Validation

Here is what it looks like afterwards.  I have to first change the code from;

                @Html.TextBoxFor(m => m.EmailAddress)

To

                @Html.EditorFor(m => m.EmailAddress)

Now I get this using FireFox.  The RED outline occurs because now I am using an editor template, which puts the correct validation classes:

Shared.css line 3392

.input-validation-error {
    background-color: #FFEEEE;
    border: 1px solid #FF0000;
}

WebCenter 6 Your Profile Validation 2

Interestingly enough, this is still not using HTML 5 validation.  The reason being there is a novalidate attribute on the form:

<form method="post" id="email-form" data-ajax-update="#change-form-email" data-ajax-success="Profile.changeSuccess" data-ajax-mode="replace" data-ajax-method="POST" data-ajax-begin="Modal.Loader.showTop" data-ajax="true" action="/Default/Account/ChangeEmail" style="display: block;" novalidate="novalidate">    <br>
    <div>
        <fieldset>
            <label class="editor-label" for="EmailAddress">New Email Address:</label>
            <div class="editor-field">
                <input type="email" value="" name="EmailAddress" id="EmailAddress" data-val-required="The Email Address field is required." data-val-email="The Email Address field is not a valid e-mail address." data-val="true" class="text-box single-line input-validation-error">
                <span data-valmsg-replace="true" data-valmsg-for="EmailAddress" class="field-validation-error"><span for="EmailAddress" generated="true" class="">The Email Address field is not a valid e-mail address.</span></span>
            </div>

            <div class="form-controls">
                <input type="submit" value="Change Email">
                <input type="button" class="change-cancel" value="Cancel">
            </div>
        </fieldset>
    </div>
</form>

This novalidate attribute is added by jquery.validate line 32:

// Add novalidate tag if HTML5.
this.attr('novalidate', 'novalidate');

According to w3schools:

novalidate novalidate Specifies that the form should not be validated when submitted

If I remove the novalidate attribute using firebug and then try to submit the form:

WebCenter 6 Your Profile Validation 3

The problem that I want you all to think about or research is:

How do we turn jquery validate on or off conditionally based on whether or not html 5 validation will work?  Modernizr gives you test’s for each individual input type, but how do you turn validation ON programatically when html 5 validation has been disabled using the novalidate attribute.  Try it out.

Furthering this, I then realized that there is a Nuget package that adds all of the HTML 5 editor templates.  It actually uses the exact same code that I came up with.  I’m going to add it to our project and see what happens.

https://github.com/srkirkland/Html5MvcTemplates

Html5MvcTemplates

There are also a ton of open source projects out there for Html 5 and mvc 3.  I wouldn’t be surprised if they are going to be built in to Mvc 4.  There is also the HTML 5 mvc 3 helpers which I’m guessing add this kind of code for non editor templates and display templates, using plain old Html.TextBox like syntax:

http://mvchtml5.codeplex.com/

https://github.com/Gutek/MVC-3-Html5EditorFor

Unobtrusive Validation with MVC 3 and Html.BeginForm

Yesterday a colleague of mine and I were trying to find out why client side unobtrusive validation attributes were being generated everywhere EXCEPT one specific page on our upcoming release of WebCenter 6.  Client side validation attributes in MVC 3 are html 5 data-val-*attributes.   They enable you to tie your validation to Data Annotation attributes on your models without having to write a line of javascript code.  This is sweet in my book because the JavaScript is completely decoupled from the actual C# code.

Here is what they look like:

<input type="text"
    name="UserName"
    data-val-required="The Username field is required."
    data-val="true"
    class="text-box single-line" />
  • data-val turns unobtrusive validation on for the input
  • data-val-required enables the required validation rule to kick in with the specified error message you see above

If you want to go into more detail, check out Brad Wilson’s in depth post about Unobtrusive Client Validation in ASP.NET MVC3.

The specific problem we were both encountering was that these attributes were simply not being output on our view when rendered in the browser.

I peeked into the source of System.Web.Mvc.dll and here is what I discovered.

  1. When you render an input using an HtmlHelper like @Html.EditorFor, @Html.TextBox etc., they are rendered with the InputExtensions.InputHelper method.
  2. InputHelper calls HtmlHelper.GetUnobtrusiveValidationAttributes to render the data-val attributes.
  3. GetUnobtrusiveValidationAttributes calls ViewContext.GetFormContextForClientValidation which checks to see if ClientValidation is enabled in the either your web.config or the scope of the view that you are rendering.
  4. GetFormContextForClientValidation will return the FormContext that was instantiated with @Html.BeginForm OR return null.
  5. If it returns null, no attributes are rendered, thus the need for Html.BeginForm.

So to re-cap.  I discovered the problem was that my colleague had NOT created his form using Html.BeginForm.  Instead, he had manually added a <form> tag, which in turn never created the ViewContext.FormContext object.

If you want to see for yourself, go download the latest MVC 3 sources from the ASP.Net site on CodePlex.

In my opinion, this is totally ridiculous.  And I guess the devs over at Microsoft agree because they are removing this requirement in MVC 4.

Here are Brad’s own words:

Important note: jQuery Validate requires your input elements to be inside of a <form> element in order to be validated. In addition, MVC 3 requires that you have called Html.BeginForm() to render this form, so that it can find its book-keeping object to help render the HTML attributes. Starting with MVC 4, we’ve eliminated the need for Html.BeginForm(), but the requirement for the HTML <form> element is still there.