I am using custom view model classes as DTO objects to hold data for display on my View pages. I have applied validation via the DataAnnotations library to perform server side validation on the properties of these classes. Here is a simple example:
[DisplayName("Customer Account Id")]
[Required(ErrorMessage = "* Account Number is required")]
[StringLength(16, ErrorMessage = "* Account Number must be 16 characters in length", MinimumLength = 16)]
public string CustomerAccountId { get; set; }
If someone submits a search and this field does not come through or comes through at a length that is not 16, validation fails, and an error message is displayed on the page via the ValidationMessage HtmlHelper:
<%= Html.ValidationMessage("CustomerAccountId")%>
Now I need to add the ability to search by account id OR a combination of First/Last name. My question is this:
How do I apply conditional validation? If I submit a search with First/Last name, I don't want validation to fail because an account number was not passed through as well. I found this link, which shows how to implement a custom validator, but it seems like this applies to 1 property. How do I pass an entire object model through, and pass back the appropriate validation error messages to the appropriate fields to be displayed on the page? Is this possible?
You can implement IDataErrorInfo. (The class name is misspelled in the article title, but the code is right.)
Related
How to validate that user enters string in textbox in asp mvc4?
What to write in required tag?
[required]
Use the [RegularExpression] attribute if you want to limit the user to only typing in alphabetic characters.
More info on MSDN.
Here is a good link to a regular expression that you can use.
This example maybe helps:
public class CustomerMetaData
{
// Require that the Title is not null.
// Use custom validation error.
[Required(ErrorMessage = "Title is required.")]
public object Title;
// Require that the MiddleName is not null.
// Use standard validation error.
[Required()]
public object MiddleName;
}
There are many ways to do it
1) By using plain Javascript or JQuery to check if it has value before submiting the page
2) On controller method check if it has value
3) If you a using EF and your view binded to a model add attribute called [Required]to the property of that model.
What do you actually want to do?
Make sure that the object the server receives has correct data in it? Then you should use data attributes on your C# model. However what do you mean by "enters string"? If the user simply needs to enter any string, then [Required] works - this just means that there has to be some value entered. Do you only want to allow a specific set of characters, like the English alphabet? Then you need to use a RegularExpression attribute.
If you further specify what you actually want to do I am sure we can help you more.
I'm trying to create a MVC model validation attribute that fills in the following situation:
I have created several models (Birthday and PhoneNumber being excellant examples) that are submitted over multiple input fields on the view (month, day, year; areacode, exchange, suffix).
public class PhoneNumber
{
[RegularExpression("^([2-9][0-8][0-9])$", ErrorMessage = "Invalid Area Code")]
public virtual string AreaCode { get; set; }
[RegularExpression("^([2-9][0-9][0-9])$", ErrorMessage = "Invalid Phone Exchange")]
public virtual string Exchange { get; set; }
[RegularExpression("^([0-9][0-9][0-9][0-9])$", ErrorMessage = "Invalid Phone Suffix")]
public virtual string Suffix { get; set; }
}
I often nest these models inside other models (Person has a PhoneNumber and a Birthday, for example). Sometimes, in my views, a PhoneNumber is required, and sometimes it isn't.
I can handle these situations on the server side by using implementing the class as an IValidatableObject, but I run into trouble if I want to do client side validation, or even just do server side validation via attributes.
I imagine I will have to build my own custom validation attribute but I'm not even sure where to start in accessing object and attribute information on multiple levels. Has anyone encountered anything like this? Any good ideas for pointing me in the right direction?
Thanks in advance!
--------Update------
By using IClientValidatable, and GetClientValidationRules, I have access to the ModelMetadata can get the type of the container. The problem is that the container is birthday or phone number, not the type of the top level model, which is what is most important here. The ModelMetadata hasn't populated the Model property yet because one may not exist yet. What I'm really trying to do is get the type of the top level model. Anyone have any insight?
Depending on how you are writing your view, I think you may want to look at an extension called BeginCollectionItem http://nuget.org/packages/BeginCollectionItem
Validation gets a little messed up if you are doing
#Html.TextBoxFor( m => number.AreaCode )
instead of
#Html.TextBoxFor( m => m.AreaCode )
I am using MVC3 and in certain locations in the code I am using the System.ComponentModel.DataAnnotations.DataType.EmailAddress attribute and letting MVCs Model validation do the validation for me.
However, I would now like to validate an email address in a different section of code where I am not using a model. I would like to use the same method that is already being used by MVC, however I was unable to find any information on how to do so.
EDIT - Sorry if my question was unclear. I will attempt to clarify.
Here is a snippet from the RegisterModel that is included with the default MVC template:
public class RegisterModel
{
...
[Required]
[DataType(DataType.EmailAddress)]
[DisplayName("Email address")]
public string Email { get; set; }
...
}
These attributes instruct mvcs model validation on how to validate this model.
However, I have a string that should contain an email address. I would like to validate the email address the same way that mvc is doing it.
string email = "noone#nowhere.com";
bool isValid = SomeMethodForValidatingTheEmailAddressTheSameWayMVCDoes(email);
As others have said, the DataType attribute doesn't actually do any validation. I would recommend you to look at Data Annotations Extensions which includes already written validation extensions for a variety of things, including Email.
It is also possible to do model validation on your full model explicitly: Manual Validation with Data Annotations.
If you want to do per attribute validation for a specific field/property, you can also look at the tests for DataAnnotationExtensions which should give you what you want:
[TestMethod]
public void IsValidTests()
{
var attribute = new EmailAttribute();
Assert.IsTrue(attribute.IsValid(null)); // Don't check for required
Assert.IsTrue(attribute.IsValid("foo#bar.com"));
..
}
Have a look at this blog post by Scott Guthrie, which shows how to implement validation of an email address using a custom attribute (based on the RegularExpressionAttribute).
You can reuse that logic if you need to validate the email address somewhere else.
You may want to look at this question: Is the DataTypeAttribute validation working in MVC2?
To summarize, [DataType(DataType.EmailAddress)] doesn't actually validate anything, it just says "hey, this property is supposed to be an e-mail address". Methods like Html.DisplayFor() will check for this and render it as foo, but the IsValid() method is pretty much a simple return true;.
You'll have to roll your own code to actually perform validation. The question linked above has some sample code you can use as a starting point.
I have a class User, that have an Email property, like that :
public class User : Entity
{
...
[Display(Name = "Email"), Required(ErrorMessage = "Required."), Remote("EmailExists", "User", ErrorMessage = "Email already in Use.")]
public virtual string Email { get; set; }
...
}
My View Create works fine with all the validation ...
But in my view Edit, my Email texbox is Readonly, so The user cant change the email...
The problem is my Remote validation EmailExists keeps firing...
Is there a way to exclude the Email client validation just in that case? Or maybe another solution?
Thanks
Best solution would be to render Email as text content(span, p, etc) in that particular case - validations would not fire. This would be best accomplished with editor templates. But if you don't wish to, you could use some javascript to remove rules on client side. Take a look at Plugins/Validation/rules - you would remove rule when textbox is readonly. But for me the first way is preferred option
I think that the easier way is to disable the field in the client instead of using readonly. The validate plugin doesn't take in account disabled fields.
You could use different ViewModels for the edit and create views and only apply the Remote attribute to view model associated with the create view or call some other remote validation logic for the view model associated with the edit view.
I have a guest book form created using asp.net mvc.
The valid gender form field must be filled in by selecting a value from a drop down control. The drop down control has 3 options, i.e., "--Select--", "Female", "Male" and the "--Select--" is selected by default. The data model has been setup to force the visitor select either female or male but not "--Select--".
We know that the visitor has a chance to temper the form data, so he can submit the gender form field pointing to a value that does not exist in the database.
My question is:
Can DataAnnotation prevent the user from posting a form field that does not exist in a database?
What is the preferred approach to counter this attempt? Do I have to check the submitted gender form field first before invoking SaveChanges()?
It depends whether you need to provide the user with a specific error, or a clean validation message. In cases where the user is trying to tamper with the form post, I would not be too concerned about the user experience.
If you care about this, you can use the IValidatableObject interface to perform a validation against the legal values:
public class Person : IValidatableObject
{
public string Gender { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//ValidGenders is a list of valid values, retrieved from the database
if (!ValidGenders.Contains(Gender))
{
yield return new ValidationResult("Gender is not valid", new string[] { "Gender" });
}
}
}
The Model validation performs validation using IValidatableObject just as it does using data annotation validation.
On the other hand, if you don't care about the user experience, you could let the error happen in the database, and handle the issue using your standard error handling pipeline. Assuming your foreign key constraints are in place, the operation will fail because the Gender value is not found in the Genders table, or whatever your setup may be.
Not sure if you are using any form of DTO's or Business Objects, but As well as validating the object client side (or within MVC) it may be worth having your objects validate themselves also.
This way you can catch any issues before they hit the DB. An interesting post on SO about the topic can be found here: Should Business Objects or Entities be Self-Validated?