I'm using Entity Framework and all the entities inherits from BaseObject:
public class BaseObject : IDataErrorInfo
{
private string _validationMessage;
public BaseObject()
{
_validationMessage = string.Empty;
}
public void Validate()
{
Validator validator = ValidationFactory.CreateValidator(GetType());
var validationResults = validator.Validate(this);
if (validationResults.Count > 0)
{
StringBuilder message = new StringBuilder();
foreach (var validationResult in validationResults)
{
message.Append(validationResult.Message);
message.Append(Environment.NewLine);
}
_validationMessage = message.ToString();
//throw new ValidationException(message.ToString());
}
}
public string Error
{
get
{
_validationMessage = string.Empty;
this.Validate();
return _validationMessage;
}
}
public string this[string columnName]
{
get
{
_validationMessage = string.Empty;
this.Validate();
return _validationMessage;
}
}
}
BaseObjects implements the IDataErrorInfo interface so I can use the ErrorProvider in combination with a bindingsource. The problem with this code is that when one property is invalid, all the other properties are invalid too. So my question is, how can I solve this? I am using the Validation Application Block and I don't know how I can validate a single property.
#Tuzo: I think it is possible by using the PropertyValidationFactory.GetPropertyValidator method.
Related
I have a scenario for login user. I write this code for check user if validate return success message.
I am using the chain responsibility pattern for this validation but it seems ugly because I need to more new in this class.
Now I want to write clean and best practice for using this pattern.
How can I do this ?
public abstract class ValidateUser
{
protected readonly ValidateUser _validateUser;
public ValidateUser(ValidateUser validateUser)
{
_validateUser = validateUser;
}
public abstract UserContext ValidateUserLogin(UserContext request);
}
CheckIsActive :
public class CheckIsActive : ValidateUser
{
public CheckIsActive(ValidateUser validateUser) : base(validateUser)
{
}
public override UserContext ValidateUserLogin(UserContext request)
{
if (request.Context.IsActive)
{
return _validateUser.ValidateUserLogin(request);
}
return new UserContext
{
Message = "User Not Active"
};
}
}
CheckPhoneConfirmed :
public class CheckPhoneConfirmed : ValidateUser
{
public CheckPhoneConfirmed(ValidateUser validateUser) : base(validateUser)
{
}
public override UserContext ValidateUserLogin(UserContext request)
{
if (request.Context.ConfirmPhoneNumber)
{
return _validateUser.ValidateUserLogin(request);
}
return new UserContext
{
Message="Phone Number Not confirmed"
};
}
}
CheckIsLockedAccount :
public class CheckIsLockedAccount : ValidateUser
{
public CheckIsLockedAccount(ValidateUser validateUser) : base(validateUser)
{
}
public override UserContext ValidateUserLogin(UserContext request)
{
if (!request.Context.IsLockedEnd)
{
return new UserContext
{
Context = request.Context
};
}
return new UserContext
{
Message = $"Your account is deactivated from to date {request.Context.LockedEnd}"
};
}
}
and I use this Validate by this way :
var validate = new CheckIsActive(new CheckPhoneConfirmed(new CheckIsLockedAccount(null)));
var validateUserContext = validate.ValidateUserLogin(new UserContext
{
Context = findUSer.Result,
Message = null
});
You can use .net core Middleware pipeline, which is based upon Chain of Responsibility pattern only.
app.Use(async (context, next) =>
{
if (context.Request.HttpContext.User.HasClaim("IsLockedEnd", "true"))
{
await next();
}
});
app.Use(async (context, next) =>
{
if (context.Request.HttpContext.User.HasClaim("ConfirmPhoneNumber", "true"))
{
await next();
}
});
app.Use(async (context, next) =>
{
if (context.Request.HttpContext.User.HasClaim("IsActive", "true"))
{
await next();
}
});
I dont feel like this pattern fits here for validation.
If you google you find following description of your pattern:
Chain of Responsibility is behavioral design pattern that allows
passing request along the chain of potential handlers until one of
them handles request. The pattern allows multiple objects to handle
the request without coupling sender class to the concrete classes of
the receivers
I dont think any of that is the case in your solution. Since I feel you dont wanna handle different validations at different places?? I think you are missusing this pattern as a decorator pattern.
Instead try the following:
How about you split your objects into following:
First you need a abstract class so you can define later you validation rule
public abstract class ValidationRule
{
public string Property { get; set; }
public string Error { get; set; }
public ValidationRule(string property)
{
Property = property;
Error = property + " is not valid";
}
public ValidationRule(string property, string error)
: this(property)
{
Error = error;
}
// validation method. To be implemented in derived classes
public abstract bool Validate(Validator validator);
// gets value for given business object's property using reflection
protected object GetPropertyValue(Validator validator)
{
// note: reflection is relatively slow
return validator.GetType().GetProperty(Property).GetValue(validator, null);
}
}
Then you can this class to make a more concrete validator. Maybe a finished rule or something you can even reuse more as for example:
public class ValidateRegex : ValidationRule
{
protected string Pattern { get; set; }
public ValidateRegex(string propertyName, string pattern)
: base(propertyName)
{
Pattern = pattern;
}
public ValidateRegex(string propertyName, string errorMessage, string pattern)
: this(propertyName, pattern)
{
Error = errorMessage;
}
public override bool Validate(Validator validator)
{
return Regex.Match(GetPropertyValue(validator).ToString(), Pattern).Success;
}
}
and then make a final rule out of it
public class ValidateEmail : ValidateRegex
{
public ValidateEmail(string propertyName) :
base(propertyName, #"\w+([-+.]\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*")
{
Error = propertyName + " is not a valid email address";
}
public ValidateEmail(string propertyName, string errorMessage) :
this(propertyName)
{
Error = errorMessage;
}
}
The Validator can look something like this:
public abstract class Validator
{
// list of business rules
List<ValidationRule> rules = new List<ValidationRule>();
// list of validation errors (following validation failure)
List<string> errors = new List<string>();
// gets list of validations errors
public List<string> Errors
{
get { return errors; }
}
// adds a business rule to the business object
protected void AddRule(ValidationRule rule)
{
rules.Add(rule);
}
// determines whether business rules are valid or not.
// creates a list of validation errors when appropriate
public bool IsValid()
{
bool valid = true;
errors.Clear();
foreach (var rule in rules)
{
if (!rule.Validate(this))
{
valid = false;
errors.Add(rule.Error);
}
}
return valid;
}
}
You can use now the validator as following (Note if constructor when you implement a lot of different validation rules):
public class Person : Validator
{
public Person ()
{
AddRule(new ValidateEmail("Email"));
AddRule(new ValidateId("MemberId"));
AddRule(new ValidateRequired("Email"));
AddRule(new ValidateLength("Email", 1, 100));
AddRule(new ValidateRequired("CompanyName"));
AddRule(new ValidateLength("CompanyName", 1, 40));
AddRule(new ValidateRequired("City"));
AddRule(new ValidateLength("City", 1, 15));
AddRule(new ValidateRequired("Country"));
AddRule(new ValidateLength("Country", 1, 15));
}
public int MemberId { get; set; }
public string Email { get; set; }
public string CompanyName { get; set; }
public string City { get; set; }
public string Country { get; set; }
public int NumOrders { get; set; }
public DateTime LastOrderDate { get; set; }
}
If you call now the IsValid() method all your validationrules get executed.
I feel like this is kinda what you want. If you dont wanna tie it to an object, you could try to create a standalone validator and composite the validator into the class where you need it instead from deriving from it.
Currently I'm developing .net 4.5 wpf MVVM application with validation system handled by INotifyDataErrorInfo. At some point in application I have to check if there are any validation errors, currently it's done like this:
public class RootViewModel : BindableBase
{
//class code
if (designInformation.Technology == Technology.CVT)
{
if (designInformation.HasErrors) return;
if (InfoInputViewModel.TrafoProperties.HasErrors) return;
if (InfoInputViewModel.CapacitorVoltageTransformerViewModel.CapacitorVoltageDivider.HasErrors) return;
if (InfoInputViewModel.CapacitorVoltageTransformerViewModel.IntermediateVoltageTransformer.HasErrors) return;
if (SpecialDesignViewModel.SpecialDesignInformation.HasErrors) return;
foreach (var item in InfoInputViewModel.SecondaryWindings.WindingsCollection)
{
if (item.HasErrors) return;
}
performCalculationsCVT();
}
}
And I'm looking for a way to simplify this code by getting all errors from model at once, but don't know where to start with this problem.
Bellow is implementation of INotifyDataErrorInfo interface i use.
public class ValidableBase : BindableBase, INotifyDataErrorInfo
{
protected readonly Dictionary<string, ICollection<string>>
_validationErrors = new Dictionary<string, ICollection<string>>();
#region INotifyDataErrorInfo Implementation
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
protected void RaiseErrorsChanged(string propertyName)
{
if (ErrorsChanged != null)
ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
}
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName) || !_validationErrors.ContainsKey(propertyName))
return null;
return _validationErrors[propertyName];
}
public bool HasErrors
{
get { return _validationErrors.Count > 0; }
}
public void AddError(string propertyName, string message)
{
if (_validationErrors.ContainsKey(propertyName))
{
string value = _validationErrors[propertyName].First();
value += Environment.NewLine;
value += message;
_validationErrors[propertyName] = new List<string> { value };
}
else
_validationErrors[propertyName] = new List<string> { message };
RaiseErrorsChanged(propertyName);
}
public void RemoveError(string propertyName)
{
_validationErrors.Remove(propertyName);
RaiseErrorsChanged(propertyName);
}
[XmlIgnore]
public Dictionary<string, ICollection<string>> ValidationErrors
{
get { return this._validationErrors; }
}
#endregion
}
}
Obviously, the base class has no idea what properties a particular child class has, let alone if they implement INDEI. You'll have to write the logic to do this. There are many ways you can accomplish this.
For me, I'd add an abstract method to the base class thusly
abstract class ValidableBase
{
// snip
protected abstract IEnumerable<ValidableBase> GetValidableProperties();
// snip
Then change HasErrors to call HasErrors recursively on the results of the above call
public bool HasErrors
{
get { return _validationErrors.Count > 0 ||
GetValidableProperties().Any(x => x.HasErrors); }
}
An example implementation of GetValidableProperties might be
protected override IEnumerable<ValidableBase> GetValidableProperties()
{
yield return SomeProperty; // a Validable property
yield return SomeOtherProperty; // this too
foreach(var prop in SomeCollectionProperty) // collection of Validable
yield return prop;
}
Lastly, I'd rename Validable to Validatable, which is the correct (english) spelling. If I were Spanish or French, I'd probably skip that last step.
I'm just wondering what is the datatype of value variable in C#'s set accessor?
Because I want to implement type-hinting in C#'s set accessor.
For example, I have a setter method:
public User
{
private string username;
public void setUsername(SingleWord username)
{
this.username = username.getValue(); // getValue() method from "SingleWord" class returns "string"
}
}
Now how do I implement this in C#'s accessor syntax?
public User
{
public string Username
{
get ;
set {
// How do I implement type-hinting here for class "SingleWord"?
// Is it supposed to be:
// this.Username = ((SingleWord)value).getValue(); ???
}
}
}
So that I can call it this way:
User newuser = new User() {
Username = new SingleWord("sam023")
};
Thanks in advance!
EDIT: Here's the source code of SingleWord:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Guitar32.Exceptions;
using Guitar32.Common;
namespace Guitar32.Validations
{
public class SingleWord : Validator, IStringDatatype
{
public static String expression = "^[\\w\\S]+$";
public static String message = "Spaces are not allowed";
private String value;
public SingleWord(String value, bool throwException = false) {
this.value = value;
if (throwException && value != null) {
if (!this.isValid()) {
throw new InvalidSingleWordException();
}
//if (this.getValue().Length > 0) {
// if (!this.isWithinRange()) {
// throw new Guitar32.Exceptions.OutOfRangeLengthException();
// }
//}
}
}
public int getMaxLength() {
return 99999;
}
public int getMinLength() {
return 1;
}
public String getValue() {
return this.value;
}
public bool isWithinRange() {
return this.getValue().Length >= this.getMinLength() && this.getValue().Length <= this.getMaxLength();
}
public override bool isValid() {
return this.getValue().Length > 0 ? Regex.IsMatch(this.getValue(), expression) : true;
}
}
public class InvalidSingleWordException : Exception {
public InvalidSingleWordException() : base("Value didn't comply to Single Word format")
{ }
}
}
I used this class to provide back-end validation by adding SingleWord as the datatype required from the setter.
The type of value is the type of the property, no matter what.
So in your example,
public string Username
{
...
set
{
value.GetType() // -> string
...
}
}
The simple solution for what you're looking for is to just call .getValue() on your SingleWord instance,
User newuser = new User()
{
Username = new SingleWord("sam023").getValue()
};
Or better yet, but I assume this won't work because of code you haven't shown us,
User newuser = new User()
{
Username = "sam023"
};
But if that's an absolute no-go, what it sounds like you're looking for is an implicit operator on SingleWord. If you have the ability to modify the class, you can add an operator that looks like this, and it'll automatically perform the conversion to a string such that you should be able to use the syntax you've listed.
public static implicit operator string(SingleWord d)
{
return d.getValue();
}
I'm using the INotifyDataErrorInfo interface to implement a general MVVM validation mechanism. I'm implementing the interface by calling OnValidate instead of OnPropertyChanged:
public void OnValidate(dynamic value, [CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
Validate(propertyName, value);
}
In the Validate Method I'm generating the validation errors, add them to a Dictionary and raise the ErrorsChanged event if a validation error was found or cleared:
if (entry.Validate(strValue, out errorNumber, out errorString) == false)
{
_validationErrors[propertyName] = new List<string> {errorString};
RaiseErrorsChanged(propertyName);
}
else if (_validationErrors.ContainsKey(propertyName))
{
_validationErrors.Remove(propertyName);
RaiseErrorsChanged(propertyName);
}
The HasErrors property is implemented by looking at the errors dictionary:
public bool HasErrors
{
get { return _validationErrors.Any(kv => kv.Value != null
&& kv.Value.Count > 0); }
}
To prevent the save button from being enabled when there is a validation error - The save command canExecuteMethod looks at the HasErrors property:
private bool IsSaveEnabled()
{
return HasErrors == false;
}
Everything works fine except the case where I'm having binding errors - if the binded value is (for example) an integer a non integer is entered - the textbox's ErrorContent is updated with an error string: "Value 'something' could not be converted".
But the INotifyDataErrorInfo mechanism is not updated about this. The HasErrors remains false and Save is enabled although there is an error in the view.
I would like to find a way to propagate the binding exception to the INotifyDataErrorInfo mechanism so I would be able to:
Disable the Save button (must).
Change the validation error message to a more meaningful error string (nice to have).
I would like to find a general MVVM solution without adding code behind in the view.
Thank you for the help
the string int case doesn't work with MVVM because your viewmodel doesn't get any information because of the binding exception.
I see two ways to get the validation you want:
Just use string properties in your viewmodel and when you have to go to your model just convert the string to your model type.
Create behaviors or "special" controls so the the input in your view is always "convertible" to your viewmodel type.
Btw I use the second approach because I have to :) but the first will always work and seems easier to me.
Here is the solution that I have found. It makes the INotifyDataErrorInfo behave correctly in the ViewModel (When there is any validation error – the HasError is true), and it allows adding validation errors from the viewModel. Other than this, it does not require changes in the view, changes in the binding or converters.
This solution involves:
Adding a custom validation rule.
Adding a base user control (which all view must derive from).
Adding some code in the ViewModel base.
Adding a custom validation rule – Validation Entity which does the actual validation and raises an event when the validation changes:
class ValidationEntity : ValidationRule
{
public string Key { get; set; }
public string BaseName = "Base";
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
var fullPropertyName = BaseName + "." + Key;
ValidationEntry entry;
var validationResult = new ValidationResult(true, null);
if ((entry = ValidationManager.Instance.FindValidation(fullPropertyName)) != null)
{
int errorNumber;
string errorString;
var strValue = (value != null) ? value.ToString() : string.Empty;
if (entry.Validate(strValue, out errorNumber, out errorString) == false)
{
validationResult = new ValidationResult(false, errorString);
}
}
if (OnValidationChanged != null)
{
OnValidationChanged(Key, validationResult);
}
return validationResult;
}
public event Action<string, ValidationResult> OnValidationChanged;
}
Adding a base user control which keeps a list of the active textboxs, and adds the validation rule to each textbox binding:
This is the code at the user control base:
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
_textBoxes = FindAllTextBoxs(this);
var vm = DataContext as ViewModelBase;
if (vm != null) vm.UpdateAllValidationsEvent += OnUpdateAllValidationsEvent;
foreach (var textbox in _textBoxes)
{
var binding = BindingOperations.GetBinding(textbox, TextBox.TextProperty);
if (binding != null)
{
var property = binding.Path.Path;
var validationEntity = new ValidationEntity {Key = property};
binding.ValidationRules.Add(validationEntity);
validationEntity.ValidationChanged += OnValidationChanged;
}
}
}
private List<TextBox> FindAllTextBoxs(DependencyObject fe)
{
return FindChildren<TextBox>(fe);
}
private List<T> FindChildren<T>(DependencyObject dependencyObject)
where T : DependencyObject
{
var items = new List<T>();
if (dependencyObject is T)
{
items.Add(dependencyObject as T);
return items;
}
var count = VisualTreeHelper.GetChildrenCount(dependencyObject);
for (var i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
var children = FindChildren<T>(child);
items.AddRange(children);
}
return items;
}
When the ValidationChange event happens – the view is called to be notified about the validation error:
private void OnValidationChanged(string propertyName, ValidationResult validationResult)
{
var vm = DataContext as ViewModelBase;
if (vm != null)
{
if (validationResult.IsValid)
{
vm.ClearValidationErrorFromView(propertyName);
}
else
{
vm.AddValidationErrorFromView(propertyName, validationResult.ErrorContent as string);
}
}
}
The ViewModel base keeps two lists:
_notifyvalidationErrors which is used by the INotifyDataErrorInfo interface to display the validation errors.
_privateValidationErrors which is used to display the errors generated from the Validation rule to the user.
When adding a validation error from the view – the _notifyvalidationErrors is updated with an empty value (just to denote there is a validation error) the error string is not added to the _notifyvalidationErrors. If we add it to there we would get the validation error string twice in the textbox ErrorContent.
The validation error string is also added to _privateValidationErrors (Because we want to be able to keep it at the viewmodel)
This is the code at the ViewModel base:
private readonly Dictionary<string, List<string>> _notifyvalidationErrors =
new Dictionary<string, List<string>>();
private readonly Dictionary<string, List<string>> _privateValidationErrors =
new Dictionary<string, List<string>>();
public void AddValidationErrorFromView(string propertyName, string errorString)
{
_notifyvalidationErrors[propertyName] = new List<string>();
// Add the error to the private dictionary
_privateValidationErrors[propertyName] = new List<string> {errorString};
RaiseErrorsChanged(propertyName);
}
public void ClearValidationErrorFromView(string propertyName)
{
if (_notifyvalidationErrors.ContainsKey(propertyName))
{
_notifyvalidationErrors.Remove(propertyName);
}
if (_privateValidationErrors.ContainsKey(propertyName))
{
_privateValidationErrors.Remove(propertyName);
}
RaiseErrorsChanged(propertyName);
}
The INotifyDataErrorInfo implementation in the view:
public bool HasErrors
{
get { return _notifyvalidationErrors.Any(kv => kv.Value != null); }
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public void RaiseErrorsChanged(string propertyName)
{
var handler = ErrorsChanged;
if (handler != null)
handler(this, new DataErrorsChangedEventArgs(propertyName));
}
public IEnumerable GetErrors(string propertyName)
{
List<string> errorsForProperty;
_notifyvalidationErrors.TryGetValue(propertyName, out errorsForProperty);
return errorsForProperty;
}
The user has an option to add validation errors from the view by calling the ViewModelBase AddValidationError and ClearValidationError methods.
public void AddValidationError(string errorString, [CallerMemberName] string propertyName = null)
{
_notifyvalidationErrors[propertyName] = new List<string>{ errorString };
RaiseErrorsChanged(propertyName);
}
public void ClearValidationError([CallerMemberName] string propertyName = null)
{
if (_notifyvalidationErrors.ContainsKey(propertyName))
{
_notifyvalidationErrors.Remove(propertyName);
RaiseErrorsChanged(propertyName);
}
}
The view can get a list of all current validation errors from the ViewModel base by calling the GetValidationErrors and GetValidationErrorsString methods.
public List<string> GetValidationErrors()
{
var errors = new List<string>();
foreach (var key in _notifyvalidationErrors.Keys)
{
errors.AddRange(_notifyvalidationErrors[key]);
if (_privateValidationErrors.ContainsKey(key))
{
errors.AddRange(_privateValidationErrors[key]);
}
}
return errors;
}
public string GetValidationErrorsString()
{
var errors = GetValidationErrors();
var sb = new StringBuilder();
foreach (var error in errors)
{
sb.Append("● ");
sb.AppendLine(error);
}
return sb.ToString();
}
Set
ValidatesOnExceptions="True"
In your Binding expression.
Hi all i am using mvvmcross and portable class libraries , so i cannot use prism or componentmodel data annotations, to validate my classes. basically i have a modelbase that all my models inherit from.
My validate code below is horribly broken, basically im looking for the code that data annotations uses to iterate thru all the properties on my class that is inheriting the base class ,
i have written various attributes that are there own validators inheriting from "validatorBase" which inherits from attribute. i just cannot for the life of me figure out thecode that says ... ok im a class im going to go through all the properties in me that have an attribute of type ValidatorBase and run the validator. my code for these are at the bottom
public class ModelBase
{
private Dictionary<string, IEnumerable<string>> _errors;
public Dictionary<string, IEnumerable<string>> Errors
{
get
{
return _errors;
}
}
protected virtual bool Validate()
{
var propertiesWithChangedErrors = new List<string>();
// Get all the properties decorated with the ValidationAttribute attribute.
var propertiesToValidate = this.GetType().GetRuntimeProperties()
.Where(c => c.GetCustomAttributes(typeof(ValidatorBase)).Any());
foreach (PropertyInfo propertyInfo in propertiesToValidate)
{
var propertyErrors = new List<string>();
TryValidateProperty(propertyInfo, propertyErrors);
// If the errors have changed, save the property name to notify the update at the end of this method.
bool errorsChanged = SetPropertyErrors(propertyInfo.Name, propertyErrors);
if (errorsChanged && !propertiesWithChangedErrors.Contains(propertyInfo.Name))
{
propertiesWithChangedErrors.Add(propertyInfo.Name);
}
}
// Notify each property whose set of errors has changed since the last validation.
foreach (string propertyName in propertiesWithChangedErrors)
{
OnErrorsChanged(propertyName);
OnPropertyChanged(string.Format(CultureInfo.CurrentCulture, "Item[{0}]", propertyName));
}
return _errors.Values.Count == 0;
}
}
here is my validator
public class BooleanRequired : ValidatorBase
{
public override bool Validate(object value)
{
bool retVal = true;
retVal = value != null && (bool)value == true;
var t = this.ErrorMessage;
if (!retVal)
{
ErrorMessage = "Accept is Required";
}
return retVal;
}
}
and here is an example of its usage
[Required(ErrorMessage = "Please enter the Amount")]
public decimal Amount
{
get { return _amount; }
set { _amount = value; }//SetProperty(ref _amount, value); }
}