AutoMapper mapping object types - c#

I'm dealing with a really awful set of generated classes which have a ton of properties of type object that contain various types I want to map. The class mappings seem to work however the property references are just copied directly without mapping the referenced objects.
How can I define a map which will map the objects inside the Items property? I have a ton of objects like this so hoping I can define this fairly simply...
Example:
class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<TerribleType1, TerribleType1Dto>();
cfg.CreateMap<TerribleType2, TerribleType2Dto>();
cfg.CreateMap<TerribleObject, TerribleObjectDto>();
});
var mapper = config.CreateMapper();
var terribleObject = new TerribleObject
{
Items = new object[] { new TerribleType1 { PropA = "Test1" }, new TerribleType2 { PropA = "Test2" } }
};
var terribleObjectDto = mapper.Map<TerribleObjectDto>(terribleObject);
//Want a TerribleType1Dto but instead I get a TerribleType1
Console.WriteLine(terribleObjectDto.Items[0].GetType().Name);
}
}
class TerribleObject
{
// Contains some TerribleType1 and TerribleType2 objects, these don't share a common base.
public object[] Items { get; set; }
}
class TerribleObjectDto
{
//Want this to have some TerribleType1Dto and TerribleType2Dto objects.
public object[] Items { get; set; }
}
public class TerribleType1
{
public string PropA { get; set; }
}
public class TerribleType1Dto
{
public string PropA { get; set; }
}
public class TerribleType2Dto
{
public string PropA { get; set; }
}
public class TerribleType2
{
public string PropA { get; set; }
}

Based on How can I use Automapper to map an object to an unknown destination type? it is possible to get the configured destination type for a mapping when you know the source type at runtime only. With the help of MapFrom() it is possible to build this ugly mapping for the inner object type objects:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<TerribleType1, TerribleType1Dto>();
cfg.CreateMap<TerribleType2, TerribleType2Dto>();
cfg.CreateMap<TerribleObject, TerribleObjectDto>()
.ForMember(t => t.Items, m => m.MapFrom((source, target, data, context) =>
{
object[] items = source.Items;
object[] targetArray = new object[items.Length];
for (int i = 0; i < items.Length; i++)
{
object fieldEntry = items[i];
Type destinationType = context.Mapper.ConfigurationProvider
.GetAllTypeMaps()
.Single(it => it.SourceType == fieldEntry.GetType())
.DestinationType;
targetArray[i] = context.Mapper.Map(fieldEntry,
fieldEntry.GetType(),
destinationType);
}
return targetArray;
}));
});
This will convert each object in the array to the configured destination type. When you run your code now:
Console.WriteLine(terribleObjectDto.Items[0].GetType().Name);
Console.WriteLine(terribleObjectDto.Items[1].GetType().Name);
you will get the following output:
TerribleType1Dto
TerribleType2Dto

Related

AutoMapper cannot map object inside object

im trying to map ViewModels to Models. My models looks like this:
public class FinalsViewModel
{
public FinalViewMode First { get; set; }
public FinalViewModel Second { get; set; }
}
public class Finals
{
public Final First { get; set; }
public Final Second { get; set; }
}
// And Final:
public class FinalViewModel
{
public int Another { get; set; }
}
public class Final
{
public int Order { get; set; }
public int Another { get; set; }
}
I created mapping that looks like this:
CreateMap<FinalsViewModel, Finals>()
.ForMember(src => src, opt => opt.MapFrom((src, dest) =>
{
var list = new List<Final>();
if (src.First != null && src.First?.Another != null)
list.Add(new Final { Order = 1, Another = src.First.Another });
if (src.Second != null && src.Second?.Another != null)
list.Add(new Final { Order = 2, Another = src.Second.Another });
var result = new Finals() // logic for mapping First = First, Second = Second etc;
return result;
}));
Im getting error from this mapping:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> AutoMapper.AutoMapperConfigurationException: Custom configuration for members is only supported for top-level individual members on a type.
My question is, how to rewrite this config to map object inside another object?
The problem is your ForMember(source=>source) , AutoMappter default map every property from source, and the first parameter is an Expression , it design for get the member name , x=>x.First will get the First and it's type.
and You want to map FinalsViewModel to Finals,
first you need create a map of FinalsViewModel => Finals
then you need create a map of FinalViewMode => Final
CreateMap<FinalsViewModel, Finals>();
CreateMap<FinalViewMode,Final>();
// you can also use `.ForMemeber()` to do more thing.

Flatten object using auto mapper but not using ForMember or the naming conventions used for flattening

Problem
Flatten large, multi level object using auto mapper to allow me to pass values to sql using Dapper.
Options
After reading the docs and various answers on SO, there seems to be two options, using ForMember or using NamingConventions. Neither of these can work for me as the object is so large that ForMember would require almost as much manual mapping. NamingConventions would mean some unreadable and irrelevant names for where the target object is being used.
refs I used: ForMember flattening
I did find a really basic example of using the ITypeConverter (Custom type converters) and have tried to make it work for me, but I'm really struggling, after three days of trying, I thought I should turn for help.
After searching various forums I decided to try and create a generic solution as I will be reusing this multiple times throughout my project.
Please note, if there is a better way (an existing extension, or a configuration i've missed, i'd love to hear of it. If not could you please offer some guidance on how to complete my task - I feel like I'm banging my head against a brick wall)
below I have added the console app I created to try to resolve this (I feel I should say that I know this code is awful, I have just been hacking away in the hope something would work)
using AutoMapper;
using System;
using System.Linq;
using System.Reflection;
namespace AutomapperTests
{
public class Program
{
static void Main(string[] args)
{
var property = Program.CreateProperty();
var config = new MapperConfiguration(cfg => cfg.CreateMap<PropertyDto, FlatProperty>()
.ConvertUsing<MyTypeConverter<PropertyDto, FlatProperty>>());
var mapper = config.CreateMapper();
var flatProperty = mapper.Map<FlatProperty>(property);
}
private static PropertyDto CreateProperty()
{
var property = new PropertyDto();
property.Guid = new Guid();//not mapping to guid
property.SomeTestVal = 123456;
property.TransactionStatus = TransactionStatus.ForSale;
property.Address = new AddressDto();
property.Detail = new DetailDto();
property.Address.PostCode1 = "ng10";
property.Detail.LandArea = 12;
return property;
}
}
public class MyTypeConverter<T, TK> : ITypeConverter<T, TK>
{
public TK Convert(T source, TK destination, ResolutionContext context)
{
var sourceType = source.GetType();
PropertyInfo[] sourceClassProperties = sourceType.GetProperties();//note: i've tried flattening the structure at this point but failed
var properties = GetCustomObjectsFromProperties(sourceType.GetProperties());
destination = (TK)Activator.CreateInstance(typeof(TK));
var destinationType = destination.GetType();
PropertyInfo[] destinationProperties = destinationType.GetProperties();
foreach (PropertyInfo sourceClassProperty in sourceClassProperties)
{
SetValue(sourceClassProperty, source, destinationProperties, destination);
}
return destination;
}
private void SetValue(PropertyInfo sourceClassProperty, T source, PropertyInfo[] destinationProperties, TK destination)
{
bool isNativeClass = IsNativeClass(sourceClassProperty);
object sourceValue = sourceClassProperty.GetValue(source);
string sourceName = sourceClassProperty.Name;
PropertyInfo destProperty = destinationProperties.FirstOrDefault(x => x.Name == sourceName);
if (destProperty == null && !isNativeClass)
{
//note: my idea was to use recursion to enter the object if necessary and search for a matching value ---maybe i'm really overthinking this???
}
SetDestinationValue(destProperty, destination, sourceValue);
}
private bool IsNativeClass(PropertyInfo sourceClassProperty)
{
return sourceClassProperty.GetType().Namespace == "System";
}
private void SetDestinationValue(PropertyInfo destProperty, TK destination, object sourceValue)
{
if (destProperty != null)
{
destProperty.SetValue(destination, sourceValue);
}
}
private PropertyInfo[] GetCustomObjectsFromProperties(PropertyInfo[] propertyInfo)
{
return propertyInfo.Where(info => info.Module.Name == GetAssemblyName()).ToArray();
}
private string GetAssemblyName()
{
return $"{typeof(T).Assembly.GetName().Name}.dll";
}
}
public class FlatProperty
{
public Guid Guid { get; set; }
public int SomeTestVal { get; set; }
public int? TransactionStatusId { get; set; }
public string Postcode1 { get; set; }
public decimal? LandArea { get; set; }
}
public class PropertyDto
{
public Guid Guid { get; set; }
public int SomeTestVal { get; set; }
public TransactionStatus? TransactionStatus { get; set; }
public AddressDto Address { get; set; }
public DetailDto Detail { get; set; }
}
public class AddressDto
{
public string PostCode1 { get; set; }
}
public class DetailDto
{
public decimal? LandArea { get; set; }
}
public enum TransactionStatus
{
Sold = 1,
ForSale = 2
}
}
Edit:
I have just found that it seems I can do something like this:
in config:
CreateMap<AddressDto, CreatePropertyDataModel>();
CreateMap<DetailDto, CreatePropertyDataModel>();
CreateMap<PropertyDto, CreatePropertyDataModel>()
.ForMember(dest => dest.Guid,
opts => opts.MapFrom(
src => src.Guid.ToString()));
set an object:
var property = new PropertyDto();
property.Guid = new Guid();//not mapping to guid
property.SomeTestVal = 123456;
property.TransactionStatus = TransactionStatus.ForSale;
property.Address = new AddressDto();
property.Detail = new DetailDto();
property.Address.PostCode1 = "ng10";
property.Detail.LandArea = 12;
return property;
in some class:
var dataModel = new UpsertPropertyDataModel();
_mapper.Map(_property, dataModel);
_mapper.Map(_property.Address, dataModel);
_mapper.Map(_property.Detail, dataModel);
My problem with this is that I get the error Unmapped members were found, these unmapped members are reffering to members Address or Detail could not map to, so I would have to set those members to Ignore(), is this a viable solution that i'm using incorrectly? (please note my real world objects are much bigger)

Mapping class array using AutoMapper

I'm new to AutoMapper and trying to map Array class ItemLink[].
public class ViewModel
{
public ItemLink[] ItemLinks { get; set; }
}
public class ItemLink
{
public string Description { get; set; }
}
I tried:
Mapper.Map<viewModel.ItemLink>(db.ItemLinks);
Error:
"Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance."
Can't it be simple mapping?
EDIT 1
To clarify more, I'm getting similar class structure from database. Example,
public class Db
{
public ItemLink[] ItemLinks { get; set; }
}
So, I want to map ViewModel.ItemLink[] with Db.ItemLink[].
You cannot provide variable to a generic parameter like you do in Mapper.Map<viewModel.ItemLink>(db.ItemLinks);. It is called Type parameter and must be a type.
As #gisek mentioned in his answer you need to configure mapper first. Normally it is done at application startup.
You can consider to fetch full objects from db, but you also have an option to use Queryable Extensions which are there to only fetch data you need for your view model.
The configuration. I assume that you have namespace DB for entity in database, and View namespace for view model.
Mapper.Initialize(cfg => {
cfg.CreateMap<DB.ItemLink, View.ItemLink>();
});
Mapper.Configuration.AssertConfigurationIsValid();
Fetch full entity from DB and then map it to property:
var viewModel = new View.Item();
viewModel.ItemLinks = Mapper.Map<View.ItemLink[]>(db.ItemLinks.ToArray());
Project entity from DB to view model:
var viewModel = new View.Item();
viewModel.ItemLinks = db.ItemLinks.ProjectTo<View.ItemLink>().ToArray();
I assumed you are using .net mvc
Firstly you need Initialize your mapping on Application Start, there is no need to initialize every time in your controller etc.
Following error means you didn't initialize mapper, automapper doesn't know your source and destination object.
Error:
"Mapper not initialized. Call Initialize with appropriate
configuration. If you are trying to use mapper instances through a
container or otherwise, make sure you do not have any calls to the
static Mapper.Map methods, and if you're using ProjectTo or
UseAsDataSource extension methods, make sure you pass in the
appropriate IConfigurationProvider instance."
For Solution:
Create an AutoMapperConfig object in your App_Start folder.
public class AutoMapperConfig
{
public static void Register()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<source,destination>(); /*If source and destination object have same propery */
cfg.CreateMap<source, destination>()
.ForMember(dest => dest.dId, opt => opt.MapFrom(src => src.sId)); /*If source and destination object haven't same property, you need do define which property refers to source property */
});
}
}
In your Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AutoMapperConfig.Register(); // Call Register method on App_Start
}
In your controller
var mappedArray = Mapper.Map<viewmodel.ItemLink[]>(db.ItemLinks);
or
var mappedArray = Mapper.Map<viewmodel.ItemLink[],ItemLinks[]>(db.ItemLinks); //ItemLinks[] refers to your dto.
You need to configure the mapper first.
There are 2 possible approaches, static and non-static. I lean towards non-static as it allows you to create multiple mappers, which can use different mapping strategies.
Non-static example:
using AutoMapper;
namespace Experiments
{
class Program
{
static void Main(string[] args)
{
var links = new ItemLink[]
{
new ItemLink {Description = "desc 1"},
new ItemLink {Description = "desc 2"},
};
var item = new Item
{
ItemLinks = links,
};
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ItemLink, ItemLink>(); // you can extend this part of the configuration here
cfg.CreateMap<Item, Item>();
cfg.CreateMap<ItemLink, MyCustomClass>()
.ForMember(myCustomClass => myCustomClass.DescriptionWithDifferentName,
expression => expression.MapFrom(itemLink => itemLink.Description)); // to map to a different type
// more configs can do here
// e.g. cfg.CreateMap<Item, SomeOtherClass>();
});
IMapper mapper = new Mapper(config);
ItemLink linkClone = mapper.Map<ItemLink>(links[0]);
ItemLink[] linkArrayClone = mapper.Map<ItemLink[]>(item.ItemLinks);
Item itemClone = mapper.Map<Item>(item);
MyCustomClass myCustomClassObject = mapper.Map<MyCustomClass>(links[0]);
}
}
public class Item
{
public ItemLink[] ItemLinks { get; set; }
}
public class ItemLink
{
public string Description { get; set; }
}
public class MyCustomClass
{
public string DescriptionWithDifferentName { get; set; }
}
}
Static example:
using AutoMapper;
namespace Experiments
{
class Program
{
static void Main(string[] args)
{
var links = new ItemLink[]
{
new ItemLink {Description = "desc 1"},
new ItemLink {Description = "desc 2"},
};
var item = new Item
{
ItemLinks = links,
};
Mapper.Initialize(cfg =>
{
cfg.CreateMap<ItemLink, ItemLink>(); // you can extend this part of the configuration here
cfg.CreateMap<Item, Item>();
cfg.CreateMap<ItemLink, MyCustomClass>()
.ForMember(myCustomClass => myCustomClass.DescriptionWithDifferentName,
expression => expression.MapFrom(itemLink => itemLink.Description));
// to map to a different type
// more configs can do here
// e.g. cfg.CreateMap<Item, SomeOtherClass>();
});
ItemLink linkClone = Mapper.Map<ItemLink>(links[0]);
ItemLink[] linkArrayClone = Mapper.Map<ItemLink[]>(item.ItemLinks);
Item itemClone = Mapper.Map<Item>(item);
MyCustomClass myCustomClassObject = Mapper.Map<MyCustomClass>(links[0]);
}
public class Item
{
public ItemLink[] ItemLinks { get; set; }
}
public class ItemLink
{
public string Description { get; set; }
}
public class MyCustomClass
{
public string DescriptionWithDifferentName { get; set; }
}
}
}
You can also configure Automapper to create missing maps automatically with cfg.CreateMissingTypeMaps = true;
using AutoMapper;
namespace Experiments
{
class Program
{
static void Main(string[] args)
{
var links = new ItemLink[]
{
new ItemLink {Description = "desc 1"},
new ItemLink {Description = "desc 2"},
};
var item = new Item
{
ItemLinks = links,
};
Mapper.Initialize(cfg =>
{
// now AutoMapper will try co create maps on it's own
cfg.CreateMissingTypeMaps = true;
// we can still add custom maps like that
cfg.CreateMap<ItemLink, MyCustomClass>()
.ForMember(myCustomClass => myCustomClass.DescriptionWithDifferentName,
expression => expression.MapFrom(itemLink => itemLink.Description));
});
ItemLink linkClone = Mapper.Map<ItemLink>(links[0]);
ItemLink[] linkArrayClone = Mapper.Map<ItemLink[]>(item.ItemLinks);
Item itemClone = Mapper.Map<Item>(item);
// without custom map myCustomClassObject.DescriptionWithDifferentName would be null
MyCustomClass myCustomClassObject = Mapper.Map<MyCustomClass>(links[0]);
}
public class Item
{
public ItemLink[] ItemLinks { get; set; }
}
public class ItemLink
{
public string Description { get; set; }
}
public class MyCustomClass
{
public string DescriptionWithDifferentName { get; set; }
}
}
}
I am not sure that I understood what you need,
I guess that you are trying to map from a list of ItemLink to a list of viewModel.ItemLink
so Mapper.Map<viewModel.ItemLink>(db.ItemLinks);
become
var listOfViewModelItemLink = Mapper.Map<List<viewModel.ItemLink>>(db.ItemLinks);
you can call ToArray() on listOfViewModelItemLink then assign to ItemLinks property of Item class
I am not sure but I guess that you are trying to map from an array of ItemLink to an array of viewModel.ItemLink. You should do it like this:
var viewModels = db.ItemLinks
.ToArray()
.Select(x=>Mapper.Map<viewModel.ItemLink>(x))
.ToArray();

Auto-mapper class object with nested multiple class objects

I have used auto-mapper to map single class object which is working fine, say example
class_source{
string a;
int b
}
class_destination
{
string a;
int b
}
now what I have viewModel based on multiple class object as
Source
public class WebSyncSummaryEntity
{
public Web_AppFormsEntity AppForms { get; set; }
public Web_EBS_SyncEntity EBS_Sync { get; set; }
public Web_SyncAuditLogEntity SyncAuditLog { get; set; }
}
Destination
[DataContract]
public class WebSyncSummaryView
{
[DataMember]
public Web_AppForms AppForms { get; set; }
[DataMember]
public Web_EBS_Sync EBS_Sync { get; set; }
[DataMember]
public Web_SyncAuditLog SyncAuditLog { get; set; }
}
how I can map to equivalent class object
I have tried in following code to map but error
public IList<WebSyncSummaryView> GetWebSyncSummary()
{
IList<WebSyncSummaryView> _WebSyncSummaryView = null;
IList<WebSyncSummaryEntity> _WebSyncSummaryEntity = _WebSyncCoreObject.GetWebSyncSummary();
if (_WebSyncSummaryEntity != null)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<WebSyncSummaryEntity, WebSyncSummaryView>();
});
IMapper mapper = config.CreateMapper();
_WebSyncSummaryView = mapper.Map<IList<WebSyncSummaryEntity>, IList<WebSyncSummaryView>>(_WebSyncSummaryEntity);
}
return _WebSyncSummaryView;
}
Error
"Error mapping types.\r\n\r\nMapping types:\r\nWebSyncSummaryEntity -> WebSyncSummaryView\r\nApp.Entities.WebSyncSummaryEntity -> App.WebServices.DataContract.WebSyncSummaryView\r\n\r\nType Map configuration:\r\nWebSyncSummaryEntity -> WebSyncSummaryView\r\nApp.Entities.WebSyncSummaryEntity -> App.WebServices.DataContract.WebSyncSummaryView\r\n\r\nProperty:\r\nSyncAuditLog"}
Error mapping types.
Mapping types:
IList`1 -> IList`1
System.Collections.Generic.IList`1[[App.Entities.WebSyncSummaryEntity, App.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] -> System.Collections.Generic.IList`1[[App.WebServices.DataContract.WebSyncSummaryView, App.Services.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
Change the Line
_WebSyncSummaryView = mapper.Map<IList<WebSyncSummaryEntity>, IList<WebSyncSummaryView>>(_WebSyncSummaryEntity);
To
_WebSyncSummaryView = mapper.Map<IList<WebSyncSummaryView>>(_WebSyncSummaryEntity);
There is no need to tell AutoMapper the source type. You try to map the IList<>, but you only want to map WebSyncSummaryEntity. Just tell the Mapper what for an result you want and the rest comes from the voodoo of AutoMapper ;)
found answer
public IList<WebSyncSummaryView> GetWebSyncSummary()
{
IList<WebSyncSummaryView> _WebSyncSummaryView = null;
IList<WebSyncSummaryEntity> _WebSyncSummaryEntity = _WebSyncCoreObject.GetWebSyncSummary();
if (_WebSyncSummaryEntity != null)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMissingTypeMaps = true; //............... missing this
cfg.CreateMap<WebSyncSummaryEntity, WebSyncSummaryView>();
});
IMapper mapper = config.CreateMapper();
_WebSyncSummaryView = mapper.Map<IList<WebSyncSummaryEntity>, IList<WebSyncSummaryView>>(_WebSyncSummaryEntity);
}

Special treatment for float properties in some but not all AutoMapper mappings

I've just started with AutoMapper in C#. I've succesfully created a mapping like this:
Mapper.CreateMap<InputTypeA, OutputTypeA>()
I've also found a way to add some logic to specific properties, like formatting a date (in InputTypeA) to a string in a specific format (in OutputTypeA).
.ForMember(
dest => dest.MyDateProperty,
opt => opt.ResolveUsing(
src => String.Format("{0:yyyy-MM-dd}", src.MyDateProperty)));
Now I need to do the same for a number of float properties, but I'm wondering if there is a short/easy way to do this, except copying a piece of code like the one above for every property that needs to follow this rule.
I've found that I can create a new map like this for mapping floats to strings:
Mapper.CreateMap<float,string>()
.ConvertUsing(src =>
String.Format(CultureInfo.InvariantCulture.NumberFormat, "{0:0.00}", src));
This works, but is too generic, because I also have a mapping for another type (let's call it InputTypeB), that also contains float properties, which need to be treated differently.
Mapper.CreateMap<InputTypeB, OutputTypeB>()
How can I make the float-to-string mapping part of the first mapping only?
You could create two separate mappers based on two separate configurations, only one of which includes the float-to-string mapping:
public class InputTypeA { public float Foo { get; set; } }
public class OutputTypeA { public string Foo { get; set; } }
public class InputTypeB { public float Bar { get; set; } }
public class OutputTypeB { public string Bar { get; set; } }
public class Program
{
public static void Main(string[] args)
{
Func<float, string> mapFunc =
src => String.Format(CultureInfo.InvariantCulture.NumberFormat, "{0:0.00}", src);
var floatToStringConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<InputTypeA, OutputTypeA>();
cfg.CreateMap<float, string>().ConvertUsing(mapFunc);
});
var regularConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<InputTypeB, OutputTypeB>();
});
IMapper floatToStringMapper = floatToStringConfig.CreateMapper();
IMapper regularMapper = regularConfig.CreateMapper();
var aIn = new InputTypeA() { Foo = 1f };
var aOut = floatToStringMapper.Map<OutputTypeA>(aIn);
Console.WriteLine(aOut.Foo); // prints "1.00"
var bIn = new InputTypeB() { Bar = 1f };
var bOut = regularMapper.Map<OutputTypeB>(bIn);
Console.WriteLine(bOut.Bar); // prints "1"
}
}
You can create custom value resolvers for each case you need to handle. Then apply these to the appropriate members in your mappings.
As an example, I need to map from TypeA to TypeB, I only want DateB to use the custom conversion:
public class TypeA {
public DateTime DateA { get; set; }
public DateTime DateB { get; set; }
}
public class TypeB {
public string DateA { get; set; }
public string DateB { get; set; }
}
I create a custom resolver:
class DateStringResolver : ValueResolver<DateTime, string> {
protected override string ResolveCore(DateTime source) {
return String.Format("{0:yyyy-MM-dd}", source);
}
}
Then in my mapper config:
Mapper.CreateMap<TypeA, TypeB>()
//Only Date B will use our custom resolver
.ForMember(d => d.DateB, opt => opt.ResolveUsing<DateStringResolver>().FromMember(src => src.DateA));
The resolver can now be applied wherever it is needed.
Docs:https://github.com/AutoMapper/AutoMapper/wiki/Custom-value-resolvers

Categories