New Validation Attributes in ASP.NET MVC 3 Future

     Introduction:

 

          Validating user inputs is an very important step in collecting information from users because it helps you to prevent errors during processing data. Incomplete or improperly formatted user inputs will create lot of problems for your application. Fortunately, ASP.NET MVC 3 makes it very easy to validate most common input validations. ASP.NET MVC 3 includes Required, StringLength, Range, RegularExpression, Compare and Remote validation attributes for common input validation scenarios. These validation attributes validates most of your user inputs but still validation for Email, File Extension, Credit Card, URL, etc are missing. Fortunately, some of these validation attributes are available in ASP.NET MVC 3 Future. In this article, I will show you how to leverage Email, Url, CreditCard and FileExtensions validation attributes(which are available in ASP.NET MVC 3 Future) in ASP.NET MVC 3 application.

 

    Description:

 

          First of all you need to download ASP.NET MVC 3 RTM Source Code from here. Then extract all files in a folder. Then open MvcFutures project from mvc3-rtm-sources\mvc3\src\MvcFutures folder. Build the project. In case, if you get compile time error(s) then simply remove the reference of System.Web.WebPages and System.Web.Mvc assemblies and add the reference of System.Web.WebPages and System.Web.Mvc 3 assemblies again but from the .NET tab and then build the project again, it will create a Microsoft.Web.Mvc assembly inside mvc3-rtm-sources\mvc3\src\MvcFutures\obj\Debug folder. Now we can use Microsoft.Web.Mvc assembly inside our application.

 

          Create a new ASP.NET MVC 3 application. For demonstration purpose, I will create a dummy model UserInformation. So create a new class file UserInformation.cs inside Model folder and add the following code,

 

    public class UserInformation
    {
        [Required]
        public string Name { get; set; }

        [Required]
        [EmailAddress]
        public string Email { get; set; }

        [Required]
        [Url]
        public string Website { get; set; }

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

        [Required]
        [FileExtensions(Extensions = "jpg,jpeg")]
        public string Image { get; set; }
    }

 

          Inside UserInformation class, I am using Email, Url, CreditCard and FileExtensions validation attributes which are defined in Microsoft.Web.Mvc assembly. By default FileExtensionsAttribute allows png, jpg, jpeg and gif extensions. You can override this by using Extensions property of FileExtensionsAttribute class.

 

          Then just open(or create) HomeController.cs file and add the following code,

 

    public class HomeController : Controller
    {

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index(UserInformation u)
        {
            return View();
        }

    }

 

          Next just open(or create) Index view for Home controller and add the following code,

 

@model NewValidationAttributesinASPNETMVC3Future.Model.UserInformation

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>UserInformation</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Email)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Email)
            @Html.ValidationMessageFor(model => model.Email)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Website)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Website)
            @Html.ValidationMessageFor(model => model.Website)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.CreditCard)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.CreditCard)
            @Html.ValidationMessageFor(model => model.CreditCard)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Image)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Image)
            @Html.ValidationMessageFor(model => model.Image)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

 

          Now just run your application. You will find that both client side and server side validation for the above validation attributes works smoothly. 

 

           

 

    Summary:

 

          Email, URL, Credit Card and File Extension input validations are very common. In this article, I showed you how you can validate these input validations into your application. I explained this with an example. I am also attaching a sample application which also includes Microsoft.Web.Mvc.dll. So you can add a reference of Microsoft.Web.Mvc assembly directly instead of doing any manual work. Hope you will enjoy this article too.

 

20 Comments

  • where can one find a complete list of validators and html helpers and their documentation?

  • @mike, see
    http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx

  • So everything appears to work with the exception of the CreditCard. Even when I enter a valid card number, validation generates an error. Is there some configuration involved or did I miss a step?

  • @Greg Hayden
    Can you provide examples of valid credit card numbers which are not working?

  • Email validation is definitely included in MVC3 as standard. Use the [DataType(DataType.EmailAddress)] attribute :)

  • Okay, ignore my previous comment, that doesn't actually DO validation. I read elsewhere that it does. My bad! :*

  • DataType really does not perform any validation, it was just not invented for that. But the name is misleading, I was just told recently by Dino Esposito in an MVC 3 training :)

  • imran how to validate a file being uploaded. i want it to be an image file of size less than 10k and check its size in pixels as well. is it possible with some validation attribute. if not what's the preferred way of doing this?
    regards

  • imran how to validate a file being uploaded. i want it to be an image file of size less than 10k and check its size in pixels as well. is it possible with some validation attribute. if not what's the preferred way of doing this?
    regards

  • @Vinod,

    See
    http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.metadatatypeattribute.aspx

  • Hello,

    Validating an email adress is simpel. Just use this:

    [RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}")]

    Greetings Madreeman.

  • I've tried to use the FileExtensions property in my model with a file upload, and while it validates on the client side correctly, it then fails the server side validation for the file extension. This is because the ModelState.Values().Value.AttemptedValue is of type HttpPostedFileBase, so it is unable to validate whether the text contains the extensions I've defined in the model.
    (if I change the form so it doesn't do a form.post, the AttemptedValue is a string and it validates correctly - but it obviously won't do the file upload)

    Has anyone found a way to make this work with a fileupload (input type="file")?

  • @Mick,I have just rechecked this, it is working. Make sure you have

    @Html.TextBoxFor(model => model.Image, new { type = "file" })
    and
    public HttpPostedFileBase Image { get; set; }
    and
    enctype = "multipart/form-data"

  • Hey dear,
    Nice work.
    :)

  • Should any one clear me why we use that server side validation instead of that we would use Java script validation or Regular Expression, which would not hit the server.....

  • @tahazubairahmed, Because Client Side Validation can easily break.

  • hey dear unfortunately my validation not working
    #My code in cshtml
    @using (Html.BeginForm("AddDownload", "Product", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
    @Html.ValidationSummary(true)

    DownloadModels

    @Html.LabelFor(model => model.DName)


    @Html.EditorFor(model => model.DName)
    @Html.ValidationMessageFor(model => model.DName)


    @Html.LabelFor(model => model.DFilePath)


    @Html.TextBoxFor(model => model.DFilePath, new { type = "file" })
    @Html.ValidationMessageFor(model => model.DFilePath)






    }

    #this is Model
    public class DownloadModels
    {
    public int DID { get; set; }

    [Required(ErrorMessage = "Download name required")]
    [DataType(DataType.Text)]
    [StringLength(200, ErrorMessage = "Must be under 200 characters")]
    [Display(Name = "Download Name")]
    public string DName { get; set; }

    [Required(ErrorMessage = "Photo name required")]
    [Display(Name = "Upload File")]
    [FileExtensions(Extensions = "txt,doc,pdf", ErrorMessage = "Please upload valid format")]
    public HttpPostedFileBase DFilePath { get; set; }

    [Display(Name = "Create Date")]
    public DateTime CreateDate { get; set; }
    [Display(Name = "Is Active")]
    public bool IsActive { get; set; }
    }

  • @manoj, can you provide me sample application?

  • @imran,

    MVC 3 Data Annotations usage question please.

    I have domain classes that I view as "the full deal". Ie, they have all their possible properties defined, especially things like maximum string length, range, possibly regexps for validity checks etc. These attributes seem to me to be domain relevant attributes.

    I also have many view models that pick and choose from those domain classes what properties make sense for this particular view. I was hoping to use MetadaType to get the annotations defined on my domain class over to my ViewModel. This "centralizes" the relevant annotations in one place.

    But, alas, it appears that using MetadataType forces me to include ALL properties defined in the referenced class (in my case the domain class) into my view model. Not quite what I was thinking. When I leave out properties in the view model that are present in the annotated domain class, I get the error: The associated metadata type for type 'XXX' contains the following unknown properties or fields: xxxprop. Please make sure that the names of these members match the names of the properties on the main type.

    Is this not a useful pattern? Is there a better way to accomplish what I am trying to do? It seems "natural" to me...

    Thanks, and good post

  • @jwdaigle, Please ask your question on forums.asp.net/1146.aspx or stackoverflow.com

Comments have been disabled for this content.