AutoMapper - passing a parameter to a custom behavior of a custom recognizer

Although I'm relatively new to AutoMapper, I use it in a small project I'm developing. I've never had a problem with this, but now I'm running into some weird behavior options in Custom Resolver.

Here's the scenario: I get a list of messages from my repository and then map them against a friendly version. Nothing fancy, just normal mapping between objects. I have a field in this frontend object that says that some user has already voted for this post and that I am using a Custom Resolver for (this is that second "ForMember"):

    public List<SupportMessageUi> GetAllVisible(string userId)
    {
        Mapper.CreateMap<SupportMessage, SupportMessageUi>()
              .ForMember(dest => dest.Votes,
                         opt => opt.ResolveUsing<SupportMessageVotesResolver>())
              .ForMember(dest => dest.UserVoted,
                         opt => opt.ResolveUsing<SupportMessagesUserVotedResolver>()
                                   .ConstructedBy(() => new SupportMessagesUserVotedResolver(userId)));

        var messages = _unitOfWork.MessagesRepository.Get(m => m.Visible);

        var messagesUi = Mapper.Map<List<SupportMessageUi>>(messages);

        return messagesUi;
    }

      


I am calling this method in a web service and the problem is that the first time I call the webservice (using the webservice console) everything works fine. For example, if I pass "555" as userId, I get this method with the correct value:

enter image description here


And in the Custom Resolver, the value was passed to the constructor correctly: enter image description here


The results are correct. The problem is as follows. The second time I call the service passing a different argument ('666' this time), the argument that goes into the Custom Resolver constructor is the old one ('555'). This is what I mean:

Right before displaying the objects, we can see that the value passed to the constructor was correct ('666'): enter image description here


But when it gets to the Resolver constructor, the value is wrong and is old ('555'): enter image description here


All subsequent calls to the service use the original value in the Custom Resolver constructor ('555'), regardless of the value I pass to the service (this also happens if I make the call from another browser). If I shutdown the server and restart it, I can pass in a new parameter (which will be used in all other calls until I close it again).

Any idea why this is happening?

+3


source to share


2 answers


Answering the question: I didn't use AutoMapper.Reset (). Once I did that, everything started working fine.



Helpful reading: http://www.markhneedham.com/blog/2010/01/27/automapper-dont-forget-mapper-reset-at-the-start/

+2


source


This is because it AutoMapper.CreateMap

is a static method and only needs to be called once. With the code CreateMap

in your web method, you are trying to call it every time you call that method in your web service. Since the web server process stays alive between calls (unless you restart it like you said), the static mappings stay in place. Hence the need for a call AutoMapper.Reset

, as you said in your answer.

But it was recommended that you create your mapping in AppStart

either Global

or a static constructor or whatever, so you only call it once. There are ways to call Maps that allow you to pass values, so you don't have to try finesse things with your constructor ValueResolver

.

Here's an example using ValueResolver

(note the change to implementation IValueResolver

instead of inheritance ValueResolver<TSource, TDestination>

):



[Test]
public void ValueTranslator_ExtraMapParameters()
{
    const int multiplier = 2;
    ValueTranslator translator = new ValueTranslator();
    Mapper.AssertConfigurationIsValid();

    ValueSource source = new ValueSource { Value = 4 };
    ValueDest dest = translator.Translate(source, multiplier);
    Assert.That(dest.Value, Is.EqualTo(8));

    source = new ValueSource { Value = 5 };
    dest = translator.Translate(source, multiplier);
    Assert.That(dest.Value, Is.EqualTo(10));
}

private class ValueTranslator
{
    static ValueTranslator()
    {
        Mapper.CreateMap<ValueSource, ValueDest>()
            .ForMember(dest => dest.Value, opt => opt.ResolveUsing<ValueResolver>().FromMember(src => src.Value));
    }

    public ValueDest Translate(ValueSource source, int multiplier)
    {
        return Mapper.Map<ValueDest>(source, opt => opt.Items.Add("multiplier", multiplier));
    }

    private class ValueResolver : IValueResolver
    {
        public ResolutionResult Resolve(ResolutionResult source)
        {
            return source.New((int)source.Value * (int)source.Context.Options.Items["multiplier"]);
        }
    }
}

private class ValueSource { public int Value { get; set; } }
private class ValueDest { public int Value { get; set; } }

      

And here's a usage example TypeConverter

:

[Test]
public void TypeTranslator_ExtraMapParameters()
{
    const int multiplier = 3;
    TypeTranslator translator = new TypeTranslator();
    Mapper.AssertConfigurationIsValid();

    TypeSource source = new TypeSource { Value = 10 };
    TypeDest dest = translator.Translate(source, multiplier);
    Assert.That(dest.Value, Is.EqualTo(30));

    source = new TypeSource { Value = 15 };
    dest = translator.Translate(source, multiplier);
    Assert.That(dest.Value, Is.EqualTo(45));
}

private class TypeTranslator
{
    static TypeTranslator()
    {
        Mapper.CreateMap<TypeSource, TypeDest>()
            .ConvertUsing<TypeConverter>();
    }

    public TypeDest Translate(TypeSource source, int multiplier)
    {
        return Mapper.Map<TypeDest>(source, opt => opt.Items.Add("multiplier", multiplier));
    }

    private class TypeConverter : ITypeConverter<TypeSource, TypeDest>
    {
        public TypeDest Convert(ResolutionContext context)
        {
            TypeSource source = (TypeSource)context.SourceValue;
            int multiplier = (int)context.Options.Items["multiplier"];

            return new TypeDest { Value = source.Value * multiplier };
        }
    }
}

private class TypeSource { public int Value { get; set; } }
private class TypeDest { public int Value { get; set; } }

      

+7


source







All Articles