How can i validate this attribute(annonation)? - c#

I am new about attributes. I just try it on my console application.
So how can i validate my person instance below example ?
class Person
{
[StringLength(8,ErrorMessage="Please less then 8 character")]
public string Name { get; set; }
}

Here is simple code example without reflection.
class Program
{
static void Main(string[] args)
{
var invalidPerson = new Person { Name = "Very long name" };
var validPerson = new Person { Name = "1" };
var validator = new Validator<Person>();
Console.WriteLine(validator.Validate(validPerson).Count);
Console.WriteLine(validator.Validate(invalidPerson).Count);
Console.ReadLine();
}
}
public class Person
{
[StringLength(8, ErrorMessage = "Please less then 8 character")]
public string Name { get; set; }
}
public class Validator<T>
{
public IList<ValidationResult> Validate(T entity)
{
var validationResults = new List<ValidationResult>();
var validationContext = new ValidationContext(entity, null, null);
Validator.TryValidateObject(entity, validationContext, validationResults, true);
return validationResults;
}
}

The only function that Attribute can handle is describe, provide some descriptive data with member. They are purely passive and can't contain any logic. (There are some AOP frameworks that can make attributes active). So if you want logic you have to create another class that will read attributes using MemberInfo.GetCustomAttributes and do the validation and return results.

Below code shows how to determine validation for only properties and give idea validation for methods ,classes etc.
public class DataValidator
{
public class ErrorInfo
{
public ErrorInfo(string property, string message)
{
this.Property = property;
this.Message = message;
}
public string Message;
public string Property;
}
public static IEnumerable<ErrorInfo> Validate(object instance)
{
return from prop in instance.GetType().GetProperties()
from attribute in prop.GetCustomAttributes(typeof(ValidationAttribute), true).OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(instance, null))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty));
}
}
After adding this code to project we can use it like:
var errors =DataValidator.Validate(person);
foreach (var item in errors)
{
Console.WriteLine(item.Property +" " + item.Message);
}

Related

apply runtime metadatatype for validation

I need to have different validation for the same object. So I thought to use Metadatatype to define the different rules the code is below:
public class ValidateObjectAttribute : ValidationAttribute
{
private readonly Type _validationMetaDataType;
public ValidateObjectAttribute(Type validationMetaDataType)
{
_validationMetaDataType = validationMetaDataType;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var modelType = value.GetType();
AssociatedMetadataTypeTypeDescriptionProvider associatedMetadataTypeTypeDescriptionProvider = null;
if (_validationMetaDataType != null)
{
associatedMetadataTypeTypeDescriptionProvider = new AssociatedMetadataTypeTypeDescriptionProvider(modelType, _validationMetaDataType);
TypeDescriptor.AddProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
}
var validationctx = new ValidationContext(value);
var results = new List<ValidationResult>();
Validator.TryValidateObject(value, validationctx, results, true);
if (associatedMetadataTypeTypeDescriptionProvider != null)
{
TypeDescriptor.RemoveProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
TypeDescriptor.Refresh(value);
}
if (results.Count == 0) return ValidationResult.Success;
return new ValidationResult($"Validation fail for prop: {validationContext.DisplayName}");
}
}
public class BarMetaData1
{
[Required]
public string BarField1;
[Required]
public string BarField2;
}
public class FooMetaData1
{
[Required]
public string FooField1;
[Required]
public string FooField2;
[Required, ValidateObject(typeof(BarMetaData1))]
public Bar FooObject1;
}
public class FooMetaData2
{
public string FooField1;
[Required]
public string FooField2;
[Required, ValidateObject(typeof(BarMetaData1))]
public Bar FooObject1;
}
public class BaseValidation
{
public bool IsValid(Type validationMetaDataType)
{
var modelType = this.GetType();
AssociatedMetadataTypeTypeDescriptionProvider associatedMetadataTypeTypeDescriptionProvider = null;
if (validationMetaDataType != null)
{
associatedMetadataTypeTypeDescriptionProvider = new AssociatedMetadataTypeTypeDescriptionProvider(modelType, validationMetaDataType);
TypeDescriptor.AddProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
TypeDescriptor.Refresh(this);
}
var validationctx = new ValidationContext(this);
var results = new List<ValidationResult>();
Validator.TryValidateObject(this, validationctx, results, true);
if (associatedMetadataTypeTypeDescriptionProvider != null)
{
TypeDescriptor.RemoveProvider(associatedMetadataTypeTypeDescriptionProvider, modelType);
}
return results.Count == 0;
}
}
public class Foo : BaseValidation
{
public string FooField1 { get; set; }
public string FooField2 { get; set; }
public Bar FooObject1 { get; set; }
}
public class Bar
{
public string BarField1 { get; set; }
public string BarField2 { get; set; }
}
the validation is call in this way:
public void Index()
{
Foo fooInstance = new Foo()
{
FooObject1 = new Bar()
};
fooInstance.IsValid(typeof(FooMetaData2));
fooInstance.IsValid(typeof(FooMetaData1));
Foo fooInstance2 = new Foo()
{
FooObject1 = new Bar()
};
fooInstance2.IsValid(typeof(FooMetaData2));
}
What is the issue:
first validation [fooInstance.IsValid(typeof(FooMetaData2))] is right (2 mandatory fields missing),
second validation call [fooInstance.IsValid(typeof(FooMetaData1))] the result is wrong (3 mandatory field missing but the code notify me only 2), it seems that the code apply the validation describe in FooMetaData2 class instead of FooMetaData1
Someone can explain to me why?
thanks
I solved using fluentValidator plugin

How to set value of a property that is a class in C#

I am trying to set the value of a property that is a class.
protected bool TryUpdate(PropertyInfo prop, object value)
{
try
{
prop.SetValue(this, value);
// If not set probably a complex type
if (value != prop.GetValue(this))
{
//... Don't know what to do
}
// If still not set update failed
if (value != prop.GetValue(this))
{
return false;
}
return true;
}
}
I'm calling this method on a number of properties from a variety of classes. This issue is when I have a class like the following:
public class Test
{
public string Name { get; set; }
public string Number { get; set; }
public IComplexObject Object { get; set; }
}
Name and Number are set just fine, but if I try and set an instance of a class that inherits from IComplexObject on Object there is no errors it just remains null.
Is there an easy way to set an instance of a class as property?
So for example if I pass in prop as {IComplexObject Object} and object as
var object = (object) new ComplexObject
{
prop1 = "Property"
prop2 = "OtherProperty"
}
At the end there are no errors but Object remains null and is not set to the instance of ComplexObject. It needs to be generic so I can pass in any class and the property will be updated.
This example works. I've put it for a reference.
I've changed it to await the task and extract the return value to the result variable so you could see that it returns true.
public class Test
{
public string Name { get; set; }
public string Number { get; set; }
public IComplexObject Object { get; set; }
public async Task<bool> TryUpdate(PropertyInfo prop, object value) {
try {
prop.SetValue(this, value);
return true;
}
catch (Exception) {
}
return false;
}
}
public class ComplexObject : IComplexObject
{
}
public interface IComplexObject
{
}
static class Program
{
static void Main() {
TestMethod();
}
static async void TestMethod() {
var test = new Test();
var result = await test.TryUpdate(test.GetType().GetProperty("Object"), new ComplexObject());
}
}
Your code is needlessly complicated, but it works completely fine. I've taken your code and expanded it into a complete example that runs.
The output is this.
Name: asdf, Number: A1B2, Object: hello this is complexobject
It was not null
This shows that the Object property is no different from any of the others. "Complex object" is not a term that really means anything in .net. Additionally your use of async seems unnecessary and confusing.
async void Main() {
Test t = new Test();
Type type = typeof(Test);
await t.TryUpdate(type.GetProperty(nameof(t.Name)), "asdf");
await t.TryUpdate(type.GetProperty(nameof(t.Number)), "A1B2");
await t.TryUpdate(type.GetProperty(nameof(t.Object)), (object)new ComplexObject());
Console.WriteLine(t.ToString());
PropertyInfo prop = type.GetProperty(nameof(t.Object));
if (prop.GetValue(t) == null) {
Console.WriteLine("It was null");
} else {
Console.WriteLine("It was not null");
}
}
public class Test {
public string Name { get; set; }
public string Number { get; set; }
public IComplexObject Object { get; set; }
// Added for the purpose if showing contents
public override string ToString() => $"Name: {Name}, Number: {Number}, Object: {Object}";
// Why is this async? Your code does not await
public async Task<bool> TryUpdate(PropertyInfo prop, object value) {
await Task.Delay(0); // Added to satisfy async
try {
prop.SetValue(this, value);
// If not set probably a complex type
if (value != prop.GetValue(this)) {
//... Don't know what to do
}
return true;
}
catch {
return false;
}
}
}
public interface IComplexObject { }
class ComplexObject : IComplexObject {
public override string ToString() => "hello this is complexobject";
}

How to lazy load a property with custom attribute

I want to create a custom attribute using Glass Mapper for getting the Sitecore URL, because it is not possible to lazy load a property with SitecoreInfo(SitecoreInfoType.Url) and we have some performance issues loading URL of mapped items, where the URL will never be used.
Here is what I've got so far:
The Configuration
public class SitecoreUrlConfiguration : AbstractPropertyConfiguration
{
public SitecoreInfoUrlOptions UrlOptions { get; set; }
public bool IsLazy { get; set; }
}
The Attribute
public class SitecoreUrlAttribute : AbstractPropertyAttribute
{
public SitecoreUrlAttribute()
{
this.IsLazy = true;
this.UrlOptions = SitecoreInfoUrlOptions.Default;
}
/// <summary>
/// Gets or sets a value indicating whether is lazy.
/// </summary>
public bool IsLazy { get; set; }
public SitecoreInfoUrlOptions UrlOptions { get; set; }
public override AbstractPropertyConfiguration Configure(PropertyInfo propertyInfo)
{
var config = new SitecoreUrlConfiguration();
this.Configure(propertyInfo, config);
return config;
}
public void Configure(PropertyInfo propertyInfo, SitecoreUrlConfiguration config)
{
config.UrlOptions = this.UrlOptions;
config.IsLazy = this.IsLazy;
base.Configure(propertyInfo, config);
}
}
The Mapper
public class SitecoreUrlMapper : AbstractDataMapper
{
public override object MapToProperty(AbstractDataMappingContext mappingContext)
{
var context = mappingContext as SitecoreDataMappingContext;
if (context == null)
{
throw new MapperException("Mapping Context is null");
}
var item = context.Item;
var scConfig = this.Configuration as SitecoreUrlConfiguration;
if (scConfig == null)
{
throw new MapperException("SitecoreUrlConfiguration is null");
}
var urlOptions = Utilities.CreateUrlOptions(scConfig.UrlOptions);
urlOptions.Language = null;
// now, what?
}
}
So far, so good. But how can I lazy load the URL in the mapper? Does anyone have an idea?
The only way I actually see is to map a Lazy<T> and add a new property to the class which returns the value of this when accessing it. So in you mapper, where you put // now what? I would return the lazy string:
return new Lazy<string>(() => LinkManager.GetItemUrl(item, urlOptions));
Then in your model, put these two properties:
[SitecoreUrl]
public Lazy<string> LazyUrl { private get; set; }
[SitecoreIgnore]
public virtual string Url
{
get
{
return this.LazyUrl.Value;
}
}
You can achieve pretty similar to this with a bit of creativity and the new Delegate functionality
In the fluent configuration map the type like so:
SitecoreType<IWhatever> sitecoreType = new SitecoreType<IWhatever>();
sitecoreType.Delegate(y => y.Url).GetValue(GetLazyUrl);
private LazyString GetLazyUrl(SitecoreDataMappingContext arg)
{
var item = context.Item;
return new LazyString(
() =>
{
// the necessary actions to get the url
});
}
public class LazyString : Lazy<string>
{
public LazyString(Func<string> valueFactory) : base(valueFactory)
{
}
public override string ToString()
{
return Value;
}
public static implicit operator string(LazyString lazyString)
{
return lazyString.Value;
}
}
It's not a string, but for the purposes of many applications, will behave like one.

Get custom attribute from specific object property/field

I've been searching for a while now and tested several methods, but i didn't find the answer i was looking for. I'll try to explain.
I have an object with several fields/properties. These properties have custom attributes.
What i want is to get the custom attribute from a specific propertie without all the knowlege of the object.
The are the base classes
// FieldAttr has a public Text propery
public class TestObject
{
// Declare fields
[FieldAttr("prop_testfld1")]
public FLDtype1 testfld1 = new FLDtype1();
[FieldAttr("prop_testfld2")]
public FLDtype2 testfld2 = new FLDtype2();
[FieldAttr("prop_testfld3")]
public FLDtype1 testfld3;
}
public class FLDtype1
{
public string Value { get; set; }
}
public class FLDtype2
{
public Guid Value { get; set; }
}
public sealed class FieldAttr: System.Attribute
{
private string _txt;
public EntityFieldType(string txt)
{
this._text = txt;
}
public string Text { get { return this._text; } }
}
And i want to be able to do this in my application:
static void Main(string[] args)
{
TestObject test = new TestObject();
// (Option 1: preferred)
Console.WriteLine(test.testfld1.getFieldAttr().Text);
// (Option 2)
Console.WriteLine(test.getFieldAttr(test.testfld1).Text);
}
Is this possible? I've seen methods to get custom attribute values from all properties/fields of an object, but not for a specific field.
I've got a working method to get custom attribute from an enum, but wasn't able to recreate it for object fields/properties. This is because i couldn't get the name of the field i was trying to explore, because (for example) test.testfld1.ToString() give's me "ns.FLDtype1".
Looking forward for the answer :)
(and excuse my english)
Yes it is possible:
public static class Extensions
{
public static FieldAttr GetFieldAttr(
this TestObject source,
Expression<Func<TestObject,object>> field)
{
var member = field.Body as MemberExpression;
if (member == null) return null; // or throw exception
var fieldName = member.Member.Name;
var test = typeof (TestObject);
var fieldType = test.GetField(fieldName);
if (fieldType != null)
{
var attribute = fieldType.GetCustomAttribute<FieldAttr>();
return attribute;
}
return null;
}
}
Usage:
TestObject test = new TestObject();
var attr = test.GetFieldAttr(x => x.testfld3);
if(attr != null) Console.WriteLine(attr.Text);
Here is the fiddle
After another day of trial and error I decided to make use of Selman22 answer with a little modification. This is code I created:
public class TestObject : iTestObject
{
// Declare fields
[FieldAttr("prop_testfld1")]
public FLDtype1 testfld1 = new FLDtype1();
[FieldAttr("prop_testfld2")]
public FLDtype2 testfld2 = new FLDtype2();
[FieldAttr("prop_testfld3")]
public FLDtype1 testfld3;
}
public class FLDtype1 : iField
{
public string Value { get; set; }
}
public class FLDtype2 : iField
{
public Guid Value { get; set; }
}
public sealed class FieldAttr: System.Attribute
{
private string _txt;
public FieldAttr(string txt)
{
this._txt = txt;
}
public string Text { get { return this._txt; } }
}
public interface iField { }
public interface iTestObject { }
public static class Extensions
{
public static FieldAttr GetFieldAttr<T>(this T source, Expression<Func<iField>> field) where T : iTestObject
{
// Get member body. If no body present, return null
MemberExpression member = (MemberExpression)field.Body;
if (member == null) { return null; }
// Get field info. If no field info present, return null
FieldInfo fieldType = typeof(T).GetField(member.Member.Name);
if (fieldType == null) { return null; }
// Return custom attribute
return fieldType.GetCustomAttribute<FieldAttr>();
}
}
Usage:
public class Program
{
public static void Main()
{
TestObject test = new TestObject();
Console.WriteLine(test.GetFieldAttr(() => test.testfld1).Text);
Console.WriteLine(test.GetFieldAttr(() => test.testfld2).Text);
Console.WriteLine(test.GetFieldAttr(() => test.testfld3).Text);
}
}
Uses:
using System;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;
I have implemented interfaces to protect the GetFieldAttr method
#Sulman22: Thnx for the response!

Access to Attributes using a String

Given a string with the same name of an object field, how can I get the reference to the object field?
For example, say I pass in a string called "field1" to the GetFieldByStr method, and the object has an field name field1, how can I get a reference to the field1 object? I'm assuming using reflection somehow.
class Example {
private FieldExample attr1;
void GetFieldByStr(String str) {
// We get passed in "field1" as a string, now I want
// to get the field1 attribute.
}
}
You need to use Reflection:
FieldInfo field = typeof(Example).GetField(str);
object value = field.GetValue(this);
(For properties, use PropertyInfo)
Note that value is an object; in order to do anything useful with it, you'll need to cast it to some class or interface (or use dynamic in C# 4).
Here's an idea that doesn't rely on reflection. The downside is that it requires some setup. You could possibly even define some custom attributes and use some clever code to perform the setup automatically on application start.
interface IAttributeStore
{
T GetAttribute<T>(string key);
}
class Example : IAttributeStore
{
public int ExampleID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
static Dictionary<string, Delegate> _AttributeAccessors;
static Example()
{
_AttributeAccessors = new Dictionary<string, Delegate>();
_AttributeAccessors.Add("ExampleID", new Func<Example, int>((example) => example.ExampleID));
_AttributeAccessors.Add("FirstName", new Func<Example, string>((example) => example.FirstName));
_AttributeAccessors.Add("LastName", new Func<Example, string>((example) => example.LastName));
}
#region IAttributeStore Members
public T GetAttribute<T>(string key)
{
Delegate accessor;
if (_AttributeAccessors.TryGetValue(key, out accessor))
{
Func<Example, T> func = accessor as Func<Example, T>;
if (func != null)
return func(this);
else
throw new Exception(string.Format("The attribute with the given key \"{0}\" is not of type [{1}].", key, typeof(T).FullName));
}
else
{
throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\".", key), "key");
}
}
#endregion
}
class Program
{
static void Main(string[] args)
{
Example example = new Example() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };
Console.WriteLine(example.GetAttribute<int>("ExampleID"));
Console.WriteLine(example.GetAttribute<string>("FirstName"));
Console.WriteLine(example.GetAttribute<string>("LastName"));
}
}
Update: This seemed interesting to me, so I threw together an alternative implementation that utilizes attributes and extension methods instead of an interface. The nice thing about this is that it requires very little code per class (you just need to add the attributes), and the code that sets up the delegates only runs if the application actually requests an attribute from a particular class.
I have to give credit to Marc Gravell's answer to this question for how to dynamically create a delegate for getting a property given a PropertyInfo object.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
class AttributeStoreAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
class StoredAttributeAttribute : Attribute
{
public string Key { get; set; }
}
public static class AttributeStore<T>
{
static Dictionary<string, Delegate> _AttributeAccessors;
public static void Initialize()
{
_AttributeAccessors = new Dictionary<string, Delegate>();
Type type = typeof(T);
// let's keep it simple and just do properties for now
foreach (var property in type.GetProperties())
{
var attributes = property.GetCustomAttributes(typeof(StoredAttributeAttribute), true);
if (attributes != null && attributes.Length > 0)
{
foreach (object objAttribute in attributes)
{
StoredAttributeAttribute attribute = objAttribute as StoredAttributeAttribute;
if (attribute != null)
{
string key = attribute.Key;
// use the property name by default
if (string.IsNullOrEmpty(key))
key = property.Name;
if (_AttributeAccessors.ContainsKey(key))
throw new Exception(string.Format("An attribute accessor has already been defined for the given key \"{0}\".", key));
Type typeOfFunc = typeof(Func<,>).MakeGenericType(type, property.PropertyType);
Delegate accessor = Delegate.CreateDelegate(typeOfFunc, null, property.GetGetMethod());
_AttributeAccessors.Add(key, accessor);
}
}
}
}
}
public static object GetAttribute(T store, string key)
{
if (_AttributeAccessors == null)
Initialize();
Delegate accessor;
if (_AttributeAccessors.TryGetValue(key, out accessor))
{
return accessor.DynamicInvoke(store);
}
else
{
throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\" on attribute store [{1}].", key, typeof(T).FullName), "key");
}
}
public static TResult GetAttribute<TResult>(T store, string key)
{
if (_AttributeAccessors == null)
Initialize();
Delegate accessor;
if (_AttributeAccessors.TryGetValue(key, out accessor))
{
Func<T, TResult> func = accessor as Func<T, TResult>;
if (func != null)
return func(store);
else
throw new Exception(string.Format("The attribute with the given key \"{0}\" on attribute store [{1}] is not of type [{2}].", key, typeof(T).FullName, typeof(TResult).FullName));
}
else
{
throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\" on attribute store [{1}].", key, typeof(T).FullName), "key");
}
}
}
public static class AttributeStoreExtensions
{
public static object GetAttribute<T>(this T store, string key)
{
return AttributeStore<T>.GetAttribute(store, key);
}
public static TResult GetAttribute<T, TResult>(this T store, string key)
{
return AttributeStore<T>.GetAttribute<TResult>(store, key);
}
}
[AttributeStore]
class Example
{
[StoredAttribute]
public int ExampleID { get; set; }
[StoredAttribute]
public string FirstName { get; set; }
[StoredAttribute]
public string LastName { get; set; }
}
[AttributeStore]
class Example2
{
[StoredAttribute]
[StoredAttribute(Key = "ID")]
public int ExampleID { get; set; }
[StoredAttribute]
[StoredAttribute(Key = "First")]
public string FirstName { get; set; }
[StoredAttribute]
[StoredAttribute(Key = "Last")]
public string LastName { get; set; }
}
class Program
{
static void Main(string[] args)
{
Example example = new Example() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };
Console.WriteLine(example.GetAttribute("ExampleID"));
Console.WriteLine(example.GetAttribute("FirstName"));
Console.WriteLine(example.GetAttribute("LastName"));
Example2 example2 = new Example2() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };
// access attributes by the default key (property name)
Console.WriteLine(example2.GetAttribute("ExampleID"));
Console.WriteLine(example2.GetAttribute("FirstName"));
Console.WriteLine(example2.GetAttribute("LastName"));
// access attributes by the explicitly specified key
Console.WriteLine(example2.GetAttribute("ID"));
Console.WriteLine(example2.GetAttribute("First"));
Console.WriteLine(example2.GetAttribute("Last"));
}
}
You can do so with the Reflection library (either FieldInfo or PropertyInfo depending if you want a field or a property)
Example:
void GetAttributesByStr(String str) {
FieldInfo attributeInfo = this.GetType().GetField(str); // you might want to use some Binding flags here like BindingFlags.Instance and BindingFlags.Public
attributeInfo.GetValue(this); // assign this to something or return it as an object
}
For properties.
var prop = this.GetType().GetProperty(str);
prop.GetValue(prop, null);

Categories