Шаблон адаптера для моделей представления в Asp. net core MVC - PullRequest
1 голос
/ 14 марта 2020

В настоящее время я конвертирую ViewModels в объекты модели, а также наоборот. Я делаю это в контроллере, и иногда это может быть довольно большой объект со многими свойствами. Мне было интересно, если это плохая практика. Должен ли я создавать классы адаптеров для их преобразования, а затем просто использовать адаптер в контроллере.

Ниже приведен пример преобразования объекта ViewModel в объект модели в контроллере:

    public async Task<IActionResult> Register(RegisterViewModel registerModel)
    {
        if (ModelState.IsValid)
        {
            ApplicationUser user = new ApplicationUser
            {
                UserName = registerModel.Email,
                Email = registerModel.Email,
                FirstName = registerModel.FirstName,
                LastName = registerModel.LastName,
                AddressLine1 = registerModel.AddressLine1,
                AddressLine2 = registerModel.AddressLine2,
                City = registerModel.City,
                PostCode = registerModel.PostCode,
                PhoneNumber = registerModel.PhoneNumber,
                NotificationPreference = Enum.GetName(typeof(NotificationPreference), NotificationPreference.None)
            };
            await userManager.CreateAsync(user, registerModel.Password);
        }
        return View(registerModel);
    }

Итак, я должен создать ApplicationUser здесь или в классе адаптера.

Ответы [ 2 ]

1 голос
/ 14 марта 2020

Краткий ответ: Это зависит от количества вещей и определенных личных предпочтений.

Длинный ответ:

Для ответа на этот вопрос нам необходимо учитывать ряд факторов:

  1. Используют ли уже некоторые проекты в нашем решении конвертеры / адаптеры
  2. Насколько велико решение на данный момент
  3. Насколько большое решение будет
  4. Сколько существует моделей / моделей представления (будет)
  5. Как точно мы хотим следовать определенным шаблонам проектирования, таким как SOLID, разделение интересов и т. Д. c
  6. Наши личные предпочтения и опыт

Один простой вариант - добавить ctor или перегрузить оператор неявного приведения для каждой ViewModel:

public class ApplicationUser
{
    // Properties

    public ApplicationUser(RegisterModel registerModel)
    {
         UserName = registerModel.Email;
         Email = registerModel.Email;
         FirstName = registerModel.FirstName;
         // etc
    }

    //    OR:
    //    public static implicit operator ApplicationUser(RegisterModel) => 
              new ApplicationUser { UserName = registerModel.Email, ... };
}

Для крупных проектов и корпоративных проектов мы могли бы использовать AutoMapper или даже создайте наши собственные конвертеры для каждой парной модели -> viewmodel, однако я бы дважды подумал, прежде чем делать это.

0 голосов
/ 15 марта 2020

Используйте AutoMapper, это не так сложно.

Startup.cs ConfigureServices:

    var mappingConfig = new MapperConfiguration(mc =>
    {
        mc.AddProfile(new RegisterViewModelProfile());

    });

    IMapper mapper = mappingConfig.CreateMapper();
    services.AddSingleton(mapper);

Создайте класс RegisterViewModelProfile. (Я обычно помещаю их в соответствующий файл класса viewmodel, в вашем случае это файл RegisterViewModel.cs. Другие создают один MapperProfile.cs и помещают все классы Profile в этот файл, но из c вы можете создавать отдельные файлы для каждого. )

public class RegisterViewModelProfile : Profile
    {
        public RegisterViewModelProfile()
        {
            CreateMap<RegisterViewModel, ApplicationUser>()
                .ForMember(dest=>dest.UserName, opt=>opt.MapFrom(src=>src.Email))
                .ForMember(dest=>dest.NotificationPreference , opt=>opt.MapFrom(src=> Enum.GetName(typeof(NotificationPreference), NotificationPreference.None) ));
                //you dont need to map the other attributes because they have the same name and type in VM and in Model so AutoMapper does it automagically

            //you can map the other way around too if you need to the same way, and you can even do conditional mapping and/or overwrite data etc
            CreateMap<ApplicationUser, RegisterViewModel>()
                .ForMember(dest => d.Email, opt => opt.MapFrom(src => "Masked because of GDPR"));

        }
    }

В вашем контроллере введите маппер и сделайте маппинг, когда вам нужно сделать:

 public class JobsteplogsController : Controller
    {
        private readonly IMapper _mapper;

        public UserController(JobManagerContextCustom context, IMapper mapper)
        {
            _mapper = mapper;
        }
        public async Task<IActionResult> Register(RegisterViewModel registerModel)
        {
            if (ModelState.IsValid)
            {
                ApplicationUser user = _mapper.Map<ApplicationUser>(registerModel);

                await userManager.CreateAsync(user, registerModel.Password);
            }
            return View(registerModel);
        }

    }
...