2014-09-17 2 views
3

Хотя я относительно новичок в AutoMapper, я использую его в небольшом проекте, который я разрабатываю. У меня никогда не было проблем с этим, но теперь я сталкиваюсь с некоторыми странными параметрами прохождения поведения в Custom Resolver.AutoMapper - передача параметра в обычное поведение искателя распознавания

Вот сценарий: я получаю список сообщений из своего репозитория, а затем сопоставляю их с дружественной к нему версией. Ничего необычного, просто нормальное отображение между объектами. У меня есть поле в этом внешнем интерфейсе объекта, который говорит, если определенный пользователь уже проголосовал за это сообщение, и это то, что я использую пользовательский Разрешитель для (это то, что второй «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; 
    } 


Я m, вызывающий этот метод в веб-службе, и проблема заключается в следующем: при первом вызове веб-службы (с помощью консоли webservice) все работает отлично. Например, если я прохожу «555», как USERID я получаю к этому методе с правильным значением:

enter image description here


И в пользовательском резольвере значение правильно передается конструктору: enter image description here


Полученные результаты верны. Проблема следующая. Во второй раз, когда я вызываю службу, передавая другой аргумент ('666' на этот раз), аргумент, который попадает в конструктор Custom Resolver, является старым ('555'). Вот что я имею в виду:

Непосредственно перед отображением объектов мы можем видеть, что значение передается конструктору было правильным («666»): enter image description here


Но когда он попадает в конструктор резольвера значение является неправильным, и старый («555»): enter image description here


Все последующие вызовы службы использовать исходное значение в конструкторе пользовательского распознавателя («555»), независимо от значения I перейти к сервису (также происходит если я сделаю звонок из другого браузера). Если я выключу сервер и перезапустите его, я могу передать новый параметр (который будет использоваться во всех других вызовах, пока я не закрою его снова).

Любая идея о том, почему это происходит?

ответ

7

Это происходит потому, что AutoMapper.CreateMap статический метод, и нужно только назвать один раз. С кодом CreateMap в вашем веб-методе вы пытаетесь вызвать его каждый раз, когда вы вызываете этот метод в своем веб-сервисе. Так как веб-сервер процесс остается живым между вызовами (если вы не перезапустите его, как вы сказали), то статические сопоставления остаются на месте. Следовательно, необходимо позвонить AutoMapper.Reset, как вы сказали в своем ответе.

Но рекомендуется, чтобы вы создали свое отображение в AppStart или Global или статический конструктор или что-то еще, поэтому вы вызываете его только один раз. Есть способы вызвать карту, которая позволяет передавать значения, поэтому вам не нужно пытаться изящество вещей с конструктором вашего ValueResolver.

Вот пример с использованием ValueResolver (обратите внимание на изменения в реализации IValueResolver вместо унаследованного 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; } } 

А вот пример использования 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; } } 
Смежные вопросы