Custom validation attribute with multiple instances problem - c#

I'm using tha namespace System.ComponentModel.DataAnnotations in C# 4 to implement my own validation attribute and it looks like this
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class MyCustomValidator : ValidationAttribute {
private String Property1 { get; set; }
private String Property2 { get; set; }
public ValeTaxiSituacaoRequired(String property1, String property2) {
Property1 = property1;
Property2 = property2;
}
public override bool IsValid(object value) {
//validation logic
}
}
I wanna use this attribute as below
[MyCustomValidator("Name", "Job")]
[MyCustomValidator("Name", "Email")]
[MyCustomValidator("Name", "Job")]
public class Employe {
}
The problem is that just one validation is perfomed. How can I execute all the validations (using asp.net mvc 2)?

you have to override TypeId property
http://www.paraesthesia.com/archive/2010/03/02/the-importance-of-typeid-in-asp.net-mvc-dataannotations-validation-attributes.aspx

If you want to implement AllowMultiple=true on your own attribute then first override TypeID and next for solution to JQuery look at the article on code project here

Take a look at FluentValidation. It allows you to separate your validation from the classes being validated so that you can call your validation logic at any time, on the server or the client.
It allows you to add as many rules of any complexity to a class, without cluttering it with attributes.

Related

How to write an ASP.NET custom validator for a model defined in an external library

I'm trying to write a custom validation class for an ASP.NET Core web app I'm developing. I've found various examples of how to write custom client-side validation, such as this and this. These are all clear and make sense to me. However, my problem is that my model is defined within a .NET Standard library that other projects share. I cannot access the base classes I need to create the custom validation class from within this library.
Basically, I need to ensure that model.PropertyA is never greater than model.PropertyB. I'm aware that I could write some JavaScript that accomplishes this, but I'd prefer to utilize the existing ASP.NET Core validation techniques if possible.
I'd prefer to avoid any 3rd party dependencies to accomplish this, if possible.
hy,
Better to avoid Validation against Data Annotation because you don't have access to them in all cases , like the case you are describing;
One powerful package exist "FluentValidation "
you can create a model class and validate against properties
sample:
public class Person {
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
full documentation : https://docs.fluentvalidation.net/en/latest/aspnet.html
and then you add a validator for your commands like the following sample :
public class CreatePersonCommandValidator :
AbstractValidator<CreatePersonCommand>
{
....
public CreateTodoListCommandValidator(IApplicationDbContext context)
{
_context = context;
RuleFor(v => v.Name)
.NotEmpty().WithMessage("Name is required.")
.MaximumLength(200).WithMessage("Name must not exceed 200 characters.");
}...
....
..
You could build a class extends the class from libraries. And extends IValidatableObject to implement Validation.
Base class is from librarie.
public class Base
{
public int PropertyA { get; set; }
public int PropertyB { get; set; }
}
MyClass is build for validation.
public class MyClass : Base, IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (PropertyA > PropertyB)
{
yield return new ValidationResult(
$"model.PropertyA {PropertyA} can't greater than model.PropertyB ." );
}
}
}
Test codes:
[HttpPost]
public IActionResult Add([FromBody]MyClass myClass)
{
if (ModelState.IsValid)
{
RedirectToAction("Index");
}
return View();
}
Test result:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>

EmailAddressAtribute ignored

I have a class which defines the property EmailAddress with the attribute EmailAddressAttribute from System.ComponentModel.DataAnnotations:
public class User : Entity
{
[EmailAddress]
public string EmailAddress { get; set; }
[Required]
public string Name { get; set; }
}
public class Entity
{
public ICollection<ValidationResult> Validate()
{
ICollection<ValidationResult> results = new List<ValidationResult>();
Validator.TryValidateObject(this, new ValidationContext(this), results);
return results;
}
}
When I set the value of EmailAddress to be an invalid email (e.g. 'test123'), the Validate() method tells me the entity is valid.
The RequiredAttribute validation is working (e.g. setting Name to null shows me a validation error).
How do I get EmailAddressAttribute working in my validator?
After playing with the overloads available for each method, I found the following overload which includes a parameter called validateAllProeprties.
When this is set to true the object is property validated.
Validator.TryValidateObject(this, new ValidationContext(this), results, true);
I'm not sure why you wouldn't want to validate all properties, but having this set to false or not set (defaults to false) will only validate required attributes.
This MSDN article explains.
to use Validation with the Data Annotation Validators you should add both references to
Microsoft.Web.Mvc.DataAnnotations.dll assembly and the System.ComponentModel.DataAnnotations.dll assembly.
then you need to register the DataAnnotations Model Binder in the Global.asax file. Add the following line of code to the Application_Start() event handler so that the Application_Start() method looks like this:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.DefaultBinder = new Microsoft.Web.Mvc.DataAnnotations.DataAnnotationsModelBinder();
}
after that you have registered the dataAnnotationsModelBinder as the default model binder for the entire ASP.NET MVC application
then your code should work properly
public class User : Entity
{
[EmailAddress]
public string EmailAddress { get; set; }
[Required]
public string Name { get; set; }
}
refer here for documentation

Data annotation validation attribute - mandatory set (i.e. one of many is required)

We want to use data annotation validation attributes to express that within a certain property set at least one is required.
E.g.:
class X
{
[Set("Set1", Validation=typeof(RequiredAttribute))]
public string A { get; set; }
[Set("Set1", Validation=typeof(RequiredAttribute))]
public string B { get; set; }
}
Which would mean that either A or B must be set. Is something like that already existing?
If not, is there a chance that you can reach the parent object of the object-to-validate in a custom data annotation validation attribute so that we can do that ourselves? Currently we only get either A or B and have no chance to reach the other.
You can, but not that way. You need to make your class part of the IValidatableObject interface (it's also from the DataAnnotations namespace).
Then you can implement a validation function in which you can check the validity using your own business logic.
Note: The name and signature of the Validate method are fixed, as they come from the interface.
public class Actor : AbstractDataholder, IValidatableObject
{
public string A { get; set; }
public string B { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(string.IsnullorWhiteSpace(this.A) && string.IsnullorWhiteSpace(this.B))
return new ValidationResult("NOT VALID");
}
}

Can ASP.Net MVC 2 Custom attributes on class level and on property level be active in the same time?

I am working on asp.net mvc 2 web application.
I have model with 3 properties:
[IsCityInCountry("CountryID", "CityID"]
public class UserInfo
{
[Required]
public int UserID { get; set; }
[Required]
public int CountryID { get; set; }
[Required]
public int CityID { get; set; }
}
I have one "required" property attribute, and one attribute on class level :
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class IsCityInCountry : ValidationAttribute
{
public IsCityInCountry(string countryIDProperty, string cityIDProperty)
{
CountryIDProperty = countryIDProperty;
CityIDProperty = cityIDProperty;
}
public string CountryIDProperty { get; set; }
public string CityIDProperty { get; set; }
public override bool IsValid(object value)
{
var properties = TypeDescriptor.GetProperties(value);
var countryID = properties.Find(CountryIDProperty, true).GetValue(value);
var cityID = properties.Find(CityIDProperty , true).GetValue(value);
int countryIDInt;
int.TryParse(countryID.ToString(), out countryIDInt);
int cityIDInt;
int.TryParse(cityID.ToString(), out cityIDInt);
if (CountryBusiness.IsCityInCountry(countryIDInt, cityIDInt))
{
return true;
}
return false;
}
}
When I post the form on my view, and CountryID is not entered, in ModelState dictionary there's an error about that issue. Other attribute is ignored ("IsCityInCountry"). When I choose CountryID and CityID, which is not in selected country, I get appropriate validation message about that, and ModelState has another key (which is ""). I understand that advantage have property attributes and then class attributes. My question; is there any way to get all validation messages at the same time, no matter what kind of attributes are involved (class or property attributes)? Thanks in advance.
ASP.NET MVC won't perform class level validation if there are property level validation errors. Brad Wilson explains this in his blog post:
Earlier today, we committed a change to MVC 2 that converted the
validation system from Input Validation to Model Validation.
What this means is that we will always run all validators on an
object, if that object had at least one value bound into it during
model binding. We run the property-level validators first, and if all
of those succeed, we'll run the model-level validators.
I would recommend you to go ahead and checkout FluentValidation.NET if you want to perform some more advanced validation in an ASP.NET MVC application. Declarative validation simply doesn't fit the bill in advanced validation scenarios.

Dataannotations validation

on asp.net mvc3 I'm using dataanotations for validation. I control the validations on my controller with a simple if(ModelState.IsValid). How can I control those validations in a simple class, not a controller?
Thanks!
Use the validator helper class: http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validator.aspx
This is pretty much what the MVC validator does behind the scenes:
This will iterate through all the annotations and figure our if there are any errors and add them to an error collection. It's best to put this in a base class then have all your other classes inherit from it. if GetErrors().Any() returns true, the model is invalid.
public IEnumerable<ErrorInfo> GetErrors() {
return from prop in TypeDescriptor.GetProperties(this).Cast<PropertyDescriptor>()
from attribute in prop.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(this))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty));
}
Error Info Class:
public class ErrorInfo{
public string Name { get; set; }
public string FormatErrorMessage { get; set; }
public ErrorInfo(string name, string formatErrorMessage){
Name = name;
FormatErrorMessage = formatErrorMessage;
}
}
Answered Here (w/ .net 4):
Using ASP.Net MVC Data Annotation outside of MVC

Categories

Resources