I am working on WinForms with EF 6.2.
I am trying to implement custom validation logic for my entities with Entity Framework.
At first, I succeeded to override the DbEntityValidationResult ValidateEntity method in my DbContext and it's working fine.
But now I have a lot of entities, it becomes very messy and I would like to implement the custom validation directly in my entities classes.
So I tried to implement the IValidatableObject interface.
Here is a simple example of an entity :
public class Inspection : IValidatableObject
{
public int Id { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "You must enter a description")]
[StringLength(maximumLength: 15, ErrorMessage = "The description cannot exceed 15 characters")]
public string Description { get; set; }
public DateTime? ActualDate { get; set; }
public DateTime? ValidityDate { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ActualDate > ValidityDate)
{
ValidationResult result = new ValidationResult("Actual Date connot be > to ValidityDate");
yield return result;
}
}
}
Now I read a lot of things but cannot figure where do I have to call the Validate method of my entities, and what value I have to pass in ValidationContext parameter.
Every tutorial I've seen targets MVC scenarios so I wonder if it is possible to use it with Winforms.
I maybe have missed something, or maybe it is not the correct approach for validation in Winforms/EF.
Please can you give me some piece of advice ?
Finally I found the solution (and my error) thanks to the MSDN article :
http://msdn.microsoft.com/en-us/data/gg193959.aspx
When I read it the first time, I missed a part while implementing the interface.
I forgot to define the memberNames parameter of the ValidationResult class.
So I just changed :
ValidationResult result = new ValidationResult("Actual Date connot be > to ValidityDate");
to
ValidationResult result = new ValidationResult("Actual Date connot be > to ValidityDate",
new[] { nameof(ActualDate), nameof(ValidityDate) });
And it worked as expected.
I am still wondering what value to pass in ValidationContext parameter if the Validate method of the interface is called manually, but it is another question.
So to answer my own question : Yes, it is possible to use IValidatableObject with Winforms.
In MVC when we post a model to an action we do the following in order to validate the model against the data annotation of that model:
if (ModelState.IsValid)
If we mark a property as [Required], the ModelState.IsValid will validate that property if contains a value or not.
My question: How can I manually build and run custom validator?
P.S. I am talking about backend validator only.
In .NET Core, you can simply create a class that inherits from ValidationAttribute. You can see the full details in the ASP.NET Core MVC Docs.
Here's the example taken straight from the docs:
public class ClassicMovieAttribute : ValidationAttribute
{
private int _year;
public ClassicMovieAttribute(int Year)
{
_year = Year;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
Movie movie = (Movie)validationContext.ObjectInstance;
if (movie.Genre == Genre.Classic && movie.ReleaseDate.Year > _year)
{
return new ValidationResult(GetErrorMessage());
}
return ValidationResult.Success;
}
}
I've adapted the example to exclude client-side validation, as requested in your question.
In order to use this new attribute (again, taken from the docs), you need to add it to the relevant field:
[ClassicMovie(1960)]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
Here's another, simpler example for ensuring that a value is true:
public class EnforceTrueAttribute : ValidationAttribute
{
public EnforceTrueAttribute()
: base("The {0} field must be true.") { }
public override bool IsValid(object value) =>
value is bool valueAsBool && valueAsBool;
}
This is applied in the same way:
[EnforceTrue]
public bool ThisShouldBeTrue { get; set; }
Edit: Front-End Code as requested:
<div asp-validation-summary="All" class="text-danger"></div>
The options are All, ModelOnly or None.
To create a custom validation attribute in .Net Core, you need to inherit from IModelValidator and implement Validate method.
Custom validator
public class ValidUrlAttribute : Attribute, IModelValidator
{
public string ErrorMessage { get; set; }
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
{
var url = context.Model as string;
if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
return Enumerable.Empty<ModelValidationResult>();
}
return new List<ModelValidationResult>
{
new ModelValidationResult(context.ModelMetadata.PropertyName, ErrorMessage)
};
}
}
The model
public class Product
{
public int ProductId { get; set; }
[Required]
public string ProductName { get; set; }
[Required]
[ValidUrl]
public string ProductThumbnailUrl { get; set; }
}
Will this approach give opportunity to work with "ModelState.IsValid" property in controller action method?
Yes! The ModelState object will correctly reflect the errors.
Can this approach be applied to the model class? Or it can be used with model class properties only?
I don't know if that could be applied onto class level. I know you can get the information about the class from ModelValidationContext though:
context.Model: returns the property value that is to be validated
context.Container: returns the object that contains the property
context.ActionContext: provides context data and describes the action method that processes the request
context.ModelMetadata: describes the model class that is being validated in detail
Notes:
This validation attribute doesn't work with Client Validation, as requested in OP.
I have a ViewModel that I can decorate with the [Required] attribute (see below). I've come to the point where I need to let the client control which fields are required or not. They can configure this trough XML and all this info is stored in the Model when it's first created. Now I have fields that are not decorated with [Required] but still need to get validated (as per "user settings") before submitting (for example the Phone field).
public class MyBusinessObjectViewModel
{
[Required]
public string Email { get; set; } //compulsory
public string Phone { get; set; } //not (yet) compulsory, but might become
}
If the user will not enter the Phone number, the data will still get posted. Wanting not to mess with custom validators, I just add the "data-val" and "data-val-required" attributes to the Html, like this:
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("data-val", "true");
dict.Add("data-val-required", "This field is required.");
#Html.TextBoxFor(x => x, dict);
This forces the client side validation for all the properties that are dynamically set as required. Is this good practice? What kind of side effects can I expect?
You should look into extending the meta model framework with your own metadata provider to do the actual binding between your site's configuration and the model metadata. You can actually set the required property flag to true on the property model metadata during the metadata creation process. I can't remember for sure whether this causes the built in editor templates to generate the attribute, but I think it does. Worst case scenario you can actually create and attach a new RequiredAttribute to the property, which is a tad bit kluggy, but works pretty well in certain scenarios.
You could also do this with IMetadataAware attributes, especially if Required is the only metadata aspect your users can customize, but the implementation really depends on what you're trying to do.
One major advantage of using a custom ModelMetadataProvider in your specific case is that you can use dependency injection (via ModelMetadataProviders) to get your customer settings persistence mechanism into scope, whereas with the data attribute you only get to write an isolated method that runs immediately after the metadata model is created.
Here is a sample implementation of a custom model metadata provider, you'd just have to change the client settings to whatever you wanted to use.
UPDATED but not tested at all
public class ClientSettingsProvider
{
public ClientSettingsProvider(/* db info */) { /* init */ }
public bool IsPropertyRequired(string propertyIdentifier)
{
// check the property identifier here and return status
}
}
public ClientRequiredAttribute : Attribute
{
string _identifier;
public string Identifier { get { return _identifer; } }
public ClientRequiredAttribute(string identifier)
{ _identifier = identifier; }
}
public class RequiredModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
ClientSettings _clientSettings;
public RequiredModelMetadataProvider(ClientSettings clientSettings)
{
_clientSettings = clientSettings;
}
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
// alternatively here is where you could 'inject' a RequiredAttribute into the attributes list
var clientRequiredAttribute = attributes.OfType<ClientRequiredAttribute>().SingleOrDefault();
if(clientRequiredAttribute != null && _clientSettings.IsPropertyRequired(clientRequiredAttribute.Identifier))
{
// By injecting the Required attribute here it will seem to
// the base provider we are extending as if the property was
// marked with [Required]. Your data validation attributes should
// be added, provide you are using the default editor templates in
// you view.
attributes = attributes.Union(new [] { new RequiredAttribute() });
}
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
// REMOVED, this is another way but I'm not 100% sure it will add your attributes
// Use whatever attributes you need here as parameters...
//if (_clientSettings.IsPropertyRequired(containerType, propertyName))
//{
// metadata.IsRequired = true;
//}
return metadata;
}
}
USAGE
public class MyModel
{
[ClientRequired("CompanyName")]
public string Company { get; set; }
}
public class MyOtherModel
{
[ClientRequired("CompanyName")]
public string Name { get; set; }
public string Address { get; set; }
}
Both of these models would validate the string "CompanyName" against your client settings provider.
Not wanting to mess with custom validators, so you messed in the View obfuscating the logic of your validation by removing it from the place where it is expected to be found.
Really, don't be afraid of creating a custom attribute validator. What you are doing right now is getting a technical debt.
Before I start ... I can't easily migrate the project to MVC3. So.
The problem I'm having is that I've defined a custom validator attribute to check the max AND min length of a string property, StringLengthInRangeAttribute.
When the Controller calls ModelState.IsValid, on a list of Passengers only the validation of a Date property is throwing invalid, when nothing has been supplied. I guess that means my problem is not with the custom validator but all validation?
Update (additional info for clarity):
I have two symptoms of this problem :
1.The Required validator on the strings doesn't fire when they are empty
and
2.My custom validator never gets called (a breakpoint I set never gets hit).
Model:
public class Passenger
{
[Required(ErrorMessageResourceType = typeof(Resources.Messages.Passenger),
ErrorMessageResourceName = "RequireNumber")]
public int Number { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Messages.Passenger),
ErrorMessageResourceName = "RequireSurname")]
[StringLengthInRange(MinLength = 2, MaxLength = 30, ErrorMessageResourceType = typeof(Resources.Messages.Passenger),
ErrorMessageResourceName = "MaxLengthSurname")]
public string Surname { get; set; }
}
Custom Validator:
public class StringLengthInRangeAttribute:ValidationAttribute
{
public int MinLength { get; set; }
public int MaxLength { get; set; }
public override bool IsValid(object value)
{
if (((string)value).Length < MinLength)
{
return false;
}
if (((string)value).Length > MaxLength)
{
return false;
}
return true;
}
}
Controller Action:
public ViewResult TailorHoliday(List<SearchAndBook.Models.ViewModels.Passenger> passengers,
int leadPassengerIndex)
{
if(!ModelState.IsValid)
{
return View("PassengerDetails", GetBookingState(_currentSession));
}
//...
return View();
}
Any advice appreciated. This is the first time I've used Data Annotations, so I'm quite prepared to feel stupid for missing something!
If you check the content of the ModelState property (in the debugger) you should be able to see every property that gets validated in ModelState.Keys and for each value you see the actual state in the ModelState.Values. If I look at your controller you seem to post a whole list of passengers. You should check as well, whether your values are really posted (use Firebug or Fiddler). Maybe your fields are outside the form.
Maybe you should show part of your view as well to spot the bug.
I was wondering if it is possible to disable the Required validation attribute in certain controller actions. I am wondering this because on one of my edit forms I do not require the user to enter values for fields that they have already specified previously. However I then implement logic that when they enter a value it uses some special logic to update the model, such as hashing a value etc.
Any sugestions on how to get around this problem?
EDIT:
And yes client validation is a problem here to, as it will not allow them to submit the form without entering a value.
This problem can be easily solved by using view models. View models are classes that are specifically tailored to the needs of a given view. So for example in your case you could have the following view models:
public UpdateViewView
{
[Required]
public string Id { get; set; }
... some other properties
}
public class InsertViewModel
{
public string Id { get; set; }
... some other properties
}
which will be used in their corresponding controller actions:
[HttpPost]
public ActionResult Update(UpdateViewView model)
{
...
}
[HttpPost]
public ActionResult Insert(InsertViewModel model)
{
...
}
If you just want to disable validation for a single field in client side then you can override the validation attributes as follows:
#Html.TextBoxFor(model => model.SomeValue,
new Dictionary<string, object> { { "data-val", false }})
I know this question has been answered a long time ago and the accepted answer will actually do the work. But there's one thing that bothers me: having to copy 2 models only to disable a validation.
Here's my suggestion:
public class InsertModel
{
[Display(...)]
public virtual string ID { get; set; }
...Other properties
}
public class UpdateModel : InsertModel
{
[Required]
public override string ID
{
get { return base.ID; }
set { base.ID = value; }
}
}
This way, you don't have to bother with client/server side validations, the framework will behave the way it's supposed to. Also, if you define a [Display] attribute on the base class, you don't have to redefine it in your UpdateModel.
And you can still use these classes the same way:
[HttpPost]
public ActionResult Update(UpdateModel model)
{
...
}
[HttpPost]
public ActionResult Insert(InsertModel model)
{
...
}
You can remove all validation off a property with the following in your controller action.
ModelState.Remove<ViewModel>(x => x.SomeProperty);
#Ian's comment regarding MVC5
The following is still possible
ModelState.Remove("PropertyNameInModel");
Bit annoying that you lose the static typing with the updated API. You could achieve something similar to the old way by creating an instance of HTML helper and using NameExtensions Methods.
Client side
For disabling validation for a form, multiple options based on my research is given below. One of them would would hopefully work for you.
Option 1
I prefer this, and this works perfectly for me.
(function ($) {
$.fn.turnOffValidation = function (form) {
var settings = form.validate().settings;
for (var ruleIndex in settings.rules) {
delete settings.rules[ruleIndex];
}
};
})(jQuery);
and invoking it like
$('#btn').click(function () {
$(this).turnOffValidation(jQuery('#myForm'));
});
Option 2
$('your selector here').data('val', false);
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
Option 3
var settings = $.data($('#myForm').get(0), 'validator').settings;
settings.ignore = ".input";
Option 4
$("form").get(0).submit();
jQuery('#createForm').unbind('submit').submit();
Option 5
$('input selector').each(function () {
$(this).rules('remove');
});
Server Side
Create an attribute and mark your action method with that attribute. Customize this to adapt to your specific needs.
[AttributeUsage(AttributeTargets.All)]
public class IgnoreValidationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var modelState = filterContext.Controller.ViewData.ModelState;
foreach (var modelValue in modelState.Values)
{
modelValue.Errors.Clear();
}
}
}
A better approach has been described here Enable/Disable mvc server side validation dynamically
Personally I would tend to use the approach Darin Dimitrov showed in his solution.
This frees you up to be able to use the data annotation approach with validation AND have separate data attributes on each ViewModel corresponding to the task at hand.
To minimize the amount of work for copying between model and viewmodel you should look at AutoMapper or ValueInjecter. Both have their individual strong points, so check them both.
Another possible approach for you would be to derive your viewmodel or model from IValidatableObject. This gives you the option to implement a function Validate.
In validate you can return either a List of ValidationResult elements or issue a yield return for each problem you detect in validation.
The ValidationResult consists of an error message and a list of strings with the fieldnames. The error messages will be shown at a location near the input field(s).
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if( NumberField < 0 )
{
yield return new ValidationResult(
"Don't input a negative number",
new[] { "NumberField" } );
}
if( NumberField > 100 )
{
yield return new ValidationResult(
"Don't input a number > 100",
new[] { "NumberField" } );
}
yield break;
}
The cleanest way here I believe is going to disable your client side validation and on the server side you will need to:
ModelState["SomeField"].Errors.Clear (in your controller or create an action filter to remove errors before the controller code is executed)
Add ModelState.AddModelError from your controller code when you detect a violation of your detected issues.
Seems even a custom view model here wont solve the problem because the number of those 'pre answered' fields could vary. If they dont then a custom view model may indeed be the easiest way, but using the above technique you can get around your validations issues.
this was someone else's answer in the comments...but it should be a real answer:
$("#SomeValue").removeAttr("data-val-required")
tested on MVC 6 with a field having the [Required] attribute
answer stolen from https://stackoverflow.com/users/73382/rob above
I was having this problem when I creating a Edit View for my Model and I want to update just one field.
My solution for a simplest way is put the two field using :
<%: Html.HiddenFor(model => model.ID) %>
<%: Html.HiddenFor(model => model.Name)%>
<%: Html.HiddenFor(model => model.Content)%>
<%: Html.TextAreaFor(model => model.Comments)%>
Comments is the field that I only update in Edit View, that not have Required Attribute.
ASP.NET MVC 3 Entity
AFAIK you can not remove attribute at runtime, but only change their values (ie: readonly true/false) look here for something similar .
As another way of doing what you want without messing with attributes I will go with a ViewModel for your specific action so you can insert all the logic without breaking the logic needed by other controllers.
If you try to obtain some sort of wizard (a multi steps form) you can instead serialize the already compiled fields and with TempData bring them along your steps. (for help in serialize deserialize you can use MVC futures)
What #Darin said is what I would recommend as well. However I would add to it (and in response to one of the comments) that you can in fact also use this method for primitive types like bit, bool, even structures like Guid by simply making them nullable. Once you do this, the Required attribute functions as expected.
public UpdateViewView
{
[Required]
public Guid? Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int? Age { get; set; }
[Required]
public bool? IsApproved { get; set; }
//... some other properties
}
As of MVC 5 this can be easily achieved by adding this in your global.asax.
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
I was looking for a solution where I can use the same model for an insert and update in web api. In my situation is this always a body content. The [Requiered] attributes must be skipped if it is an update method.
In my solution, you place an attribute [IgnoreRequiredValidations] above the method. This is as follows:
public class WebServiceController : ApiController
{
[HttpPost]
public IHttpActionResult Insert(SameModel model)
{
...
}
[HttpPut]
[IgnoreRequiredValidations]
public IHttpActionResult Update(SameModel model)
{
...
}
...
What else needs to be done?
An own BodyModelValidator must becreated and added at the startup.
This is in the HttpConfiguration and looks like this: config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());
using Owin;
using your_namespace.Web.Http.Validation;
[assembly: OwinStartup(typeof(your_namespace.Startup))]
namespace your_namespace
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
Configuration(app, new HttpConfiguration());
}
public void Configuration(IAppBuilder app, HttpConfiguration config)
{
config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());
}
...
My own BodyModelValidator is derived from the DefaultBodyModelValidator. And i figure out that i had to override the 'ShallowValidate' methode. In this override i filter the requierd model validators.
And now the IgnoreRequiredOrDefaultBodyModelValidator class and the IgnoreRequiredValidations attributte class:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Http.Controllers;
using System.Web.Http.Metadata;
using System.Web.Http.Validation;
namespace your_namespace.Web.Http.Validation
{
public class IgnoreRequiredOrDefaultBodyModelValidator : DefaultBodyModelValidator
{
private static ConcurrentDictionary<HttpActionBinding, bool> _ignoreRequiredValidationByActionBindingCache;
static IgnoreRequiredOrDefaultBodyModelValidator()
{
_ignoreRequiredValidationByActionBindingCache = new ConcurrentDictionary<HttpActionBinding, bool>();
}
protected override bool ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, object container, IEnumerable<ModelValidator> validators)
{
var actionContext = validationContext.ActionContext;
if (RequiredValidationsIsIgnored(actionContext.ActionDescriptor.ActionBinding))
validators = validators.Where(v => !v.IsRequired);
return base.ShallowValidate(metadata, validationContext, container, validators);
}
#region RequiredValidationsIsIgnored
private bool RequiredValidationsIsIgnored(HttpActionBinding actionBinding)
{
bool ignore;
if (!_ignoreRequiredValidationByActionBindingCache.TryGetValue(actionBinding, out ignore))
_ignoreRequiredValidationByActionBindingCache.TryAdd(actionBinding, ignore = RequiredValidationsIsIgnored(actionBinding.ActionDescriptor as ReflectedHttpActionDescriptor));
return ignore;
}
private bool RequiredValidationsIsIgnored(ReflectedHttpActionDescriptor actionDescriptor)
{
if (actionDescriptor == null)
return false;
return actionDescriptor.MethodInfo.GetCustomAttribute<IgnoreRequiredValidationsAttribute>(false) != null;
}
#endregion
}
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class IgnoreRequiredValidationsAttribute : Attribute
{
}
}
Sources:
Using string debug = new StackTrace().ToString() to find out who is
handeling the model validation.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/configuring-aspnet-web-api to know how set my own validator.
https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http/Validation/DefaultBodyModelValidator.cs to figure out what this validator is doing.
https://github.com/Microsoft/referencesource/blob/master/System.Web/ModelBinding/DataAnnotationsModelValidator.cs to figure out why the IsRequired property is set on true. Here you can also find the original Attribute as a property.
If you don't want to use another ViewModel you can disable client validations on the view and also remove the validations on the server for those properties you want to ignore. Please check this answer for a deeper explanation https://stackoverflow.com/a/15248790/1128216
In my case the same Model was used in many pages for re-usability purposes. So what i did was i have created a custom attribute which checks for exclusions
public class ValidateAttribute : ActionFilterAttribute
{
public string Exclude { get; set; }
public string Base { get; set; }
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!string.IsNullOrWhiteSpace(this.Exclude))
{
string[] excludes = this.Exclude.Split(',');
foreach (var exclude in excludes)
{
actionContext.ModelState.Remove(Base + "." + exclude);
}
}
if (actionContext.ModelState.IsValid == false)
{
var mediaType = new MediaTypeHeaderValue("application/json");
var error = actionContext.ModelState;
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, error.Keys, mediaType);
}
}
}
and in your controller
[Validate(Base= "person",Exclude ="Age,Name")]
public async Task<IHttpActionResult> Save(User person)
{
//do something
}
Say the Model is
public class User
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Range(18,99)]
public string Age { get; set; }
[MaxLength(250)]
public string Address { get; set; }
}
This one worked for me:
$('#fieldId').rules('remove', 'required');
Yes it is possible to disable Required Attribute. Create your own custom class attribute (sample code called ChangeableRequired) to extent from RequiredAtribute and add a Disabled Property and override the IsValid method to check if it is disbaled. Use reflection to set the disabled poperty, like so:
Custom Attribute:
namespace System.ComponentModel.DataAnnotations
{
public class ChangeableRequired : RequiredAttribute
{
public bool Disabled { get; set; }
public override bool IsValid(object value)
{
if (Disabled)
{
return true;
}
return base.IsValid(value);
}
}
}
Update you property to use your new custom Attribute:
class Forex
{
....
[ChangeableRequired]
public decimal? ExchangeRate {get;set;}
....
}
where you need to disable the property use reflection to set it:
Forex forex = new Forex();
// Get Property Descriptor from instance with the Property name
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(forex.GetType())["ExchangeRate"];
//Search for Attribute
ChangeableRequired attrib = (ChangeableRequired)descriptor.Attributes[typeof(ChangeableRequired)];
// Set Attribute to true to Disable
attrib.Disabled = true;
This feels nice and clean?
NB: The validation above will be disabled while your object instance is alive\active...