Search code examples
javascriptasp.netasp.net-mvc-3validationmodels

ASP.NET MVC3: Why are my custom validation attributes never working?


Basically, I have correctly followed different tutorials. Now, my models are taken from a library file (dll) which shouldnt be a problem as everything else functions fine.

My model:

public class RoomBookingInsert
{

    public Int32 CostCentreNo { get; set; }
    public Int32 CustomerAccNo { get; set; }
    public Int32 RoomNo { get; set; }
    public Int32 ServiceCode { get; set; }
    [PriceValidation]
    public Decimal HourlyRate { get; set; }
    [DataType(DataType.Date)]
    [DateRange("2010/12/01", "2010/12/16")]
    public DateTime StartDate { get; set; }
}

The attributes ARE recognised, as they go blue accordingly, and autocomplete detects them. However, when I post my form, it accepts anything.

I have included my code below for validation attributes, and I recognise that this is server side, and so happens on the post command.

My Form in asp.net mvc3 using razor:

@model MyLibrary.RoomBookingInsert

@{
    ViewBag.Title = "Temp";
}

<h2>Temp</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>RoomBookingInsert</legend>

        @Html.EditorForModel()
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

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

Here is my first Price validation (ensuring that it never goes negative).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

    public class PriceValidationAttribute : ValidationAttribute

    {
        private decimal minPrice = 0.00M;
        private decimal maxPrice = 100.00M;

            public PriceValidationAttribute()
            {
            }
            public override bool IsValid(object value)
            {
                decimal price = (decimal)value;
                if (price < this.minPrice || price > this.maxPrice)
                    return false;
                return true;
            }

    }

Here is my Date Range validation:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Globalization;

    public class DateRangeAttribute : ValidationAttribute
    {
        private const string DateFormat = "yyyy/MM/dd";
        private const string DefaultErrorMessage =
               "'{0}' must be a date between {1:d} and {2:d}.";

        public DateTime MinDate { get; set; }
        public DateTime MaxDate { get; set; }

        public DateRangeAttribute(string minDate, string maxDate)
            : base(DefaultErrorMessage)
        {
            MinDate = ParseDate(minDate);
            MaxDate = ParseDate(maxDate);
        }

        public override bool IsValid(object value)
        {
            if (value == null || !(value is DateTime))
            {
                return true;
            }
            DateTime dateValue = (DateTime)value;
            return MinDate <= dateValue && dateValue <= MaxDate;
        }
        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentCulture,
                ErrorMessageString,
                name, MinDate, MaxDate);
        }

        private static DateTime ParseDate(string dateValue)
        {
            return DateTime.ParseExact(dateValue, DateFormat,
                 CultureInfo.InvariantCulture);
        }

}

Solution

  • The page will not be automatically validated. In order to validate the page what you need to do on your controller is something like this:

    // Guessing your view is called Temp...
    public class TempController : Controller
    {
        // This method will create the view with the RoomBookingInsert model
        // NOTE: it has no HttpPost attribute
        public ActionResult Temp()
        {
             return View(new MyLibrary.RoomBookingInsert());
        }
    
        // This is the post back action method for your view
        // NOTE: this has an HttpPost attribute
        [HttpPost]
        public ActionResult Temp(MyLibrary.RoomBookingInsert model)
        {
            // Always start by checking the model state and if it is not valid
            // return the view with the original model
            if(!ModelState.IsValid)
            {
                return View(model);
            }
    
            // Rest of logic goes here
            ...
        }
    
    }