I'm trying to add Data Validation To my DateTime Attribut i want to oblige user to select Date between DateTime.Now and smaller then one years after DateTime.now.addyears(+1)
This is my code :
public class DateDebut : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null) return false;
DateTime enteredDate = (DateTime)value;
if ( (enteredDate >= DateTime.Now) && (enteredDate <= DateTime.Now.AddYears(+1)))
return true;
else
return false;
}
}
[Required]
[Display(Name = "De : ")]
[DataType(DataType.Date)]
[DateDebut(ErrorMessage="Date invalide")]
public DateTime dd { get; set; }
This Custom Validation dosn't work, verification is not excuted, ai think i'm missed something realy simple?
I agree completelt with Daniel,
However I find that when i am needing to do comparisons of properties in my model I use the IValidatableObject
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.ivalidatableobject.aspx
I find it faster and easier for most small types of comparisons
you would have some that looks like this
public class myModel : IvalidatableObject
{
string debut = DateTime.Now.ToShortDateString();
string fin = DateTime.Now.AddYears(+1).ToShortDateString();
[Required]
[Display(Name = "De : ")]
[DataType(DataType.Date)]
public DateTime dd { get; set; }
public IEnumerable<ValidationResult> Validate()
{
if(this.debut > this.fin)
{
yield return new ValidationResult("debut cannot be greated then fin");
}
}
}
read up and see whats best for you
Attributes are static in nature. Have you considered writing your own attribute for validation? There are several examples on the web that should get you started.
You could also inherit from RangeAttribute and inject it as needed.
Related
I have the following piece of code in my model for which I would like to add a custom validator:
[Required]
[Display(Name = "Date Of Birth")]
[DataType(DataType.Date)]
public DateTime DateOfBirth { get; set; }
I tried researching but there is no specific answer. I'd like to know the correct syntax for creating a custom validator for a date
1.Create a class and derive it from ValidationAttribute class and override IsValid method in it and then implement your validation logic inside the method:
public class AgeMajorityValidator : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
DateTime dateOfBirth;
if (!DateTime.TryParse(value.ToString(), out dateOfBirth))
return new ValidationResult("" + validationContext.DisplayName + " is not valid date format");
int age = new DateTime(DateTime.Now.Subtract(dateOfBirth).Ticks).Year - 1;
if (age > 18)
return ValidationResult.Success;
else
return new ValidationResult("Please Enter a Valid Age.");
}
return new ValidationResult("" + validationContext.DisplayName + " is required");
}
2.Use AgeMajorityValidator as an attribute in your model like below:
[Display(Name = "Date Of Birth")]
[DataType(DataType.Date)]
[AgeMajorityValidator]
public DateTime DateOfBirth { get; set; }
I have a little problem, here is my code:
public partial class Tourist
{
public Tourist()
{
Reserve = new HashSet<Reserve>();
}
public int touristID { get; set; }
[Required]
[StringLength(50)]
public string touristNAME { get; set; }
public DateTime touristBIRTHDAY { get; set; }
[Required]
[StringLength(50)]
public string touristEMAIL { get; set; }
public int touristPHONE { get; set; }
public virtual ICollection<Reserve> Reserve { get; set; }
}
}
How can I restrict touristBIRTHDAY to be +18 years old? I think that I have to use this function, but I don't know where to put it:
Note: this function it's an example.
DateTime bday = DateTime.Parse(dob_main.Text);
DateTime today = DateTime.Today;
int age = today.Year - bday.Year;
if(age < 18)
{
MessageBox.Show("Invalid Birth Day");
}
Thanks ;)
UPDATE:
I follow the solution of Berkay Yaylaci, but I'm getting a NullReferenceException. It's seems that my value parameter is default, and then my method is not posting, why? What is the solution to that?
You can write your own Validation. First, create a class.
I called MinAge.cs
public class MinAge : ValidationAttribute
{
private int _Limit;
public MinAge(int Limit) { // The constructor which we use in modal.
this._Limit = Limit;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
DateTime bday = DateTime.Parse(value.ToString());
DateTime today = DateTime.Today;
int age = today.Year - bday.Year;
if (bday > today.AddYears(-age))
{
age--;
}
if (age < _Limit)
{
var result = new ValidationResult("Sorry you are not old enough");
return result;
}
return null;
}
}
SampleModal.cs
[MinAge(18)] // 18 is the parameter of constructor.
public DateTime UserBirthDate { get; set; }
IsValid runs after post and check the Limit. If age is not greater than the Limit (which we gave in modal!) than return ValidationResult
Implement IValidatableObject on your tourist class.
Put your logic in the Validate() method.
You are using MVC so there is no MessageBox.Show(). The MVC model binder will automatically call you validation routine.
Here's another SO question with the details How do I use IValidatableObject?
Also your age logic is wrong. it needs to be
DateTime now = DateTime.Today;
int age = now.Year - bday.Year;
if (now < bday.AddYears(age)) age--;
I have a MVC 4 project where I would like to use functionality similar to DisplayFromat, but setting a DataFormatString is not enough. I would like a function to be called to format the string. Is that possible?
I have tested inheriting DisplayFormat but that just lets me set the DataFormatString.
I have looked at customizing DataAnnotationsModelMetadataProvider, but I don't see how I would make it call a custom function for formatting.
My particular case is that I need to format the integer 201351 as "w51 2013". I couldn't come up with a format string that does that.
The easiest way is to expose a read-only property on your Model:
public class Model{
public int mydata{get; set;}
public string formattedDate{
get{
string formattedval;
// format here
return formattedval;
};
}
}
You can create a custom ValidationAttribute. Here is some code I use to validation someone has selected a drop down value.
using System.ComponentModel.DataAnnotations;
public sealed class PleaseSelectAttribute : ValidationAttribute
{
private readonly string _placeholderValue;
public override bool IsValid(object value)
{
var stringValue = value.ToString();
if (stringValue == _placeholderValue || stringValue == "-1")
{
ErrorMessage = string.Format("The {0} field is required.", _placeholderValue);
return false;
}
return true;
}
public PleaseSelectAttribute(string placeholderValue)
{
_placeholderValue = placeholderValue;
}
}
Then Use it:
[Required]
[Display(Name = "Customer")]
[PleaseSelect("Customer")]
public int CustomerId { get; set; }
I've been getting started with ASP.NET MVC and now have a basic understanding of using a repository pattern with my EF Code First POCO classes and using Ninject for DI.
I'd like to get into proper TDD habits and struggle to fully understand how best to use it along with where to implement some logic.
For example I have the following simplified POCO class:
public int ProjectID { get; set; }
[Required]
[MaxLength(150)]
public string Title { get; set; }
public string Description { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? DueDate { get; set; }
public DateTime? CompletionDate { get; set; }
public virtual ICollection<ProjectCode> ProjectCodes { get; set; }
public virtual ICollection<ProjectTask> ProjectTasks { get; set; }
Here is my Interface (generated by the MVCScaffolding)
public interface IProjectRepository
{
IQueryable<Project> All { get; }
IQueryable<Project> AllIncluding(params Expression<Func<Project, object>>[] includeProperties);
Project Find(int id);
void InsertOrUpdate(Project project);
void Delete(int id);
void Save();
}
I'd like to validate that the DueDate and CompletionDate are later than the StartDate. I'm not sure if I can do this using dataannotations as it's a bit complex although it would be useful to allow the unobtrusive javascript validation to work in my view.
If I can use data annotations I'm not sure how to go about writing tests for this logic.
My other idea was to create a service layer between the controller and interface to perform this validation, but then I can't work out an easy way to do the client / server side validation or how best to implement a basic service to validate the dates as I require.
I expect to have more complex variants on this over time and it would be good to get my architecture "right" now.
I would use DataAnnotations. I found this article very useful on custom data validations. From it I have a GreaterThanAttribute added to my project custom validations, the server side of which looks like:
public class GreaterThanAttribute : ValidationAttribute{
public GreaterThanAttribute(string otherProperty)
: base("{0} must be greater than {1}")
{
OtherProperty = otherProperty;
}
public string OtherProperty { get; set; }
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name, OtherProperty);
}
protected override ValidationResult
IsValid(object firstValue, ValidationContext validationContext)
{
var firstComparable = firstValue as IComparable;
var secondComparable = GetSecondComparable(validationContext);
if (firstComparable != null && secondComparable != null)
{
if (firstComparable.CompareTo(secondComparable) < 1)
{
return new ValidationResult(
FormatErrorMessage(validationContext.DisplayName));
}
}
return ValidationResult.Success;
}
protected IComparable GetSecondComparable(
ValidationContext validationContext)
{
var propertyInfo = validationContext
.ObjectType
.GetProperty(OtherProperty);
if (propertyInfo != null)
{
var secondValue = propertyInfo.GetValue(
validationContext.ObjectInstance, null);
return secondValue as IComparable;
}
return null;
}
}
The DataAnnotation itself is reasonably easy to mock and test.
Please ask if you can't understand what I'm asking.
I have created a custom ValidateAttribute for my ViewModel
i created it for validate properties which depend from another property of ViewModel
if (user checked "01" or "09" from QrupList) Then
Company name is needed
Name,surname and LastName are not needed
else
Company name is not needed
Name,surname and LastName are needed
I have ViewModel as below
[ValidateForGroupAttribute("Group", "CompanyName")]
public partial class AbonentViewModel
{
[DisplayName("Şirkət")]
public string CompanyName { get; set; }
[DisplayName("Soyadı")]
[Required(ErrorMessage = "Soyadı vacibdir")]
public string Surname { get; set; }
[DisplayName("Qrup")]
[Required(ErrorMessage = "Qrup vacibdir")]
public string Group{ get; set; }
public SelectList GroupList { get; set; }
}
My custom ValidationAttribute classes:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class ValidateForGroupAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' a müvafiq '{1}' daxil din";
public ValidateForGroupAttribute(string originalProperty, string confirmPropertyCompany)
: base(_defaultErrorMessage)
{
OriginalProperty = originalProperty;
ConfirmPropertyCompany = confirmPropertyCompany;
}
public string OriginalProperty { get; private set; }
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
OriginalProperty, ConfirmPropertyCompany);
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
object originalValue = properties.Find(OriginalProperty, true).GetValue(value);
object confirmValueCompany = properties.Find(ConfirmPropertyCompany, true).GetValue(value);
if ((string)originalValue == "01" || (string)originalValue == "09")
return false;
else
return true;
}
}
How do I do it? What is wrong in my ValidationAttributes?
We looked at validation using data annotations a few months back, and decided it was better to use something like fluent validation, as we had complex business rules and logic that would have taken too much effort to realise with data annotations. Have a look at the documentation, and you will see fluent validation makes things like this easy.
Sorry, I did not get back sooner: Check fluent validation here
Your rule could look something like. Syntax not tested, but I am sure you will be able to figure it out.
public class AbonentViewModelValidator : AbstractValidator<AbonentViewModel> {
public AbonentViewModelValidator() {
RuleFor(model => model.CompanyName).NotEmpty().When(model => (model.GroupList.Id == 1 || model.GroupList.Id == 9 ));
RuleFor(model => model.Surname).NotEmpty().When(model => (model.GroupList.Id != 1 || model.GroupList.Id != 9 ));
RuleFor(model => model.Name).NotEmpty().When(model => (model.GroupList.Id != 1 || model.GroupList.Id != 9 ));
}
}