Turning off validation for properties in a MVC model

Sometimes it is required that some properties in a MVC model should not be validated, but the rest are required and should be validated in the client view. Mostly I cannot turn off client validation for all properties in the model.

Here is an example of a Model class. I need to validate 2 properties and the other 2 should not be validated. (client side).

using System;
namespace Mvc4DateTimeClientValidationTest.Models
{
    public class TestModel
    {
        public DateTime Date1 { get; set; }
        public DateTime? Date2 { get; set; }

        public DateTime NoValidationDate1 { get; set; }
        public DateTime? NoValidationDate2 { get; set; }
    }
}

To achieve this, the HtmlHelper class is extended.

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Routing;
using System.Web.Mvc;

namespace Mvc4DateTimeClientValidationTest
{
    public static class HtmlHelperExtensions
    {
        public static MvcHtmlString HiddenForWithoutClientValidation<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
        {
            return HiddenForWithoutClientValidation(htmlHelper, expression, null);
        }

        public static MvcHtmlString HiddenForWithoutClientValidation<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
        {
            var name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText(expression));
            var id = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(ExpressionHelper.GetExpressionText(expression));

            var value = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model;
            var routeValueDictionary = htmlAttributes != null ? new RouteValueDictionary(htmlAttributes) : new RouteValueDictionary();

            return HiddenForWithoutClientValidation(name, id, value, routeValueDictionary);
        }

        private static MvcHtmlString HiddenForWithoutClientValidation(string name, string id, object value, IEnumerable<KeyValuePair<string, object>> routeValueDict)
        {
            var input = new TagBuilder("input");
            if (!string.IsNullOrEmpty(id))
            {
                input.Attributes.Add("id", id);
            }
            input.Attributes.Add("name", name);
            input.Attributes.Add("type", "hidden");
            foreach (var routeValue in routeValueDict)
            {
                input.MergeAttribute(routeValue.Key, routeValue.Value.ToString(), true);
            }

            if (value != null)
            {
                input.Attributes.Add("value", value.ToString());
            }

            return new MvcHtmlString(input.ToString(TagRenderMode.SelfClosing));
        }
    }
}

No changes are required for the controller class, unless I validate the model server side

 public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var t = new TestModel
                {
                    Date1 = DateTime.Now,
                    Date2 = DateTime.Now,
                    NoValidationDate1 = DateTime.Now,
                    NoValidationDate2 = DateTime.Now
                };
            return View(t);
        }
    }

And here’s how the new extension is used in the Razor view: (@Html.HiddenForWithoutClientValidation(m => m.NoValidationDate1))

@using System.Web.Optimization
@using Mvc4DateTimeClientValidationTest

@model Mvc4DateTimeClientValidationTest.Models.TestModel
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="de-DE">
    <head>
        <title>title</title>
        @Scripts.Render("~/bundles/jquery")
        @Scripts.Render("~/bundles/jqueryui")
        @Scripts.Render("~/bundles/jqueryval")
        @Styles.Render("~/Content/css")
        @Styles.Render("~/Content/themes/base/css") 
    </head>
    <body>
        <div>
            @Html.HiddenFor(m => m.Date1)
            @Html.HiddenFor(m => m.Date2)
            
            @Html.HiddenForWithoutClientValidation(m => m.NoValidationDate1)
            @Html.HiddenForWithoutClientValidation(m => m.NoValidationDate2)

        </div>
    </body>
</html>

Using Firebug, the result can be viewed. You can see the difference in the html input controls. 2 input controls will be validated client side and 2 will not be validated.
htmlValidationTags

This could also be achieved in the view using javascript.

Code: https://github.com/damienbod/Mvc4DateTimeClientValidationTest

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: