How to retrieve Data Annotations from code? (programmatically)
Extension method:
public static T GetAttributeFrom<T>(this object instance, string propertyName) where T : Attribute
{
var attrType = typeof(T);
var property = instance.GetType().GetProperty(propertyName);
return (T)property .GetCustomAttributes(attrType, false).First();
}
Code:
var name = player.GetAttributeFrom<DisplayAttribute>(nameof(player.PlayerDescription)).Name;
var maxLength = player.GetAttributeFrom<MaxLengthAttribute>(nameof(player.PlayerName)).Length;
Get Data Annotations attributes from model
This is the universal way how to do this:
private string GenerateValidationModel<T>()
{
var name = typeof(T).Name.Replace("Model", "ViewModel");
name = Char.ToLowerInvariant(name[0]) + name.Substring(1);
var validationModel = "var " + name + " = {\n";
foreach (var prop in typeof(T).GetProperties())
{
object[] attrs = prop.GetCustomAttributes(true);
if (attrs == null || attrs.Length == 0)
continue;
string conds = "";
foreach (Attribute attr in attrs)
{
if (attr is MinLengthAttribute)
{
conds += ", minLength: " + (attr as MinLengthAttribute).Length;
}
else if (attr is RequiredAttribute)
{
conds += ", required: true";
}
// ...
}
if (conds.Length > 0)
validationModel += String.Format("\t{0}: ko.observable().extend({{ {1} }}),\n", prop.Name, conds.Trim(',', ' '));
}
return validationModel + "};";
}
Usage:
string validationModel = GenerateValidationModel<LoginModel>();
Output:
var loginViewModel = {
UserName: ko.observable().extend({ minLength: 3, required: true}),
Password: ko.observable().extend({ required: true}),
};
It's good idea to cache the output
Adding and Removing Data Annotations from code
It is impossible to add, remove or modify DataAnnotations dynamically since they are Attributes. Attributes are part of the type and can't be changed during runtime.
You could use ModelState as Larsenal suggested provided that:
- you use it After validation has executed. (prior to that, ModelState will be empty. It doesn't provide access to all validators, it only stores validator-errors after they've occurred)
- you don't have any clientside validation that's based on the DataAnnotationValidators and fires errors that prevent you from even reaching the serverside validation.
Get parameter's value of a Data Annotation
You need to use reflection to get the attribute applied to your controller action. Below is a quick and dirty example of how you could do that:
private string GetPermissionFilerValue()
{
object[] attributes = typeof(YourControllerType).GetType().GetMethod("Index").GetCustomAttributes(typeof (PermissionFilterAttribute));
return attributes[0].Roles;
}
Basically you need to get a reference to your controller's type and then from that, get a reference to the method on your controller. Once you have that, in the form a MethodInfo object, you can use GetCustomAttributes to get all custom attributes applied to your method or all custom attributes of a specific type. Once you have your attribute instance you can inspect the Roles property.
As I mentioned, the example above is a very quick and dirty demonstration of how to get an attribute instance for a specific method. You'll likely need to tailor it to fit it into your specific scenario.
How to retrieve GroupName data annotation from ModelMetadata
GroupName
is not parsed by the DataAnnotationsModelMetadataProvider
. So there's no way to get it right off the ModelMetadata
object, even with an extension method.
You could implement your own provider that extends the existing one to add support for GroupName, which Brad Wilson explains in his blog.
You could also write your own attribute instead of using Display(GroupName = )
and implement the IMetadataAware
interface to add the groupname to ModelMetadata.AdditionalValues
.
Data-Annotations - EntityValidation removal based on condition in code
That is not possible with the existing RequiredAttribute
.
However, you can implement your own custom conditional validation attribute.
Here are some links to guide you in the right direction:
http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx
http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx
http://blogs.msdn.com/b/simonince/archive/2011/09/29/mvc-validationtookit-alpha-release-conditional-validation-with-mvc-3.aspx
Once you implement your custom RequiredIf
conditional validation attribute you can set the condition like:
public class ValidationSample
{
[RequiredIf("PropertyValidationDependsOn", true)]
public string PropertyToValidate { get; set; }
public bool PropertyValidationDependsOn { get; set; }
}
How to catch DataAnnotations Validation in MVVM
the solution
public class Person : IDataErrorInfo // Represents person data.
{
/// <summary>
/// Gets or sets the person's first name.
/// </summary>
/// <remarks>
/// Empty string or null are not allowed.
/// Allow minimum of 2 and up to 40 uppercase and lowercase.
/// </remarks>
[Required]
[RegularExpression(@"^[a-zA-Z''-'\s]{2,40}$")]
public string FirstName{ get; set;}
/// <summary>
/// Gets or sets the person's last name.
/// </summary>
/// <remarks>
/// Empty string or null are not allowed.
/// </remarks>
[Required]
public string LastName { get; set;}
public int Age{ get; set;}
public string Error // Part of the IDataErrorInfo Interface
{
get { throw new NotImplementedException(); }
}
string IDataErrorInfo.this[string propertyName] // Part of the IDataErrorInfo Interface
{
get { return OnValidate(propertyName); }
}
/// <summary>
/// Validates current instance properties using Data Annotations.
/// </summary>
/// <param name="propertyName"></param>
/// <returns></returns>
protected virtual string OnValidate(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
throw new ArgumentException("Invalid property name", propertyName);
string error = string.Empty;
var value = this.GetType().GetProperty(propertyName).GetValue(this, null);
var results = new List<ValidationResult>(1);
var context = new ValidationContext(this, null, null) { MemberName = propertyName };
var result = Validator.TryValidateProperty(value, context, results);
if (!result)
{
var validationResult = results.First();
error = validationResult.ErrorMessage;
}
return error;
}
}
thanks to Rachel for here hint
and to this link which was very enlightened
Related Topics
Unique Random String Generation
How to Find and Replace Text in a File
Silent Failures in C#, Seemingly Unhandled Exceptions That Does Not Crash the Program
How to Use a MySQL User Defined Variable in a .Net MySQLcommand
How to Get Current User Timezone in C#
How to Convert an Escaped JSON String Within a JSON Object
Why Cannot C# Generics Derive from One of the Generic Type Parameters Like They Can in C++ Templates
Parameterized Queries VS. SQL Injection
Why Interface Layer/Abstract Classes Required in Our Project
What Does Placing a @ in Front of a C# Variable Name Do
.Net Xml Serialization Gotchas
Oraclecommand SQL Parameters Binding
Properties VS. Fields: Need Help Grasping the Uses of Properties Over Fields