My code below:
foreach (var PI in ObjType.GetProperties())
{
var metaData = ModelMetadataProviders.Current.GetMetadataForType(null, PI.GetType());
string DispName = metaData.DisplayName
}
ObjType is the type of an EF6 schema first entity with DisplayName been added as a Metadata class. The error above is probably because PI.GetType() returns the type of the PropertyInfo. But I really can't figure out how to get the property itself.
I have look into various example using:
ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
However, in my case, I am not using any Lambda Expression. I just need to construct a list of the properties' DisplayName and pass it on.
But I really can't figure out how to get the property itself.
You want PropertyInfo.PropertyType, so change PI.GetType() to PI.PropertyType.
I don't know if this will help you, but this is how i got the MetaDataClassType from the object it has been attached to.
Example Class with a MetadataType:
[MetadataType(typeof(TheMetaDataYouWantTheTypeFrom))]
public class ObjectYouWantMetaDataTypeFrom
{
public string Username { get; set; }
public string Name { get; set; }
}
public class TheMetaDataYouWantTheTypeFrom
{
[Required(ErrorMessage = "You must enter a username.")]
public object Username { get; set; }
[Required(ErrorMessage = "You must enter a name.")]
public object Name { get; set; }
}
The Code to get the MetadataClassType
Type ObjectType = ObjectYouWantMetaDataTypeFrom.GetType();
object ObjectMetaData = ObjectType.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
MetadataTypeAttribute MetaData = ObjectMetaData as MetadataTypeAttribute;
if (MetaData == null)
{ throw new NullReferenceException(); }
Type metadataClassType = MetaData.MetadataClassType;
Related
I used to get one name for one property, but now I get data with two names for one property. That is, it was ServiceName ->ServiceName, and it became ServiceName ->ServiceName, Name.
value assignment code:
PropertyInfo property = item.GetType().GetProperty(column.Caption);
var range = worksheet.Cell(i, listIndex[indexForList]);
if (range == null)
{
continue;
}
var value = ChangeType((object)range.Value, property.PropertyType);
property.SetValue(item, value);
I have a model:
public class ImportAdditionalService
{
public string ServiceName { get; set; }
public decimal? Price { get; set; }
}
Are there any attributes in this case for class properties, so that I can use reflection for two names?
I am using C# 4.5 and ASP.NET MVC 5.
I have the following:
[Required(ErrorMessage = "Prop1 is required")]
public string Prop1 { get;set;}
[Required(ErrorMessage = "Prop2 is required")]
public string Prop2 { get;set;}
As you see the error message is the property name plus the " is required" string. What I need is instead of typing the property name and the message for every property, use a generic method composer, that will return the name of the decorated property and a string that I add, something like:
public string GetMessage()
{
// Caller property should be a variable that is retrieved dynamically
// that holds the name of the property that called the function
return CallerProperty + " is required";
}
so now I can user:
[Required(ErrorMessage = GetMessage())]
public string Prop2 { get;set;}
so in brief: How can I know the property name that is decorated by an attribute.
Use reflection.
Pseudo
public List<Required> CallerProperty<T>(T source)
{
List<Required> result = new List<Required>();
Type targetInfo = target.GetType();
var propertiesToLoop = source.GetProperties();
foreach (PropertyInfo pi in propertiesToLoop)
{
Required possible = pi.GetCustomAttribute<Required>();
if(possible != null)
{
result.Add(possible);
string name = pi.Name; //This is the property name of the property that has a required attribute
}
}
return result;
}
This is just a demo of how to capture a custom attribute on a property. You have to work out how to manage a list of them, or whatever you need in order to generate the return type you need. Perhaps map it with the "pi.Name" also referenced? I don't know precisely what you need.
You can use the "nameof" expression as follows:
class Class1
{
[CustomAttr("prop Name: " + nameof(MyProperty))]
public int MyProperty { get; set; }
}
public class CustomAttr : Attribute
{
public CustomAttr(string test)
{
}
}
I am going to walk through the properties of items in an ICollection and at Compile Time will not necessarily know what type the items in the ICollection will be. I can get the Property name, but would like to get the DataAnnotation Display Name (if any).
How can I find the Display Name defined in DataAnnotations (if any) of an unknown type at run time?
So far I have this:
foreach (var thisSection in Report.ReportSections)
{
reportBody.Append(thisSection.ReportSectionName + Environment.NewLine);
if (thisSection.ReportItems != null)
{
var itemType = thisSection.ReportItems.GetType().GetGenericArguments().Single();
var first = true;
foreach (var prop in itemType.GetProperties())
{
if (!first) reportBody.Append(",");
// This gives me the property name like 'FirstName'
reportBody.Append(prop.Name);
try
{
// I'd like to get the Display Name from
// [Display(Name = "First Name")]
var displayName = prop.GetCustomAttributes();
}
catch (Exception e)
{
}
first = false;
}
reportBody.Append(Environment.NewLine);
}
}
ReportSection is defined like this:
public interface IReportSection
{
string ReportSectionName { get; }
ICollection ReportItems { get; }
}
The ICollection could contain a collection of objects like this:
public class ProjectAffiliateViewModel
{
public string Role { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
}
For the Role property we would get Role, and for the FirstName property we would get First Name.
Like this:
DisplayAttribute attribute = prop.GetCustomAttributes(typeof(DisplayAttribute), false)
.Cast<DisplayAttribute>()
.SingleOrDefault();
string displayName = (attribute != null) ? attribute.Name : prop.Name;
I have a hard time explaining what I'm exactly trying to do. There's probably a name for it, but I don't know what it is.
First, I have a model such as:
public class Customer
{
public int Id { get; set; }
public int ProductId { get; set; }
...more properties...
public virtual Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
...more properties...
}
Second, I have a string of HTML text with placeholders in {}. I'd like to have something like {Id} and have it replace the Html text with the model properties.
<div><span>Name</span><span>{Id}-{Product.Name}</span></div>
My thought was to use a NameValueCollection to get the Model properties as strings. Using reflection, I can do that for the base properties, but not for something like Product.Name.
Am I going about this the wrong way? What could I use to get a NameValueCollection that I could loop through and do a replace of the Html?
Here is the current code I have (skips virtual properties):
public virtual NameValueCollection GetNameValueCollection(Object obj)
{
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();
var coll = new NameValueCollection();
foreach (PropertyInfo property in properties)
{
if(!property.GetGetMethod().IsVirtual)
{
if (property.PropertyType == typeof(DateTime))
{
var date = (DateTime)property.GetValue(obj, null);
coll.Add(property.Name, date.ToLongDateString());
}
else if (property.PropertyType == typeof(DateTime?))
{
var date = (DateTime?)property.GetValue(obj, null);
if (date.HasValue)
{
coll.Add(property.Name, date.Value.ToLongDateString());
}
else
{
coll.Add(property.Name, string.Empty);
}
}
else
{
var value = property.GetValue(obj, null);
if (value != null)
{
coll.Add(property.Name, value.ToString());
}
}
}
}
return coll;
}
This should be recursive, but it seems like there should be a better way. By the way, I don't need a NameValueCollection specifically (could be Dictionary<string,string> for example). Thoughts? Is there a nuget package that already does this?
I ended up just using what I had and added a sub section for handling child objects. I didn't want to do full recursion since I only wanted the direct child objects, not all the way through the chain.
Take this class for example:
public class Applicant : UniClass<Applicant>
{
[Key]
public int Id { get; set; }
[Field("X.838.APP.SSN")]
public string SSN { get; set; }
[Field("APP.SORT.LAST.NAME")]
public string FirstName { get; set; }
[Field("APP.SORT.FIRST.NAME")]
public string LastName { get; set; }
[Field("X.838.APP.MOST.RECENT.APPL")]
public int MostRecentApplicationId { get; set; }
}
How would I go about getting all of the properties that are decorated with the field attribute, get their types, and then assign a value to them?
This is all done with reflection. Once you have a Type object, you can then get its PropertyInfo with myType.GetProperties(), from there, you can get each property's attributes with GetCustomAttributes(), and from there if you find your attribute, you've got a winner, and then you can proceed to work with it as you please.
You already have the PropertyInfo object, so you can assign to it with PropertyInfo.SetValue(object target, object value, object[] index)
You'll need to use Reflection:
var props =
from prop in typeof(Applicant).GetProperties()
select new {
Property = prop,
Attrs = prop.GetCustomAttributes(typeof(FieldAttribute), false).Cast<FieldAttribute>()
} into propAndAttr
where propAndAttr.Attrs.Any()
select propAndAttr;
You can then iterate through this query to set the values:
foreach (var prop in props) {
var propType = prop.Property.PropertyType;
var valueToSet = GetAValueToSet(); // here's where you do whatever you need to do to determine the value that gets set
prop.Property.SetValue(applicantInstance, valueToSet, null);
}
You would just need to invoke the appropriate reflection methods - try this:
<MyApplicationInstance>.GetType().GetProperties().Where(x => x.GetCustomAttributes().Where(y => (y as FieldAttribute) != null).Count() > 0);