views:

867

answers:

3

Hi there,

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 othere..

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 teh constructor and it appears that 1 petition is overwritting the other - hence the static versions of Mapper..

Well i hope i am correct but i can't find anything else...

I would really appreciated any help

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 its like one session is overwritting 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 overriden ResolveCore its 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 its really bad, i am sure automapper can do what i am trying but i am obvious not doing something right..

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..

But i would really love to know where i am going wrong?

A: 

Have you looked at using the Map call that takes in the destination object?

var bar = new Bar("Custom each call");

Mapper.Map(foo, bar);

Jimmy Bogard
Thanks jimmy, Not sure if i quite understand. If i change the map then i won't have access to my standard src object which i do need as i do normally mappings its only on a few properties that require me to call the special ResolveUsing and passing a parameter as there is quite a bit of logic here... So in resolveusing i am still using my standard src object but applying extra logic before return (in this case a stringg) - am i misunderstanding you?
mark smith
if you could elaborate i would very much appreciate it.
mark smith
I think I misunderstood - do you have a little snippet that shows how you're using the CreateMap and Map calls?
Jimmy Bogard
Hi jimmy, thanks for getting back to me.. yep sure do.. i am going to update my question now ..
mark smith
Ok question has been updated with an example of what i am doing, using "RESOLVEUSING" ... before i was using ConstructedBy but now i am creating the instance and passing it into the ResolveUsing - i hope this makes sense..
mark smith
Hi jimmy, i have done some extensive testing and updated my question. please forgive it being a bit long but i wanted to include everything. The summary is this.. Correct value arrives in constrructor and save in private then when it executes the overriden ResolveCore it returns the wrong one :-) ..
mark smith
Hi Jimmy, i have updated my msg again - i hopefully have explained everything correct, there is a small temporary solution that i have done - althought not ideal - i have explained it in my original message that i have just edited. Look forward to any thoughts you have on my issue. Thank you once again
mark smith
A: 

Well it appears that my question is abandoned but after quite a while playing around I finally found a GOOD fix..

basically i was inside a Resolve and i had another MAP which one of the properties called another ResolveUsing ...

It appears there seems to be an issue with this. Another weird thing is that it failed everytime the application pool was started or recycled.. Hence it failed the first time and then was ok until the recycle happened (i am using a wcf app).

So i replaced the second Mapping with with a foreach and did my mapping like that inside my original Resolve ...

I have put the answer here in case it can help anybody else in the future..

I was using the Mapper static methods to do my mappings, these were not in global.asax as i need to pass different things depending on certain factors..

I always wondered if it would be possible to do it with Instance versions of mappper, i though it existed..... but never found out..

But anyway all is working 100% now...

mark smith
A: 

If you want to use an instanced version of the Mapper in Automapper, then I think you can use the MappingEngine class. I believe the static Mapper class instantiates and configures an MappingEngine object to do all of the nitty gritty mapping work.

Here's an example of applying IoC to Automapper (which requires instantiation of the MappingEngine)

http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/05/11/automapper-and-ioc.aspx

DuCKa