I have the current piece of code :
using System;
using System.ComponentModel.DataAnnotations;
using Boo.Lang;
class Program
{
public partial class Foo
{
public string SomeField { get; set; }
}
[MetadataType(typeof(FooMetadata))]
public partial class Foo
{
}
public class FooMetadata
{
[Required(ErrorMessage = "Some Field is required")]
public string SomeField { get; set; }
}
static void Main()
{
var sample = new Foo { SomeField = null };
var context = new ValidationContext(sample);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(sample, context, results);
if (!isValid)
{
foreach (var validationResult in results)
{
Console.WriteLine(validationResult.ErrorMessage);
}
}
else
Console.WriteLine("sample is valid");
Console.ReadLine();
}
}
It says that sample is valid although it's not the case. Am I missing something ?
Validator.ValidateObject goes through all validation attributes and throws ValidationException for the first one that fails. I don't think one can get the list of all properties that failed this way.
The MSDN documentation is a bit confusing here, it says:
The ValidateObject method evaluates each ValidationAttribute attribute
that is associated with the object type. If validateAllProperties is
set to true, the method validates the property values of the object.
TryValidateObject method manual continues:
It also checks whether each property that is marked with
RequiredAttribute is provided.
I confirm that it always checks all the Required attributes, regardless of validateAllProperties. But if you have, for example, a Range validation attribute it will only check it when validateAllProperties is true (because this is when it validates the property value).
A bit confusing, but as you noticed, TryValidateObject shows all the failed properties.
Related
I need to mark some properties as passwords so that they could be automatically screened. I found a standard attribute for that:
[PasswordPropertyText]
public string ThePassword { get; set; }
Following method checks if the attribute is there:
private static bool _isPassword(PropertyInfo p)
{
PasswordPropertyTextAttribute passProp = (PasswordPropertyTextAttribute)p.GetCustomAttribute(typeof(PasswordPropertyTextAttribute));
return (passProp != null); // Additional condition should go here
}
Now I would like to have my own logic here:
[PasswordPropertyText] should result in true.
[PasswordPropertyText(true)] should result in true.
[PasswordPropertyText(false)] should result in false.
but the default value of PasswordPropertyTextAttribute.Password is false when the argument is omitted.
Is there any way to get the raw attribute value?
Since attribute constructor information are stored as metadata as well you can get the required information by calling the GetCustomAttributesData method. Have a look at this simple example:
class Program
{
[PasswordPropertyText]
public string Password1 { get; set; }
[PasswordPropertyText(true)]
public string Password2 { get; set; }
[PasswordPropertyText(false)]
public string Password3 { get; set; }
static void Main(string[] args)
{
var props = typeof(Program).GetProperties();
foreach(var prop in props)
{
var attributeData = prop.GetCustomAttributesData().First(x => x.AttributeType == typeof(PasswordPropertyTextAttribute));
Console.WriteLine($"{prop.Name}: {(attributeData.ConstructorArguments.Cast<CustomAttributeTypedArgument?>().FirstOrDefault()?.Value ?? true)}");
}
Console.ReadLine();
}
}
Output:
Password1: True
Password2: True
Password3: False
What you're describing cannot be done using reflection.
Reflection is not looking at the code as it was written: it is looking at the model that results from that code. Since the default constructor for PasswordPropertyTextAttribute passes a false value to another constructor, the model that it produces is indistinguishable from using [PasswordPropertyText(false)].
If you want different behavior from the built-in attribute, I'd recommend creating your own attribute that has the behavior you're looking for instead.
I have a problem to read a Custom Attributes.
I have read more tutorial for this, but cannot read the value.
NB: I use a console application.
Main Class
namespace IRCBotter
{
public class IrcBot
{
[UserLevel(LevelRequired = 10)]
void HelpCommand(string user)
{
GetAttribute(typeof(IrcBot));
}
public static void GetAttribute(Type t)
{
// Get instance of the attribute.
UserLevel MyAttribute =
(UserLevel)Attribute.GetCustomAttribute(t, typeof(UserLevel));
if (MyAttribute == null)
{
Message.Error("The attribute was not found.");
}
else
{
// Get the Name value.
Message.Error("Valore " + MyAttribute.LevelRequired.ToString());
}
}
}
}
Attribute Class
namespace IRCBotter.Commands
{
[AttributeUsage(AttributeTargets.All ,AllowMultiple=true)]
class UserLevel : Attribute
{
public int LevelRequired { get; set; }
}
}
on debug, Console say me "The attribute was not found".
Have a one simple working example for get correct value from custom attribute?
In the void HelpCommand
need to check if variable user stored is equal in one stored list
and him level is > in LevelRequired.
You haven't declared the attribute on the class, you defined it on the method HelpCommand. You will have to get the MethodInfo for HelpCommand and call GetCustomAttribute on that. Something along these lines.
MethodInfo method = type.GetMethod("HelpCommand");
UserLevel userLevel = method.GetCustomAttribute<UserLevel>();
I have a created an object that will hold errors encountered as well as a boolean field to indicate if any errors were present at all. The class looks like this.
public class ValidationResult
{
public bool IsValid{ get; set; }
public List<string> Errors { get; set; }
}
I go to use an instance of this class in a validation method as such
public class ValidationService
{
// This instance will hold the errors if there are any
ValidationResult myValidationResult = new ValidationResult();
public void ValidationMethod()
{
// Validation takes place here
...
// Some errors occurred to lets add then to the instance of the ValidationResult object
myValidationResult.IsValid = false;
myValidationResult.Errors.Add("An error occurred here are the details");
}
}
The problem is that the Errors collection in the instance myValidationResult is null? Why is this? I created an instance of the class and the boolean property IsValid is available, yet the Errors collection is null.
You must initialize your Errors property:
public class ValidationResult
{
public ValidationResult()
{
Errors = new List<string>();
}
public bool IsValid{ get { return (Errors.Count() == 0); } }
public List<string> Errors { get; set; }
}
Only value types are initialized per default. Your List<string> is a reference type and it does have it default value - null.
Look here for a little bit more information:
https://msdn.microsoft.com/en-us/library/aa691171(v=vs.71).aspx
Here is my entire program. I expect it to return false but the result is true. Do I expect wrong result or I do something wrong here?
using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations;
public class Program
{
public static void Main()
{
var c = new Ax(){Id = 1000, Name = "A"};
//c.Name = null; // when un-comment this, result as expected
var context = new ValidationContext(c);
var isValid = Validator.TryValidateObject(c, context, null);
Console.WriteLine(isValid);
}
public class Ax
{
[Range(1,100)] // I expect this to cause failed validation
public int Id{get; set;}
[Required]
public string Name { get; set; }
}
}
Result: true
You are using this method:
Validator.TryValidateObject(Object, ValidationContext, ICollection<ValidationResult>)
This method evaluates each ValidationAttribute instance that is
attached to the object type. It also checks whether each property that
is marked with RequiredAttribute is provided. It does not recursively
validate the property values of the object.
You should use the other overload and pass true as third parameter:
Validator.TryValidateObject (Object,
ValidationContext,
ICollection<ValidationResult>, Boolean)
I have a class (Application) that has multiple properties of the type of another custom class (Employment). I would like to validate that Employment class conditionally based on whether the property of the Application class is marked with [Required].
From what I've found, I think I should be utilizing the IValidatableObject interface for Employment. The problem is that I'm not sure how to use reflection (or something else maybe) to check if this instance of the class is annotated with the [Required] attribute to determine whether to validate it or not.
Maybe this isn't even possible. I initially set up two classes for the Employment class: Employment and EmploymentRequired. Only the latter had the validation attributes on its properties. It works, but I'd like to just have one class to use if possible.
public class Application
{
[Required]
public Employment Employer1 { get; set; }
public Employment Employer2 { get; set; }
}
public class Employment : IValidatableObject
{
[Required]
public string EmployerName { get; set; }
[Required]
public string JobTitle { get; set; }
public string Phone { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
var t = this.GetType();
//var pi = t.GetProperty("Id");
//var isRequired = Attribute.IsDefined(pi, typeof(RequiredAttribute));
//how can I get the attributes of this property in Application class?
if (isRequired)
{
Validator.TryValidateProperty(this.EmployerName,
new ValidationContext(this, null, null) { MemberName = "EmployerName" }, results);
Validator.TryValidateProperty(this.JobTitle,
new ValidationContext(this, null, null) { MemberName = "JobTitle" }, results);
}
return results;
}
}
You should be able to check for the required attribute using Attribute.IsDefined.
http://msdn.microsoft.com/en-us/library/system.attribute.isdefined.aspx
Seems like you can't do this, because using reflection you can't get parent object/class that references your current instance and all the more so reference property information.
EDIT: Maybe you can make Employment type Generic with required and non required validation modes?
I think you are searching for the Attribute.IsDefined method. You would have to first obtain the reference to the field itself, and then validate the presence of the attribute. Like the following (adapted from the example at MSDN):
// Get the class type (you can also get it directly from an instance)
Type clsType = typeof(Application);
// Get the FieldInfo object
FieldInfo fInfo = clsType.GetField("Employer1");
// See if the Required attribute is defined for the field
bool isRequired = Attribute.IsDefined(fInfo , typeof(RequiredAttribute));
Since what I'm trying to do doesn't seem to be possible exactly, I found a different way to do it, based on the suggestion of #user1578874. I added an IsRequired property to Employment and used MVC Foolproof Validation to mark those properties as [RequiredIf("IsRequired")]. Seems to be the cleanest solution.