MVC4 validate Date to be today or after? - asp.net-mvc

I have a playlist Model class in MVC4 that has a Date property, and when a user creates it, I want them not to be able to specify a date before today (so today or after).
Here's part of my Playlist class:
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[Required(ErrorMessage = "Incorrect date format.")]
public DateTime Date { get; set; }
How do I add validation for this "range"? Right now it's only validating to see if it's a valid date, but 11/30/2012 is valid and won't throw up any errors even though it was yesterday.
I'm using Razor for my Views. Thank you.

You can't validate against dynamic values using the Range attribute. You can create your own validator based on ValidationAttribute that validates the date against the current or a calculated date. Or you can use the IValidatableObject interface in your model class (buddy class to stop it getting overwritten by EF), and validate the properties you want there.

Related

should I remover all [DataType(DataType.Date)] from my models?

I was having a problem where two fields "BattleStartDate" and "BattleEndDate" where not displaying on my edit form, even though the correct vales had been set on the DB when the record was created. The Create and Edit views both use a common partial View _BattleEditFields.
My old model:
[DisplayName("Battle Start Date")]
[Required(ErrorMessage = "Enter date (mm/dd/yyy) when the battle started")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[DataValidation(ValidationType.RangeValidation, "The battle starting date must be after 1/1/1860 and before 6/1/1865.")]
public DateTime BattleStartDate { get; set; }
[DisplayName("Battle End Date")]
[Required(ErrorMessage = "Enter date (mm/dd/yyy) when the battle ended")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[DataValidation(ValidationType.RangeValidation, "The battle ending date must be after 1/1/1860 and before 6/1/1865.")]
[DataValidation(ValidationType.CompareDates, "The battle ending date must be equal to or greater than the start date.", compareWith: "BattleStartDate")]
public DateTime BattleEndDate { get; set; }
I noticed that at runtime I got the following error message.
error CS0103: The name 'type' does not exist in the current contex
Once I updated the model to removed the [DataType(DataType.Date)] from both fields, every thing worked fine. I have several other date fields that also have [DataType(DataType.Date)] in the model (see below). Should I just go ahead and remove all of them, even though it does not appear to be causing a problem?? (just have to go back an test the change).
-- these are audit type fields and not displayed to the user --
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime BattleDateAccepted { get; set; }
// --------------------------------------------------------------------------------------------
public string BattleChangedBy { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime BattleDateChange { get; set; }
Normally we would advise against this, but it is advised that you try to follow conventions and patterns in your code, so seeing some Date properties with this attribute and not others can easily lead to confusion, some developers down the track might add it back to those that are missing, other devs might remove it from all of them as you are suggesting here. So this becomes a depends kind of scenario...
Firstly identify why you are using the DataType(DataType.Date) attribute in the first place, in MVC the first reason is usually for validation, however this attribute can also be used in DB ORM libraries that manage your database schema like Entity Framework to ensure that the type of the field in the database should be a Date ONLY data type.
EF has other attributes that can be used for the same purpose, in MVC apps it is common to use a convention to map this attribute to reduce the risk of the two attributes being set with conflicting values.
If you are using an ORM that needs this attribute to manage the database schema, then each of these attributes that you remove may need a corresponding change set elsewhere in your model to ensure that the DB schema is not affected.
This attribute is heavily referenced in MVC validation documentation and is a the minimal configuration for Date input validation. Removing this attribute from the model might still allow invalid values to be accepted through your API, even if the view (due to your other validation attributes) correctly generates the validation in the UI. If your API is not exposed to external callers this may not be a concern to you.
As you have identified that the fields that have this attribute, but are not displayed in the UI do not cause this error you should look into your view code and configuration, to see if you are using a 3rd party control package that is missing a component.
'type' does not exist in the current context is NOT a common error associated with this attribute specifically, but could occur with custom control or UI validation code that references mismatched assemblies, usually a .Net FX UI component in a .Net Core project or vice versa.
In your case, if removing the DataType attribute resolves your error AND has no other adverse effects on your application runtime OR deployment, then remove it. If your model is not exposed through an API to external callers or you would not be letting external callers modify the other fields, then for consistency I would recommend removing this attribute from all the DateTime fields.
Because this is a against the normal MVC expectations for validation, I would include a note about this in your documentation for the model/project so you remember why you have made this decision.
If you have reasons other than validation for keeping the attributes you should investigate further to understand the cause before you apply this to all Date fields in your entire model.

DataAnnotations Date Range

In my MVC4 project I have a Meta class where I have my date format specified with DataAnnotations. I want to limit the range to the SQL DateTime type.
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[Range(typeof(DateTime), "01/01/1753", "12/31/9999", ErrorMessage = "Check Date")]
public DateTime SeniorityDate
{
get;
set;
}
The format works fine without the range validation. When I add the range validation and I enter an invalid date I get the error message specified. The issues is when I fix the date again to something like 01/27/2008 then the validator still indicates the date is not valid. I assumed this is because I am not entering nor do I want a time component. Is there a way around this issue?
I ended up modifying code listed here to meet my needs.
http://www.headspringlabs.com/blog/mvc-custom-unobtrusive-validator-attribute-date-range-validation/

Requiring Date and Time

I need a datetime. I currently have:
Model:
[DisplayFormat(DataFormatString = "{0:f}", ApplyFormatInEditMode = true)]
public DateTime DateFrom { get; set; }
Controller:
assetBookingModel.DateFrom = DateTime.Now.AddDays(1);
View:
#Html.EditorFor(model => model.DateFrom)
This displays a text box with a date and no time. I can add a calendar extender with a time property without too much problems, but MVC doesn't seem to have any proper validation for this, or add in the time by default.
I have searched the web and there isn't too much help to be found.
What is the best way to go about implementing a Date and Time field, that will not accept only the Date.
This is what I'd use, [CustomValidation]. Allows you to create your own validation function. A few useful examples are here:
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.customvalidationattribute%28v=vs.95%29.aspx

Date range validation with Entity Framework 4 data annotations

I am using Entity Framework 4 to provide the model for a ASP.NET MVC3 / Razor2 web application. I am using DataAnnotations to implement validation. I need to limit some dates to the range accepted by the SQL smalldatetime type.
My problem is that I can't get the RangeAttribute to work correctly for a date field. The model metadata definition for the field in question is:
[Display(ResourceType = typeof(Resources.Patient), Name = "DateOfBirth_Name")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[DataType(DataType.Date)]
[Range(typeof(DateTime), "01/01/1900", "06/06/2079", ErrorMessageResourceType = typeof(Resources.Patient), ErrorMessageResourceName = "DateOfBirth_Range")]
public System.DateTime DateOfBirth { get; set; }
With this code, whatever value I put into the date field, it is treated as invalid by the application. In case its' relevant, I am using the JQuery-UI date picker with the field in question as well.
Can anyone help please?
You do not specify where the error occurs, but my guess is that it is client-side(?) jQuery Validation does not work well with the RangeAttribute. To verify, disable jQuery Validation and the valid input should pass the (server) validation.
To get around this you will have to write your own date range validation, e.g. http://blogs.msdn.com/b/stuartleeks/archive/2011/01/25/asp-net-mvc-3-integrating-with-the-jquery-ui-date-picker-and-adding-a-jquery-validate-date-range-validator.aspx
Alternatively you could look into packages such as Data Annotations Extensions or MVC Foolproof Validation to see if they could be used for solving the problem.

In ASP.NET MVC 4, how to validate that a DateTime value is entered on the correct format?

In our ASP.NET MVC 4 application, one of the models has a field of the DateTime type. When editing such model objects via a form, the value for the DateTime field has to be non-empty and on the format yyyy-MM-dd H:mm:ss (e.g., 2012-10-17 10:49:00). How do I ensure this field is correctly validated in the application? I've tried the following annotations:
[System.ComponentModel.DataAnnotations.Required]
[System.ComponentModel.DataAnnotations.DisplayFormat(DataFormatString="yyyy-MM-dd H:mm:ss",
ApplyFormatInEditMode=true)]
However, validation of form data doesn't require all components of the format to be present. For instance, the value '2012-10-17' is accepted (leaving out the 'H:mm:ss' part). It's just verified that the field contains a valid DateTime string.
How should I ensure that this DateTime field is indeed on my specified format (yyyy-MM-dd H:mm:ss)?
Alternative solution - view-only model class
Darin's solution is of course valid, but it's not the only one you can use. And it would require you to write more complex code than with this solution that I'm going to show you here.
So this is an alternative. I'd suggest that instead of creating a custom model binder you rather create a separate view model class that instead of taking DateTime takes a string where you can set as complex validation regular expression as you like. And then have a method on it that would translate it to your application/domain model class instance (and back).
// suppose this app model
public class User
{
[Required]
public string Name { get; set; }
[Required]
public DateTime DateOfBirth { get; set; }
}
public class ViewUser
{
[Required]
public string Name { get; set; }
[Required]
[RegularExpression("\d{4}-\d{2}-\d{2}(?:\s\d{1,2}:\d{2}:\d{2})?")]
public string DateOfBirth { get; set; }
public ViewUser(User user)
{
this.Name = user.Name;
this.DateOfBirth = user.DateOfBirth.ToString("yyyy-MM-dd H:mm:ss");
}
public User ToPoco()
{
return new User {
Name = this.Name,
DateOfBirth = DateTime.Parse(this.DateOfBirth, "yyyy-MM-dd H:mm:ss")
};
}
}
With a bit of tweaking you could inherit ViewUser from User class and use new keyword on DateOfBirth and use base property to store correct typed value. In that case you wouldn't need the ToPoco method.
Note: you will have to use DateTime.TryParseExact method to parse your dates because they may include time or they may not. I didn't include that in my code because it depends on the exact requirements of your date input.
You could write a custom model binder which will use the exact format you have specified in the DisplayFormat attribute. I have shown an example of how this could be achieved in this post.
Also don't be confused into thinking that the DisplayFormat attribute overrides the Required attribute. The DisplayFormat is only used for displaying the field in the input field. It is not a validation attribute. It has strictly nothing to do with validation and when the form is POSTed to the server it is never used.

Resources