I know about the feature of defining a Before/AfterMap callback on the map level for a given type pair. However, I'm searching for a solution to define a global Before/AfterMap function somehow, which would apply to every defined type map.
In most of my DTOs I have a mechanism which prevents changed notifications temporarly with the BeginUpdate/EndUpdate pattern. I would like AutoMapper to wrap the mapping between these calls whenever the target type supports it.
I've looked through questions here and the AutoMapper docs but haven't found a native solution.
I think I've found a porposed solution, but haven't tested it completely yet.
After all of my maps are registered, I would do something like this:
var typeMaps = Mapper.GetAllTypeMaps();
foreach (var typeMap in typeMaps)
{
typeMap.AddBeforeMapAction(...);
typeMap.AddAfterMapAction(...);
}
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.
I have some older code that use the JsonSchemaResolver class and the GetSchema method, but according to the documentation those are now obsolete. Therefore I want to update my code to use the new API, but I can't seem to find the corresponding way of getting a resolved schema with the JSchemaResolver class.
There isn't really an equivalent method with JSchemaResolver.
While JsonSchemaResolver was just an id/value dictionary of schemas, JSchemaResolver is designed to resolve schemas from external resources. Its main method GetSchemaResource returns a Stream which is then loaded internally.
Something like JsonSchemaResolver was removed because it couldn't handle complex situations like circular schema relationships.
I am surprised that NInject does not follow the type hierarchy when looking for a binding.
Bind<ICollection<ICard>>().ToConstructor(/* .. */);
var Cards = IoC.Kernel.Get<IList<ICard>>();
In the above code, the Kernel.Get<..>() sends me an ActivationException because I haven't explicitely bound IList<ICard>. In other words, for NInject, an IList<ICard> is not an ICollection<ICard>. Sounds strange to me.
Of course I can remove the error by explicitely adding Bind<IList<ICard>>().To<..>(), but I don't understand why NInject doesn't follow type hierarchy by default. Am I missing something?
So, can somebody explain:
Why NInject forces me to be that specific in my bindings
How I can overcome this behaviour without adding a tedious list of bindings for every possible collection (unless you convince me that it is a very bad practice to do so)
I've just started using AutoMapper and so far found it very straight-forward and time-saving.
Just one thing I'm not sure about - how do I map all the properties of a given type in the same way?
Can this be done with AutoMapper in a single statement, using a lambda, as with regular mapping?
What you are looking for is known as a CustomTypeConverter. These are global in scope, and only need to be configured once.
The syntax is:
Mapper.CreateMap<TSourceProperty,TDestinationProperty>().ConvertUsing(argument);
where argument can be
An implementation of ITypeConverter<TSourceProperty,TDestinationProperty>
A Func<TSourceProperty,TDestinationProperty>
Jimmy Bogard has an article on implementing CustomTypeConverters at http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/05/05/automapper-feature-custom-type-converters.aspx .
More information is also provided in the CustomTypeConverter page of the AutoMapper documentation.
Oh, and by the way (since I want Omu's bounty) you can also do this by switching to valueinjecter.
Currently, I've created a class with ~30 properties to be set. This is done to build up a URL request later on(ie, "http://www.domain.com/test.htm?var1=a&var2=b...&var30=dd").
The issue I'm facing is the property names don't necessarily match the query variable names(this is intended to be different). For example, I may have a variable titled "BillAddress", whereas the query variable will need to be "as_billaddress".
I have no control over the query variable naming scheme as these are set at an external source.
One possible solution I've used is creating a custom attribute and decorating the properties with their respective query counterparts:
[CustomQueryAttribute("as_billaddress")]
string BillAddress{get;set;}
To retrieve the attribute though, requires a little reflection and due to the larger number of properties, I was curious if there is a neater way to accomplish this functionality. Not so much as setting/retrieving custom attributes without reflection, but being able to tie an alternate string variable to any property.
I've also pondered about setting each variable up as a sort of KeyValuePair, with each key representing the query counterpart, but I didn't get too far in that thought.
To summarize/clarify my above backstory, what would you do to associate a string with a property(not the value of the property)?
As always, any comments are greatly appreciated.
I would probably stick with a custom attribute, but the other potential option would be to do something like hold a static Dictionary that had string and property info (or property name), so you could get/set the property directly via this.
Something like:
static Dictionary<string, PropertyInfo> propertyMap = new Dictionary<string, PropertyInfo>();
static MyClass()
{
Type myClass = typeof(MyClass);
// For each property you want to support:
propertyMap.Add("as_billaddress", MyClass.GetProperty("BillAddress"));
// ...
}
You could then just do a dictionary lookup instead of using reflection in each call... This could also be setup fairly easy using configuration, so you could reconfigure the mappings at runtime.
A custom attribute seems like the best option to me - the framework seems to do this a lot as well (specifically with serialization).
If you look at popular ORM mappers then nearly all either use custom attributes or some kind of XML mapping file. The advantage of the latter is that you can modify the mapping without recompiling your application - the downside is that it hurts performance. However, I'd say your choice seems perfectly reasonable.