У меня есть проект, который написан на C#
поверх платформы ASP.NET MVC 5. Я использую AutoMapper , чтобы динамически отобразить модель представления в модель объекта и наоборот.
Все свойства DateTime в модели объекта находятся в часовом поясе UTC, где свойства DateTime в моих моделях представления находятся в локальном часовом поясе пользователя, вошедшего в систему.
Когда я сопоставляю модель объекта с моделью представления, мне нужно преобразовать DateTime из часового пояса UTC в зарегистрированный локальный часовой пояс пользователя. Для стандартизации процесса преобразования времени у меня есть класс обслуживания, который обрабатывает преобразование времени, который называется DateTimeConverter
. Класс преобразователя имеет зависимости, и его методы не являются статически вызываемыми.
Обычно у меня есть класс mapper / factory, который позволяет мне группировать процесс, который создает объект, в одно место.
Вот пример моего класса картостроителя / фабрики
public CategoryMapper
{
private IMapper Mapper;
private IDateTimeConverter TimeConverter;
private ICategoryService CategoryService;
// There services are auto injected from the IoC
public MapperService(IMapper mapper, IDateTimeConverter timeConverter, ICategoryService categoryService)
{
Mapper = mapper;
TimeConverter = timeConverter;
CategoryService = categoryService;
}
public ListCategoriesViewModel GetListCategoriesViewModel()
{
var viewModel = new ListCategoriesViewModel();
// Use AutoMapper to create the viewmodels
var categories = Mapper.Map<List<DisplayCategoryViewModel>>(CategoryService.GetAll());
// I am trying to avoid having to do this loop each time...
// Hoping that somehome this can be adding in tho the previous call
// or add some kind of converter to AutoMapper to call TimeConverter.UtcToLocal on ALL DateTime properties
categories.ForEach(category =>
{
category.CreatedAt = TimeConverter.UtcToLocal(category.CreatedAt);
category.UpdatedAt = TimeConverter.UtcToLocal(category.UpdatedAt);
});
ViewModel.Categories = categories;
return viewModel;
}
}
Вот мой DisplayVategoryViewModel
класс
public class DisplayCategoryViewModel : IMapFrom
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
...
...
public void Map(IMapperConfigurationExpression expression)
{
// This method is called from the mapping profile when the app starts using reflection
// This way I can keep the mapping rules close to my viewmodel instead of having to move
// these rules into the mapper class directly.
// It is much easier to have the rules and the object in the same place when adding or renaming properties
expression.CreateMap<Category, DisplayCategoryViewModel>()
.ForMember(viewModel => viewModel.Name, opts => opts.MapFrom(model => model.Title));
}
}
Как вы можете видеть выше, я сначала вызываю Mapper.Map<List<DisplayCategoryViewModel>>
, чтобы сообщить AutoMapper для сопоставления объекта с использованием сопоставленного профиля. Но сопоставленный профиль не знает, что свойства DateTime должны быть преобразованы с использованием реализации IDateTimeConverter
. Таким образом, все значения DateTime отображаются как есть, что означает, что они все еще находятся в UTC TimeZone. Чтобы преобразовать значения DateTime, я вызываю метод ForEach
, который повторяет все записи, чтобы исправить свойства DateTime.
Кроме того, все мои модели ViewModel являются простыми DTO, поэтому я не хочу добавлять туда никакой логики. Я не хочу вставлять что-либо в конструктор любого из моих кодов неисправности.
Я надеюсь, что мне удастся добавить какое-то правило в конфигурацию Mapping, чтобы оно могло преобразовать любое свойство DateTime в UTC или в местный часовой пояс. Или передайте обратный вызов Mapper.Map<>()
, чтобы я мог передать пользовательскую логику, которая применяется во время процесса сопоставления, чтобы избежать необходимости создавать еще один цикл для сопоставленных записей.