Custom Validation Annotation for Checking if Username Already Exists - c#

I've looked at a number of questions on creating custom data annotation classe for model validation and so far I can't extrapolate an answer from any of them as they all vary quite wildly in responses.
I am trying to run a method that returns a boolean on what's been entered into the textbox for that property but I'm not sure how to get at the property contents to run the method. Basically this is a check to see if this username already exists. Here is what I've tried but as you can see, I don't know how to get at the string entered into the field to run the method on.
public class Username : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
ADSI adsi = new ADSI();
if (adsi.UserExists(//here's where the text entered should go))
{
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
}
return null;
}
}

I figured it out. The value object is the text that the user has entered into the field.
public class Username : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
ADSI adsi = new ADSI();
if (adsi.UserExists(value.ToString()))
{
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
}
return null;
}
}
Obviously the method I use for checking if a username exists is something I wrote so you'll need to refer to documentation on how to do that.
Usage:
[Username(ErrorMessage = "Username already exists.")]
public string Username {get; set;}

Related

Access Route values in ValidationAttribute

My route is defined as http:/.../home/index/1 which is (controller/action/id).
ViewModel is as below..
public class TestVM
{
[CustomValidation]
public string name{get; set;}
}
public class CustomValidation : ValidationAttribute
{
protected override ValidationResult? IsValid (object? value, validationContext)
{
var vm = (TestVM)validationContext.ObjectInstance;
//how to get the route value here?
}
}
To validate Name property, I need to have value of Id. To access route value in the IsValid method, I defined one more property Id in the TestVM.
Is there a way to access the Id in the IsValid without defining in the TestVM?
Is there a way to access the Id in the IsValid without defining in the
TestVM?
Seems you are trying to access parameter which has been passed to controller route so that, you can get those values inside your CustomValidation class
Well, using IHttpContextAccessor we can get all route value from which are available within HttpContext.Request. Thus, you can access property name of member of TestVM class.
Access Route Value Inside ValidationAttribute:
You can implement in following way:
public class CustomValidator : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
var vm = context.ObjectInstance as TestVM;
var httpContextAccessor = context.GetRequiredService<IHttpContextAccessor>()
var getIdFromRouteValue = httpContextAccessor.HttpContext.Request.Query["Id"];
var getNameFromRouteValue = httpContextAccessor.HttpContext.Request.Query["name"];
vm.Id = getIdFromRouteValue;
vm.name = getNameFromRouteValue;
return ValidationResult.Success;
}
}
Program.cs:
IHttpContextAccessor requires to register AddHttpContextAccessor() service on your program.cs file. You can do as following:
builder.Services.AddHttpContextAccessor();
Note: Please make sure you have followed the correct order. You can get more details on our official document here.
Output:

ValidationAttribute working partially or not working on Blazor?

I'm trying to resolve a problem I found while trying to do a custom validation attribute on my daughter's dog store using blazor.
Basically I have a property as follow:
[Test]
public int? PetAge { get; set; }
As you can see, I'm going to create a custom attribute called "Test", so I created a new class as follow:
public class Test : ValidationAttribute
{
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
return new ValidationResult("niet! niet!");
}
}
and my understanding is that I can return a new ValidationResult with a string message or if everything goes fine, I can return ValidationResult.Success. In my example, it should always return a problem, as we did not provide any other logic than always returning a validationresult.
When running this code, it simply does not return anything, no error displayed on the form. Now what I did notice is that if I use the other version of the IsValid method, it works, the only problem is that I would like to send a custom message back and not just a true/false result. The one working is as follow:
public override bool IsValid(object? value)
{
return false;
}
But in that case, I have to provide the error message in the parameter like this:
[Test(ErrorMessage("this is not ok!")]
public int? PetAge { get; set; }
As these parameters must be constants, it was an awesome idea not only to be able to display a custom-built message as an error and/or have access to the context, etc...
am I doing something wrong on my Blazor app? any help will be appreciated!
I noticed this too, try the following
public class Test : ValidationAttribute
{
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
return new ValidationResult("niet! niet!", new[] { validationContext.MemberName });
}
}

MVC Data Annotation And Custom Validation Attribute

I have a field in a model on which builtin data annotation and custom validation attribute not seems to be working correctly. Looks like there is an issue with the order of there execution.
[Required]
[Display(Name = "UserName")]
[RegularExpression(#"^[^\s\,]*$", ErrorMessage = "Username Cannot must not contain any spaces or commas")]
[UnqiueUserName]
public string UserName { get; set; }
public class UnqiueUserName : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null && Membership.GetUser(value.ToString()) != null)
{
return new ValidationResult
(string.Format("UserName Already Exist"));
}
return ValidationResult.Success;
}
}
If I enter username user,123 The custom validation attribute executing first and that make the exception to occur.
The parameter "username" must not contain a comma
But If I enter user 123 the builtin Data Annotation Regular Expression execute first this time.
I want my Custom Validation attribute after the builtin one. Please suggest

MVC 4 : Possible to use variable from validation in validation message?

Many forms in my project have a part number input. Currently in the controller I often times test the part number to see if the part exists or user has access or if the part is obsolete, then based on the condition I reload the view passing a message through a string parameter then viewbag for display to show why the form submit failed. I'm trying to clean this up and instead use model property validation.
I have a few working well however one of the validations I want to test is if the part is obsolete and has a suggested alternate part number to use. Based on the property value (part number) I have a service layer method that will return a bool of if the part is obsolete and another one that will return the suggested use part number. If possible I'd like to trigger the validation on the bool check, then pass that alternate part number into the validation message that gets generated.
Here is the validation code in it's current form:
public class PartAlternateValidation : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
{
return false;
}
GP10Service gp10svc = new GP10Service();
//string altPart = gp10svc.GetPartAlternate(value.ToString());
return gp10svc.CheckPartAlternate(value.ToString());
}
}
Did quite a bit of searching around but couldn't find anything that specifically discussed this. Thinking maybe I could have an out string parameter with the bool in IsValid, but not sure how to then pass that to the message (or call FormatErrorMessage method from the IsValid method?). Thinking maybe there is a way using ModelState.AddModelError, however I believe the key on these is tied to the property, correct? So I'm fuzzy on how I could detect when the property fails a particular validation and use the property value as a variable in generating the message that way.
Probably something simple, has been a good excuse to do more research and I will continue reading but any suggestions or tips would be welcome.
Thanks.
Please see below tip helps..
Model:
namespace Mvc4Test.Models
{
public class Part
{
[AlternateValidation(Suggetion = "Please Use 123 (This is a Suggestion)")]
public string PartNumber { get; set; }
}
public class AlternateValidation : ValidationAttribute
{
public string Suggetion { get; set; }
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
if (value != null)
{
if (value.ToString() == "123")
{
return ValidationResult.Success;
}
else
{
return new ValidationResult(Suggetion);
}
}else
return new ValidationResult("Value is Null");
}
}
}
View:
#Html.EditorFor(model => model.PartNumber)
#Html.ValidationMessageFor(model => model.PartNumber)

Order of validation messages from custom attribute in MVC3 view model

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.");
}
}

Categories