Ответ 1
Если вы используете профили, вы можете разместить там все свои вызовы "CreateMap". Кроме того, вы можете создать статический класс начальной загрузки, который содержит вашу конфигурацию, а часть запуска просто вызовет загрузчик.
Я часто использую AutoMapper для сопоставления объектов Model (Domain) с объектами ViewModel, которые затем потребляются моими представлениями, в шаблоне Model/View/View-Model.
Это включает в себя множество операторов Mapper.CreateMap, которые все должны быть выполнены, но должны выполняться только один раз в жизненном цикле приложения.
Технически, тогда я должен хранить их все в статическом методе где-нибудь, который вызывается из моего метода Application_Start() (это приложение ASP.NET MVC).
Однако, кажется, неправильно группировать множество различных проблем отображения вместе в одном центральном месте.
Особенно, когда код сопоставления становится сложным и включает в себя форматирование и другую логику.
Есть ли лучший способ организовать код сопоставления, чтобы он находился близко к ViewModel, который это касается?
(Я придумал одну идею - имея метод CreateMappings на каждом ViewModel и в BaseViewModel, вызывая этот метод при создании экземпляра. Однако, поскольку метод следует вызывать только один раз в жизненном цикле приложения, ему нужно некоторое дополнительную логику для кэширования списка типов ViewModel, для которых был вызван метод CreateMappings, а затем только вызывать его, если необходимо, для ViewModels, которые не входят в этот список.)
Если вы используете профили, вы можете разместить там все свои вызовы "CreateMap". Кроме того, вы можете создать статический класс начальной загрузки, который содержит вашу конфигурацию, а часть запуска просто вызовет загрузчик.
Если вы действительно не хотите использовать загрузчик, то по крайней мере статический конструктор - это простой способ обеспечить, чтобы ваш CreateMap вызывался не более одного раза. (С меньшим количеством беспорядков и большей резьбой, чем ответ Джонатона.)
public class AccountController : Controller
{
static AccountController()
{
Mapper.CreateMap<Models.User, ViewModels.UserProfile>();
Mapper.CreateMap<Models.User, ViewModels.ChangePassword>();
}
}
ОК, как я это делаю сейчас:
Я добавляю некоторую логику в конструктор моего BaseController, который запускает метод CreateMappings, но только один раз для типа контроллера:
public abstract class BaseController : Controller
{
public BaseController()
{
if (!controllersWithMappingsCreated.Contains(GetType()))
{
CreateMappings();
controllersWithMappingsCreated.Enqueue(GetType());
}
}
protected virtual void CreateMappings() { }
}
В каждом конкретном контроллере я использую CreateMappings для объявления сопоставлений для всех моделей /ViewModels, относящихся к этому контроллеру.
public class AccountController : BaseController
{
public AccountController() : base() { }
protected override void CreateMappings()
{
Mapper.CreateMap<Models.User, ViewModels.UserProfile>();
Mapper.CreateMap<Models.User, ViewModels.ChangePassword>();
}
}
Я также нашел несколько интересных альтернатив с участием атрибутов здесь и здесь, однако они ударили меня как немного усложненный.