Check if instance of class is annotated with attribute - c#

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.

Related

Get method the attribute is attached to, without looping through every class and method [duplicate]

I have a custom attribute, inside the constructor of my custom attribute I want to set the value of a property of my attribute to the type of the property my attribute was applied to, is there someway to access the member that the attribute was applied to from inside my attribute class?
It's possible from .NET 4.5 using CallerMemberName:
[SomethingCustom]
public string MyProperty { get; set; }
Then your attribute:
[AttributeUsage(AttributeTargets.Property)]
public class SomethingCustomAttribute : Attribute
{
public StartupArgumentAttribute([CallerMemberName] string propName = null)
{
// propName == "MyProperty"
}
}
Attributes don't work that way, I'm afraid. They are merely "markers", attached to objects, but unable to interact with them.
Attributes themselves should usually be devoid of behaviour, simply containing meta-data for the type they are attached to. Any behaviour associated with an attribute should be provided by another class which looks for the presence of the attribute and performs a task.
If you are interested in the type the attribute is applied to, that information will be available at the same time you are reflecting to obtain the attribute.
You can do next. It is simple example.
//target class
public class SomeClass{
[CustomRequired(ErrorMessage = "{0} is required", ProperytName = "DisplayName")]
public string Link { get; set; }
public string DisplayName { get; set; }
}
//custom attribute
public class CustomRequiredAttribute : RequiredAttribute, IClientValidatable
{
public string ProperytName { get; set; }
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var propertyValue = "Value";
var parentMetaData = ModelMetadataProviders.Current
.GetMetadataForProperties(context.Controller.ViewData.Model, context.Controller.ViewData.Model.GetType());
var property = parentMetaData.FirstOrDefault(p => p.PropertyName == ProperytName);
if (property != null)
propertyValue = property.Model.ToString();
yield return new ModelClientValidationRule
{
ErrorMessage = string.Format(ErrorMessage, propertyValue),
ValidationType = "required"
};
}
}

Asp.Net Core Model Validation *Multiple* Attributes

I have a Asp.Net Core REST service and I'm using the built in validation. I needed some additional functionality, so I found some examples of validation attributes that I needed, so here is a small part of my model:
[RequiredIfEmpty("B")]
[RequiredIfEmpty("C")]
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
So, pretty obvious what I'm going for. I want to validate that A is specified if B or C is empty.
When I send a JSON request that will fail validation, I only get:
"A is required when B is empty."
I'm expecting to get:
"A is required when B is empty."
"A is required when C is empty."
So, it seems like the validation code does a distinct on the attributes based on type because it ignores the 2nd one. This is further proven if I do:
[RequiredIfEmpty("B")]
[RequiredIfEmpty2("C")]
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
RequiredIfEmpty2 is just derived from RequiredIfEmpty, no additional code. Now I get the expected:
"A is required when B is empty."
"A is required when C is empty."
In this example, I only have 2 dependent properties, so no biggie to create a 2 version, but its very hacky and I don't like it.
I thought about changing the RequiredIfEmpty attribute to take a string[] of properties, but it doesn't appear like the MVC infrastructure would allow multiple error strings returned by a single attribute.
I did report it to Microsoft, but wondering if anybody else can think of a work-around besides having a 2 version?
.Net Core + .Net Framework
You can override the Equals and GetHashCode methods in the attribute to create distinctions between AllowMultiple attributes.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public sealed class RequiredIfEmptyAttribute : RequiredAttribute
{
private object _instance = new object();
public override bool Equals(object obj) => _instance.Equals(obj);
public override int GetHashCode() => _instance.GetHashCode();
// all the rest of the code
}
.Net Framework Only
If you're only targeting the .Net Framework, you can use the TypeId property to be a unique identifier between two attributes of the same type. (MSDN documentation)
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public sealed class RequiredIfEmptyAttribute : RequiredAttribute
{
public override object TypeId { get; } = new object();
// all the rest of the code
}
I thought about changing the RequiredIfEmpty attribute to take a string[] of properties, but it doesn't appear like the MVC infrastructure would allow multiple error strings returned by a single attribute.
Correct. You cannot return more than one message per attribute. You could implement the IValidatableObject interface to achieve this, however.

Using ServiceStack OrmLite to create Key Value table for dynamic types

I want to create a key value table in my database along the lines of
public class KeyValue {
public string Id { get; set; }
public dynamic Value {get; set; }
}
Using a slightly modified SqlProvider I have no problems getting CreateTable<KeyValue>() to generate varchar(1024) Id, varchar(max) Value.
I have no issues saving objects to it. The problem is when I load the objects
var content = dbConn.GetById<KeyValue>("about");
content.Value at this point is a string.
Looking at the database record, the text for value does not appear to store any type information.
Is there really anything I can do better other than manually invoking ServiceStack.Text and call deserialize with the appropriate type information?
I do not need absolute dynamic, my actual use case is for polymorphism with a base class instead of dynamic. So I don't really care what type Value is whether it's the base class, dynamic, object, etc. Regardless other than using the class
public class KeyValue {
public string Id { get; set; }
public MySpecificChildType Value {get; set; }
}
I haven't been able to get anything other than a string back for Value. Can I tell OrmLite to serialize the type information to be able to correctly deserialize my objects or do I just have to do it manually?
Edit: some further information. OrmLite is using the Jsv serializer defined by ServiceStack.Text.TypeSerializer and is in no way pluggable in the BSD version. If I add a Type property to my KeyValue class with the dynamic Value I can do
var value = content.Value as string;
MySpecificChildType strongType =
TypeSerializer.DeserializeFromString(content, content.Type);
I just really want a better way to do this, I really don't like an object of 1 type going into the db coming back out with a different type (string).
I haven't worked much with the JsvSerializer but with the JsonSerializer you can achieve this (in a few different ways) and as of ServiceStack 4.0.11 you can opt to use the JsonSerializer instead, see https://github.com/ServiceStack/ServiceStack/blob/master/release-notes.md#v4011-release-notes.
Example
public abstract class BaseClass {
//Used for second example of custom type lookup
public abstract string Type { get; set; }
}
public class ChildA : BaseClass {
//Used for second example of custom type lookup
public override string Type { get; set; }
public string PropA { get; set; }
}
And then in your init/bootstrap class you can configure the serializer to emit the type information needed for proper deserialization:
public class Bootstrapper {
public void Init() {
ServiceStack.Text.JsConfig.ExcludeTypeInfo = false;
ServiceStack.Text.JsConfig.IncludeTypeInfo = true;
}
}
If you wish to use something other that the default "__type" attribute that ServiceStack uses (if you for example want to have a friendly name identifying the type rather then namespace/assembly) you can also configure your own custom type lookup as such
public class Bootstrapper {
public void Init() {
ServiceStack.Text.JsConfig.ExcludeTypeInfo = false;
ServiceStack.Text.JsConfig.IncludeTypeInfo = true;
ServiceStack.Text.JsConfig.TypeAttr = "type";
ServiceStack.Text.JsConfig.TypeFinder = type =>
{
if ("CustomTypeName".Equals(type, StringComparison.OrdinalIgnoreCase))
{
return typeof(ChildA);
}
return typeof(BaseClass);
}
}
}

Giving parameters a metatag for reflection

I would like to flag a parameter in such a way that I can read the tag via reflection. The reason I want to do this is because I am creating business layer objects that map to a database and I want to flag certain parameters as 'read-only', such as uniqueidentifier fields that are being generated in the database.
I am already iterating through the properties for filling the parameters. This is a snippet of how I'm assigning values...
foreach (var prop in this.GetType().GetProperties())
{
switch (prop.PropertyType.Name)
{
case "Int32":
int tmpInt = -1;
if (!DBNull.Value.Equals(rowFromDatabase[prop.Name]) && int.TryParse(rowFromDatabase[prop.Name].ToString(), out tmpInt))
{
prop.SetValue(sender, tmpInt);
}
break;
case "Boolean":
bool tmpBool = false;
if (!DBNull.Value.Equals(rowFromDatabase[prop.Name]) && bool.TryParse(rowFromDatabase[prop.Name].ToString(), out tmpBool))
{
prop.SetValue(sender, tmpBool);
}
break;
..............
continued...
..............
}
}
I want to be able to access some kind of metadata on a parameter that is accessible via the prop variable shown above where I can specify some kind of extra information. How can I do this?
EDIT: I'd like to set the metadata like this
[CustomTag]
public Guid ID { get; set; }
Extend the class System.Attribute then decorate your properties with your custom attributes.
For example:
public class ReadOnlyAttribute : System.Attribute
{
}
or
public class DbColumnInfoAttribute : System.Attribute
{
public string ColumnName {get; set; }
public bool Required { get; set; }
public DbColumnInfoAttribute( string name, bool req){
ColumnName = name;
Required = req;
}
}
Then use them:
public class YourClass
{
[ReadOnly]
[DbColumnInfo( "User_Name", true)]
public string UserName { get; set; }
}
To read them via Reflection:
var listOfAttrib = prop.GetCustomAttributes(typeof(MyAttribute), true);
I would recommend that ALL of your attribute classes extend a common class so you can get all custom properties without having to know the exact attribute you're looking for otherwise you'll end up having to fire multiple GetCustomAttributes

Get member to which attribute was applied from inside attribute constructor?

I have a custom attribute, inside the constructor of my custom attribute I want to set the value of a property of my attribute to the type of the property my attribute was applied to, is there someway to access the member that the attribute was applied to from inside my attribute class?
It's possible from .NET 4.5 using CallerMemberName:
[SomethingCustom]
public string MyProperty { get; set; }
Then your attribute:
[AttributeUsage(AttributeTargets.Property)]
public class SomethingCustomAttribute : Attribute
{
public StartupArgumentAttribute([CallerMemberName] string propName = null)
{
// propName == "MyProperty"
}
}
Attributes don't work that way, I'm afraid. They are merely "markers", attached to objects, but unable to interact with them.
Attributes themselves should usually be devoid of behaviour, simply containing meta-data for the type they are attached to. Any behaviour associated with an attribute should be provided by another class which looks for the presence of the attribute and performs a task.
If you are interested in the type the attribute is applied to, that information will be available at the same time you are reflecting to obtain the attribute.
You can do next. It is simple example.
//target class
public class SomeClass{
[CustomRequired(ErrorMessage = "{0} is required", ProperytName = "DisplayName")]
public string Link { get; set; }
public string DisplayName { get; set; }
}
//custom attribute
public class CustomRequiredAttribute : RequiredAttribute, IClientValidatable
{
public string ProperytName { get; set; }
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var propertyValue = "Value";
var parentMetaData = ModelMetadataProviders.Current
.GetMetadataForProperties(context.Controller.ViewData.Model, context.Controller.ViewData.Model.GetType());
var property = parentMetaData.FirstOrDefault(p => p.PropertyName == ProperytName);
if (property != null)
propertyValue = property.Model.ToString();
yield return new ModelClientValidationRule
{
ErrorMessage = string.Format(ErrorMessage, propertyValue),
ValidationType = "required"
};
}
}

Categories