I have wrote an email validation attribute.
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public class EmailAttribute : RegularExpressionAttribute
{
public EmailAttribute() : base(#"[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
{
this.ErrorMessage = "Please provide a valid email address";
}
}
When the validation has been called, the validator runs ok, and when exits throws an error:
System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'
I tried changing the validator implementation, and for every it throws me the same error message.
If I remove the email validation attribute from the object's property everything works. If I add some new random validation attribute it works.
Here is my model:
public partial class LoginModel : BaseViewModel
{
private string email = string.Empty;
private string password = string.Empty;
[Required]
[MinLength(5)]
[Email]
public string Email
{
get => this.email;
set
{
SetProperty(ref this.email, value, true);
OnPropertyChanged("ErrorDictionary[Email]");
}
}
[Required]
[DataType(DataType.Password)]
[MinLength(8)]
public string Password
{
get => this.password;
set
{
SetProperty(ref this.password, value, true);
OnPropertyChanged("ErrorDictionary[Password]");
}
}
}
thnx
I get the same error failure when the ValidationResult is not a success and I return ValidationResult error message of type string.
If the validationResult is ValidationResult.Success then it works and even changes the control to a different color if I wish. Therefore it is the xaml view receiving an incompatible value in the binding expecting bool but gets a string
Related
I have Custom Unique Email validation using ASP.NET Core-6 Web API Entity Framework project
public class UserUniqueEmailValidator : ValidationAttribute
{
private readonly ApplicationDbContext _dbContext;
public UserUniqueEmailValidator(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public bool IsUniqueUserEmailValidator(string email)
{
if (_dbContext.ApplicationUsers.SingleOrDefault(x => x.Email.ToLower() == email.ToLower()) == null) return true;
return false;
}
}
Then I called it here:
[Required(ErrorMessage = "Email field is required. ERROR!")]
[StringLength(100, ErrorMessage = "Email field must not exceed 100 characters.")]
[EmailAddress(ErrorMessage = "The Email field is not a valid e-mail address.")]
[UserUniqueEmailValidator(ErrorMessage = "Email already exists !!!")]
public string Email { get; set; }
But I got this error:
There is no argument given that corresponds to the required formal parameter 'dbContext' of 'UserUniqueEmailValidator.UserUniqueEmailValidator(ApplicationDbContext)'
How do I resolve it?
Thanks
Instead of implementing your own validation attribute, use the Remote Validation attribute.
Here is an example implementation
[Remote("ValidateEmailAddress","Home")]
public string Email { get; set; }
The validateEmailAddress implementation
public IActionResult ValidateEmailAddress(string email)
{
return Json(_dbContext.ApplicationUsers.Any(x => x.Email != email) ?
"true" : string.Format("an account for address {0} already exists.", email));
}
Hope it helps.
Just as the error indicates: Validator's constructor contains the ApplicationDbContext parameter which is not valid;
Also, IsUniqueUserEmailValidatormethod has not been called ,so the codes inside it will never be executed
If you want to custom ValidationAttribute you could overrride protected virtual ValidationResult? IsValid(object? value, ValidationContext validationContext)
and access ApplicationDbContext as below:
protected override ValidationResult? IsValid(
object? value, ValidationContext validationContext)
{
var context = validationContext.GetService<ApplicationDbContext>();
//add your logical codes here
return ValidationResult.Success;
}
For more details,you could check this document
I do have a entity class with some required attributes depending of a selector.
For instance: The Selector can assume "1" or "2". If selector was "1", a group of parameters shall be required. If selector is "2" another set of parameters is required.
class MyClass{
public int Selector {get;set;} // 1 or 2
public string A_required_for_1 {get;set;}
public string B_required_for_1 {get;set;}
public string C_required_for_2 {get;set;}
public string D_required_for_2 {get;set;}
public string E_Required_for_both_selectors {get;set;}
}
User should be able to switch between selectors during Create or Edit actions in view.
Client validation is already solved.
How can I deal with it in server validation?
You can either create your own custom validation attribute or use MVC Foolproof Validation and then do:
class MyClass
{
public int Selector {get;set;} // 1 or 2
[RequiredIf("Selector == 1", ErrorMessage = "Your Error Message")]
public string A_required_for_1 {get;set;}
[RequiredIf("Selector == 1", ErrorMessage = "Your Error Message")]
public string B_required_for_1 {get;set;}
[RequiredIf("Selector == 2", ErrorMessage = "Your Error Message")]
public string C_required_for_2 {get;set;}
[RequiredIf("Selector == 2", ErrorMessage = "Your Error Message")]
public string D_required_for_2 {get;set;}
[Required("Your Error Message")]
public string E_Required_for_both_selectors {get;set;}
}
As mentioned by Win it does not seem to have been in active development for a while so you may want to go down the route of creating your own custom validation attribute, which does require more work but you can have a finer control over the validation itself. Choose depending on your needs.
For a custom validation attribute you could do something like this:
public class RequiredIfOtherProperty : ValidationAttribute
{
private readonly string _otherPropertyName;
private readonly string _compareValue;
public RequiredIfOtherProperty(string otherPropertyName, string compareValue)
{
_otherPropertyName = otherPropertyName;
_compareValue = compareValue;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var otherProperty = validationContext.ObjectType.GetProperty(_otherPropertyName);
if (otherProperty == null)
{
return new ValidationResult($"Property '{_otherPropertyName}' does not exist");
);
var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null);
if (!_compareValue.Equals(otherPropertyValue))
{
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
}
return null;
}
}
It should give you a rough idea on what you can do and you can change the actual validation to however you like. You can then use it like a normal attribute e.g.
[RequiredIfOtherProperty("SomeProperty", "ValueToCompareWith")]
I believe mvcfoolproof will work for this situation [https://foolproof.codeplex.com/][1]
It is also available on nuget. It adds additional validation attributes such as
[RequiredIf]
[RequiredIfNot]
[RequiredIfTrue]
[RequiredIfFalse]
[RequiredIfEmpty]
[RequiredIfNotEmpty]
[RequiredIfRegExMatch]
[RequiredIfNotRegExMatch]
It is very simple to use.
I have created a custom validation rule that requires two textboxes if and only if the previous set of radio buttons shows Yes selected. Validation works fine if no radio selection or No is made, but fails when Yes is selected, if when data is supplied.
My custom validation is:
public class DamageSupport : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var incidentdetail = (IncidentDetail) validationContext.ObjectInstance;
return (incidentdetail.PropertyDamage == "Y") ? new ValidationResult("This field is required since Property Damage is set to 'Yes'") : ValidationResult.Success;
}
}
Here are my modelvalidation rules:
[MaxLength(1)]
[Display(Name = "Property Damaged?")]
public string PropertyDamage { get; set; }
[RegularExpression(#"^\d+.\d{0,2}$")]
[Range(0, 99999999.99)]
[Display(Name = "Estimated value of damage")]
[DamageSupport]
public decimal? DamageAmount { get; set; }
[Display(Name = "Description of the damage")]
[DamageSupport]
public string DamageDescription { get; set; }
I look at the data in the ModelState object data in debug mode, and all the data I types is there,just fails validation for some reason.
I double checked it wasn't a data type issue by removing the custom validation and saving the same data, works fine.
Anyone think of someplace for me to look?
We have created the following view model in one of our MVC3 projects:
[PropertiesMustMatch("Email", "ConfirmEmail", ErrorMessage = "The email address you provided does not match the email address in the confirm email box.")]
[PropertiesMustMatch("NewPassword", "ConfirmPassword", ErrorMessage = "The new password you provided does not match the confirmation password in the confirm password box.")]
public class ActivationStep2ViewModel
{
.....
The PropertiesMustMatch is a custom attribute that we have created, code as below:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class PropertiesMustMatchAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";
private readonly object _typeId = new object();
public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
: base(_defaultErrorMessage)
{
OriginalProperty = originalProperty;
ConfirmProperty = confirmProperty;
}
public string ConfirmProperty { get; private set; }
public string OriginalProperty { get; private set; }
public override object TypeId
{
get
{
return _typeId;
}
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
OriginalProperty, ConfirmProperty);
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
return Object.Equals(originalValue, confirmValue);
}
}
However, on the view, when there is a mismatch between both the 1) Email and Confirm email and 2) the password and confirm password, the validation message for the password is displayed on top. See image below:
We would like the validation message for the Email text boxes to be displayed on top as these text boxes appear before the password text boxes.
NOTE: The order of the messages on local build (through VS2010) works as expected. The order of messages is screwed up only in our DEV and TEST environments. Looking at the deployed DLLs through reflector, this is what is displayed: (the order of attributes is reversed)
What can we do to fix this on the release builds?
Any help / suggestions would be much appreciated.
Thanks.
We still do not know why the compiler muddles up the order of validation attributes set up, a bit crap!
We had to use a different approach to fix this.
We got rid of the custom validation attributes and implemented IValidatableObject on the view model. In the Validate method, added validation logic in the order that we wanted the messages displayed (code below):
public class ActivationStep2ViewModel : IValidatableObject
{
.
.
.
.
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(Email != ConfirmEmail)
{
yield return new ValidationResult("The email address you provided does not match the email address in the confirm email box.");
}
if(NewPassword != ConfirmPassword)
{
yield return new ValidationResult("The new password you provided does not match the confirmation password in the confirm password box.");
}
}
Having created my own validation attribute deriving from System.ComponentModel.DataAnnotations.ValidationAttribute, I wish to be able to detect from my controller, whether or not that specific attribute was valid on the model.
My setup:
public class MyModel
{
[Required]
[CustomValidation]
[SomeOtherValidation]
public string SomeProperty { get; set; }
}
public class CustomValidationAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// Custom validation logic here
}
}
Now, how do I detect from the controller whether validation of CustomValidationAttribute succeeded or not?
I have been looking at the Exception property of ModelError in the ModelState, but I have no way of adding a custom exception to it from my CustomValidationAttribute.
Right now I have resorted to checking for a specific error message in the ModelState:
public ActionResult PostModel(MyModel model)
{
if(ModelState.Where(i => i.Value.Errors.Where((e => e.ErrorMessage == CustomValidationAttribute.SharedMessage)).Any()).Any())
DoSomeCustomStuff();
// The rest of the action here
}
And changed my CustomValidationAttribute to:
public class CustomValidationAttribute : ValidationAttribute
{
public static string SharedMessage = "CustomValidationAttribute error";
public override bool IsValid(object value)
{
ErrorMessage = SharedMessage;
// Custom validation logic here
}
}
I don't like relying on string matching, and this way the ErrorMessage property is kind of misused.
What are my options?
I think it is meaningful to have a Enum named ExceptionType in the CustomValidationAttribute which clearly identifies the type of Exception raised.
In the controller we may check for the exceptionType and handle accordingly .
try
{
}
Catch(Exception e)
{
Switch(e.ExceptionType)
{
case ExceptionType.Val1:
// Handle accordingly
break;
}
}