Глобально применять преобразователь значений с помощью AutoMapper

17

Я пытаюсь, чтобы AutoMapper позаботился о локализации всех свойств DateTime на наших моделях просмотра для нас. Мы используем UTC всюду в нашей системе и сохраняем все в UTC в базе данных, но мы хотели бы автоматически преобразовать это в часовой пояс пользователя для отображения.

Посмотрев на все варианты, я решил использовать ValueResolver. Вот суть распознавателя:

public class LocalizedDateTimeFormatter : ValueResolver<DateTime, DateTime>
{
    protected override DateTime ResolveCore(DateTime source)
    {
        // get company

        return company.TimeZone.ConvertFromUtc(source);
    }
}

Я настраиваю отображение следующим образом:

Mapper.CreateMap<Entity, Model>()
    .ForMember(dest => dest.Foo, opt => opt.ResolveUsing<LocalizedDateTimeFormatter>()
                                            .FromMember(src => src.Foo));

Все это прекрасно работает, и я доволен этим. Однако в идеале мы бы хотели, чтобы по умолчанию все свойства DateTime в модели представления использовали для использования этого резольвера. Я начал путь к отражению свойств модели представления, выделению DateTime и использованию перегрузок ForMember и FromMember, которые принимают имена строк свойств, но это казалось ... уродливым. Плюс дублирование логики построения вложенных свойств AutoMapper будет довольно быстро разрушаться.

Вопрос: Есть ли простой способ сказать AutoMapper глобально использовать ValueResolver, как это? Чтобы сказать: «В любое время, когда вы сопоставляете свойство DateTime с источником в свойство DateTime в конечном месте, используйте этот преобразователь»?

Я просмотрел тесты AutoMapper и не видел ничего, что сработало бы.

Спасибо!

    
задан Darrell Mozingo 14.04.2011 в 18:22
источник
  • Это отличный вопрос, и я это будет общим требованием. Мне не повезло, что я попытался выполнить это в ответ на ответ Джимми. Кто-нибудь знает о рабочем примере? –  Rob Bowman 22.07.2015 в 12:57

1 ответ

14

Да - но с небольшим изменением порядка MapperRegistry. Сначала создайте конвертер типов от DateTime до DateTime:

Mapper.CreateMap<DateTime, DateTime>().ConvertUsing<CompanyTimeConverter>();

Код вашей компанииTimeConverter выглядит так же, как и у распознавателя значений, кроме того, что он наследует от TypeConverter.

Затем вам нужно изменить порядок MapperRegistry (я собираюсь изменить это в будущем, это имеет смысл):

MapperRegistry.AllMappers = () => new IObjectMapper[] {
    new DataReaderMapper(),
    new TypeMapMapper(TypeMapObjectMapperRegistry.AllMappers()),
    new StringMapper(),
    new FlagsEnumMapper(),
    new EnumMapper(),
    new ArrayMapper(),
    new EnumerableToDictionaryMapper(),
    new DictionaryMapper(),
    new ListSourceMapper(),
    new CollectionMapper(),
    new EnumerableMapper(),
    new TypeConverterMapper(),
    new AssignableMapper(),
    new NullableMapper()
};

Первоначально, «Assignable» mapper появился перед преобразователем TypeConverter, так что, если бы два типа были назначены друг другу, он просто сделал бы это.

    
ответ дан Jimmy Bogard 15.04.2011 в 15:27
  • Удивительно, спасибо Джимми! Мне действительно не нужно было менять порядок MapperRegistry, чтобы заставить его работать. Я запускаю AutoMapper 1.1.0.188. –  Darrell Mozingo 15.04.2011 в 20:20
  • есть ли способ сделать это на уровне профиля? Я не думаю, что изменения в MapperRegistry могут быть изолированы –  chester89 16.10.2012 в 08:47
  • Что делать, если вы используете AutoMapper для сопоставления как объекта, так и модели, а затем обратно из модели представления в объект (например, при редактировании объекта)? Как вы можете сказать AutoMapper только для отображения в одном направлении или для использования ConvertFromUtc в одном направлении и ConvertToUtc в другом? –  Farinha 24.10.2014 в 18:23
  • @Jimmy Bogard: Как создать карту для перечисления. В случае IQueryable. –  Hemant Malpote 09.01.2015 в 09:19