I am using this library to map my Entity objects as Graphs:
https://github.com/SimonCropp/GraphQL.EntityFramework
I know if I manually create a field I can add a description, like so:
AddNavigationField(
name: "mainAddress",
description: "Main Address",
resolve: x => x.Source.MainAddress);
Is there a way to add descriptions to fields that were created using AutoMap()? Preference would be through annotations on the Entity object's properties, but I'd be interested in any method of doing this. Main reason is to add a pretty name to each field for display on a web interface, rather than displaying the camel cased name, so if there's a better way than using description I'd also be interested in that.
Related
I have inherited a project that uses AutoMapper and the AutoMapper.Attributes NuGet package. In the ViewModels the [MapsFrom...] Attributes were placed on properties to identify the mapping from the source property. Recently we re-architected the application, separating the Data Models into a separate C# library (they had all been located within the Website project), unfortunately AutoMapper.Attributes has a known bug where this breaks the [MapsFrom...] and related Attributes (they are ignored causing the properties in the ViewModel to end up Null).
The AutoMapper.Attributes project has officially been abandoned and the owner no longer recommends its use meaning this bug will never be fixed, you can read about it here: https://github.com/schneidenbach/AutoMapper.Attributes/issues/26
That being said, we have a block of code that takes in a ViewModel Type, inspected the Custom Attributes on that type looking for the [MapsFrom...], and uses this to determine the Source Type for that ViewModel. We don't know the Source Type at runtime and need to determine, from the AutoMapper Mappings, what the Source Type of the object is (i.e. the Entity Framework DbSet that is set as the Source, via the CreateMap(...). This has proven elusive to solve, after much research i'm turning to you guys for help on this.
What I Have:
Here is what the method currently looks like, obviously this will no longer work as we have had to remove the [MapsFrom....] attributes:
internal static Type GetSourceType(Type viewModelType)
{
if (!(viewModelType.GetCustomAttributes(typeof(MapsFromAttribute), true).FirstOrDefault() is MapsFromAttribute mapsFromAttribute))
{
throw new Exception("The view model class named " + $"{viewModelType.Name} is not decorated with MapsFrom attribute");
}
var destinationType = mapsFromAttribute.SourceType;
return destinationType;
}
What I need:
I need to modify the method above so that when a ViewModel Type is passed into the method I can extract the source Type thats mapped to that ViewModel. Lets see an example, if we had the Mapping below:
CreateMap<User, UserViewModel>();
When a UserViewModel is passed into the method I need to determine that its source Type is User (which just so happens to also be an EntityFramework DbSet but that doesn't really matter in terms of this discussion).
The FindTypeMapFor method (shown below) won't help because you have to provide it with the Source Entity, which is exactly what I'm trying to discover.
TypeMap typeMap = AutoMapper.Mapper.Instance.ConfigurationProvider.FindTypeMapFor(TDto, TEntity>();
PLEASE NOTE: We are using AutoMapper version 8.0, we have all of our CreateMap(...) statements in Profile classes, we are NOT using Attributes anymore.
Background
My ASP.NET MVC application allows users to create custom reports and select things like fields to display, order of fields etc. A View should be able to read those custom report configurations and display the model fields accordingly.
Example
1) Let's say we have a model called Person - Id, Name, Age, Address, Height.
2) Let's say the custom report configuration is in a model called CustomReportConfig - Shows only Age, Name and height (in that order).
Now, what should happen in the View is something like (assuming there exists a ViewModel that contains both Person and CustomReportConfig)
foreach(string fieldName in #model.ViewModel.CustomReportConfig)
#model.ViewModel.Person.**fieldName**
As you notice, the fieldName part in the above code is a string variable but in Views this should be statically typed.
Question
Is it possible to use a variable for the fieldName part in #model.Person.fieldName in the above code?
Note: I understand that this can be done by if else conditions for each field or reflection or creating a generic DataTable type of object in ViewModel etc but I'm wondering it there's a better way to do it by just creating the the fieldName in #model.Person.fieldName programmatically.
Perhaps keep a list of fields / property names, and use reflection to grab the property?
Probably a neater way to do it would be to keep a list of objects that each implement some interface, and then just loop over the list.
foreach (IMyCustomInterface obj in #model.ViewModel.CollectionOfCustomReportConfigs)
#obj.ToRenderedString()
I Use ArangoDB Graph Database with ArangoDB-NET(C# Driver).
how can I map properties of c# object to attributes of ArangoDB?
more than any thing, I need to mapping when I insert a document, because of the ArangoDB's id create according of this pattern : "CollectionName/_key"
ArangoDB's id= _key(attribute) <================> C#' id= Id(property)
any one can help me?
thanks a lot
You can try to use AliasField attribute which should map specified field to property. Dummy entity in unit tests uses this attribute to map lower case version of properties.
One of the key features of a project I'm working on is the ability for the user to configure Forms (as in "Forms" to fill-up) based on a pool of pre-existing field types (well known types, for instance "user name", "date of birth" etc. but also "generic types" like "string", "DateTime" etc.).
We used to have a static ViewModel that worked fine for the "well known" types and looked like this:
public class UserInputModel
{
[StringLength(200)]
public string Name { get; set; }
[Required(ErrorMessageResourceName = "BirthDateEmptyError", ErrorMessageResourceType = typeof(Resources.ErrorMessages))]
public DateTime BirthDate { get; set; }
//Here comes a lot of other properties
}
All the known properties were listed and we were showing or hiding them given the context.
But the last requirement came and changed all that. The user shall now be able to add as many generic type fields as he wants. In order to do this, we decided to make this InputModel entirely dynamic. It now looks like this:
public class UserInputModel
{
// Each ModelProperty has an "Id" and a "Value" property
public ICollection<ModelProperty> Properties { get; set; }
}
This works like a charm. The razor view only has to iterates over the collection, create the corresponding controls for each property of the collection in a more than standard way:
#Html.TextBoxFor(m => m.Properties[index].Value);
... and we nicely get the data back as a filled form.
=> This works fine, but we don't have any client-side validation. For this, we would need some Metadata... which we don't have via annotations anymore since we're dynamically creating the model.
In order to provide those MetaData, I created a CustomModelMetadataProvider that inherits from DataAnnotationsModelMetadataProvider and registered it as the new ModelMetadataProvider in the Global.asax. The CreateMetadata() function gets called upon creation of the ViewModel, and that for each of the properties of my ViewModel... sofar so good.
Where the problem starts: in order to add some metadata to the current property, I first need to identify which property I am currently looking at ("Name" has a maxlength of 200, "date of birth" hasn't so I cannot assign a maxlength to every property per default). And somewhow I didn't manage to do that yet since all the properties have the same name Value and the same container type ModelProperty.
I tried accessing the container of the property via reflection, but since the ModelAccessor's target is the ViewModel itself (because of the lambda expression m => m.Properties), the following construct gives me the ViewModel as a whole, not just the ModelProperty:
var container = modelAccessor.Target.GetType().GetField("container");
var containerObject = (UserInputModel)container.GetValue(modelAccessor.Target);
I've been flipping this over and over but cannot find a way to identify which ModelProperty I have in hand. Is there a way to do this?
Update: after flipping this in every possible direction for a while, we finally went another way. We are basically using unobstrusive javascript to use MVC's validation capabilities without touching attributes nor metadata. In short, we add HTML attributes like value-data="true" (and all other required attributes) to the #Html.TextBoxFor() statements. This works wonderfully for all the atomic validations (required, stringlength etc.).
Tim, you can leverage what appears to be client-side validation through Ajax with the Remote attribute on your properties.
Basically, you'll need to set up a validation controller and then write some smarts into that controller. But at least you'd be able to write some helper methods and keep it all in one place. You would have a series of validators, based on the meta data that you are presenting to the end users, and each validator method would work for a particular type with good re-use.
The one pitfall to this approach would be that you would need to write a validation method for each type and condition that you want to support. Sounds like you're having to go down that road anyways, though.
Hope this helps.
See if this article help you: Technique for carrying metadata to View Models with AutoMapper.
Also use this one for ideas (custom model metadata provider): changing viewmodel's MetadataType attribute at runtime
Fluent validation is probably the best option for you in my mind, but its obviously up to you to select the best match among those above.
Update
Try use ModelMetadata and override ModelMetadataProvider: Dive Deep Into MVC: ModelMetadata and ModelMetadataProvider. This way you completely customize your model metadata (this replaces data annotations) and you have complete control on what is happening, rather than relying on ASP.NET MVC.
Another good place to look at it is Creating your own ModelMetadataProvider to handle custom attributes.
Hope this all is of help to you.
I really don't know much about attributes in general in C#, I've seen them in use in a lot of different ways/places but I don't think I see the importance of some of them. Some definitely have importance because they provide a noticeable function, such as [Serializable]. Yet, others don't seem so important, such as one my coworker uses to mark properties with [DataMember].
I suppose my question is, what are attributes and how are they useful? Is there a way to create my own attributes and how can I tell if fields/methods/classes/whatever have particular attributes or what values are set in those attributes?
what are attributes?
Attributes enable you to embed information about a type or method in the metadata which describes that type or method.
You typically want to use attributes to describe facts about the mechanism of the type or method rather than the meaning of the type or method. For example, suppose you have a type Employee. A fact about the meaning of Employee is that it is a kind of Person, that an Employee has a Manager, and so on. A fact about the mechanism of Employee is that it can be the target of data binding, or it can be serialized to disk, or whatever. An employee cannot be serialized to disk, but the class Employee can be. Attributes let you separate information about the technical details from the semantic model.
Is there a way to create my own attributes?
Yes. Create a class which extends Attribute. By convention you want to name it "FooAttribute". If you do so you can use either the [Foo] syntax or the [FooAttribute] syntax at your discretion.
How can I tell if fields/methods/classes/whatever have particular attributes or what values are set in those attributes?
Use the GetCustomAttributes method on the reflection objects.
Where should I read for more information?
Start with the attributes tutorial:
http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx
And then read all of chapter 17 of the C# specification.
Attributes are a means by which you can associate metadata with types in .NET. This allows you to check for a type and get information about it that's separate from the "runtime" information of the type.
This can be very useful. You mentioned [Serializable], but other simple examples include many of the System.ComponentModel types, such as Description, which is used by the property grid to "describe" properties when you work with them in the designer. Since the "description" of a property isn't really related to the behavior of the type in a program (at runtime), it doesn't belong in the class. However, it's very handy when you go to edit a control in a visual designer, for example, to see a description (or category, etc) of a property. Attributes are the means by which this is handled.
I think the answer to the following question will provide you some insight to your questions.
How do attribute classes work?
Here is a repost of the answer I provided.
Attributes are essentially meta data that can be attached to various pieces of your code. This meta data can then be interogate and affect the behaviour of certain opperations.
Attributes can be applied to almost every aspect of your code. For example, attributes can be associated at the Assembly level, like the AssemblyVersion and AssemblyFileVersion attributes, which govern the version numbers associated with the assembly.
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Then the Serializable attribute for example can be applied to a type declaration to flag the type as supporting serialization. In fact this attribute has special meaning within the CLR and is actually stored as a special directive directly on the type in the IL, this is optimized to be stored as a bit flag which can be processed much more efficiently, there are a few attributes on this nature, which are known as pseudo custom attributes.
Still other attributes can be applied to methods, properties, fields, enums, return values etc. You can get an idea of the possible targets an attribute can be applied to by looking at this link
http://msdn.microsoft.com/en-us/library/system.attributetargets(VS.90).aspx
Further to this, you can define your own custom attributes which can then be applied to the applicable targets that your attributes are intended for. Then at runtime your code could reflect on the values contained in the custom attributes and take appropriate actions.
For a rather naive example, and this is just for the sake of example :)
You might want to write a persistence engine that will automatically map Classes to tables in your database and map the properties of the Class to table columns. You could start with defining two custom attributes
TableMappingAttribute
ColumnMappingAttribute
Which you can then apply to your classes, as an example we have a Person class
[TableMapping("People")]
public class Person
{
[ColumnMapping("fname")]
public string FirstName {get; set;}
[ColumnMapping("lname")]
public string LastName {get; set;}
}
When this compiles, other than the fact that the compiler emits the additional meta data defined by the custom attributes, little else is impacted. However you can now write a PersistanceManager that can dynamically inspect the attributes of an instance of the Person class and insert the data into the People table, mapping the data in the FirstName property to the fname column and the LastName property to the lname column.
As to your question regarding the instances of the attributes, the instance of the attribute is not created for each instance of your Class. All instances of People will share the same instance of the TableMappingAttribute and ColumnMappingAttributes. In fact, the attribute instances are only created when you actually query for the attributes the first time.
C# provides a mechanism for defining declarative tags, called attributes, which you can place on certain entities in your source code to specify additional information. The information that attributes contain can be retrieved at run time through reflection. You can use predefined attributes or you can define your own custom attributes.
http://msdn.microsoft.com/en-us/library/aa288059%28v=VS.71%29.aspx