Been having some real issues with automapper. I think I have found the solution but unsure of how to implement it.
basically I am using a custom mapping with ResolveUsing and ConstructedBy to pass in params to the constructor, I understand that most people set this up in the global.asax once and forget about it.
But the problem is that my method (on a wcf) passes in different params to the constructor of a ResolveUsing ......
Before I was using the Mapper.CreateMap and Mapper.Map which are static methods and it appears that when different petitions come into the wcf service via methods (multi -user) they are conflicting with each other.
After reading something it appears I can use the instance version of CreateMap and Map so that each individual petition gets its own map and can pass in its own params.
But I can't seem to find how to do it. Can anyone explain please? I am really stuck...
Before now and again I would get duplicate key errors and also I put in a log trace on the constructor and it appears that 1 petition is overwriting the other - hence the static versions of Mapper.
Well I hope I am correct, but I can't find anything else...
EDITED - AN EXAMPLE OF WHAT I HAVE
Basically all mapping is working as it should, as I am using MapFrom in most cases.
Then I create an instance of my Resolver which I pass in a URL. I have checked the url before I pass it in and its correct. But once it returns it returns the wrong URL.
The reason I need pass in the URL is that it has variables in there so I need to replaced the variables... Basically there are 2 urls depending on the office and I have logs everywhere and I can see what I am passing in but once I pass it in - it isn't the one I passed in, if that makes sense, this is weird!!
Its a WCF service and a client has called the method twice passing in 2 different offices hence 2 different URLs. But they always return the same URL. It's like one session is overwriting the other...
I hope this makes sense.
SalesPointResolver newSalesPointResolver = new SalesPointResolver(returnReservationUrl, reservationSite.ReservationUrl, startDate, endDate, officeCode);
Mapper.CreateMap<Models.Custom.House, DTO.House>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.TaxIncluded,
opt => opt.MapFrom(src => src.Segments.FirstOrDefault().TaxIncluded))
.ForMember(dest => dest.TaxPercentage,
opt => opt.MapFrom(src => src.Segments.FirstOrDefault().TaxPercentage))
.ForMember(dest => dest.SalesPoints,
opt =>
opt.ResolveUsing(newSalesPointResolver))
;
FOUND OUT WHERE IS FAILING - BUT UNKNOWN WHY
See my comments inline with code. In the constructor the urlTemplate arrives, I save it in a private var and then in the overridden ResolveCore it's something else :-)
I have placed some log4net logs on there, so I can see whats happening.
[Log]
public class SalesPointResolver : ValueResolver<Models.Custom.House, IList<DTO.SalesPoint>>
{
private readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private string urlTemplate;
public SalesPointResolver (bool returnReservationUrl, string urlTemplate, DateTime startDate, DateTime endDate, string officeCode)
{
this.urlTemplate = urlTemplate;
log.Error("passed in " + urlTemplate); // THIS IS PERFECT
log.Error("I am now " + this.urlTemplate); // THIS IS PERFECT
}
protected override IList<DTO.SalesPoint> ResolveCore(House source)
{
this.house = source;
log.Error("in resolveCore :" + this.urlTemplate); // THIS IS RETURNING THE WRONG VALUE
TEMPORARY SOLUTION
I have done a temporary solution but it's really bad. I am sure automapper can do what I am trying, but I am obviously doing something wrong.
Basically I return via LINQ a collection of records (THIS IS MY SOURCE) so I entered a new field on every record that has the correct URL template on there. And then, instead of passing in (via constructor) the url template, I have it available as a property on EVERY record on the collection (THE SOURCE) ... and it works perfect.
Of course, this really is patch and not ideal but it gets me running.
Where am I going wrong?
Yes, there is a way to use an instance version of AutoMapper.
Instead of...
Mapper.CreateMap<Dto.Ticket, Entities.Ticket>()
you can use:
var configurationStore =
new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
var mapper = new MappingEngine(configurationStore);
configurationStore.CreateMap<Dto.Ticket, Entities.Ticket>()
In response to Luke Woodwards's comment on the newer syntax:
ConfigurationStore store
= new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
store.AssertConfigurationIsValid();
MappingEngine engine = new MappingEngine(store);
//add mappings via Profiles or CreateMap
store.AddProfile<MyAutoMapperProfile>();
store.CreateMap<Dto.Ticket, Entities.Ticket>();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With