Подтвердить что ты не робот

Использование функций ViewModels для POST в MVC элегантно

В настоящее время я передаю свои объекты домена в свои представления и привязываю непосредственно к ним из POST. Все говорят, что это плохо, поэтому я пытаюсь добавить концепцию ViewModel.

Однако я не могу найти способ сделать это очень изящно, и я хотел бы знать, какие решения других людей не должны заканчиваться очень грязным действием контроллера.

типичный процесс для некоторых функций "добавить человека" выглядит следующим образом:

  • сделать запрос GET для представления, представляющего пустую модель просмотра Person
  • post back (in) действительные данные Контроллер
  • связывает опубликованные данные с моделью просмотра человека
  • Если сбой привязки, мне нужно выполнить то же действие, что и в (1), но с некоторыми данными, а не с пустым объектом и ошибками.
  • Если привязка завершилась, мне нужно отобразить свойства из виртуальной машины на реальную модель
  • проверить модель
  • если проверка прошла: сохранить человека, зафиксировать, сопоставить данные пользователей с виртуальной машиной отображения и вернуть ее в виде
  • Если проверка не выполнена, выполните те же действия, что и в (1), но с некоторыми данными и ошибками

Выполнение всего этого в действии контроллера (игнорирование GET), конечно же, не является SRP или DRY.

Я пытаюсь думать о способе нарушить этот процесс, чтобы он выполнял SRP, является чистым, модульным и, прежде всего, проверяемым.

Каковы решения людей для этого?

Я экспериментировал с пользовательскими обработчиками-action-invokers, чтобы разделить проблемы на отдельные методы, умные модели-строчки и просто грубую силу, но я еще не нашел решения в довольстве.

P.S. поскольку он добавляет столько сложностей, убедить меня, почему мне даже нужно беспокоиться

4b9b3361

Ответ 1

Я почувствовал такой же дискомфорт. Мой единственный способ сделать это:

  • Создание связующего для привязки и проверки модели представления
  • Создайте связующее, чтобы получить объект из базы данных (или просто сделать это в контроллере).
  • Вызов унаследованного метода сохранения в суперклассе. Этот метод принимает viewmodel и объект, который будет обновлен, и выполняет всю работу, указанную вами на ваших шагах.

Метод действия выглядит следующим образом:

public ActionResult Whatever(TViewModel viewModel, TEntity entity)
{
    return Save(viewModel, entity);
}

Базовый контроллер имеет общее определение, например:

public abstract BaseController<TEntity, TViewModel>
    where TEntity : Entity
    where TViewModel : ViewModel

Конструктор имеет две зависимости: одну для репозитория объектов и другую для сопоставления модели, например:

protected BaseController(IRepository<TEntity> repository, IMapper<TEntity, TViewModel> mapper)

После этого вы можете записать защищенный метод Save, который можно вызвать из действий контроллера в подклассе, например:

protected ActionResult Save(TViewModel viewModel, TEntity entity)
{
    if (!ModelState.IsValid)
        return View(viewModel);

    _mapper.Map(viewModel, entity);
    if (!entity.IsValid)
    {
        // add errors to model state
        return View(viewModel);
    }

    try
    {
        _repository.Save(entity);
        // either redirect with static url or add virtual method for defining redirect in subclass.
    }
    catch (Exception)
    {
        // do something here with the exception
        return View(viewModel);
    }
}

Что касается проверки, вы можете протестировать метод сохранения в действительных/недопустимых моделях и объектах просмотра. Вы можете протестировать реализацию mapper модели, действительное состояние модели представления и действительное состояние объекта отдельно.

Предоставив базовый контроллер общий, вы можете повторить этот шаблон для каждой компиляции entity/viewmodel в своем домене, если вы создаете множество контроллеров для выполнения того же самого.

Мне очень интересно услышать, что другие говорят об этом. Большой вопрос.

Ответ 2

Шаблон MVVM (ViewModel) определенно тот, на который нужно пойти, у меня был аналогичный вопрос о POSTing обратно к действию несколько дней назад - вот ссылка: MVVM и ModelBinders в ASP.NET MVC Framework

В результате вы можете использовать атрибут Bind, чтобы отправить обратно сложный тип, который вы хотите.

Ответ 3

У меня есть много хороших решений в приложении asp.net mvc sample, которое находится в загрузке valueinjecter (mapper, который я использую для отображения ViewModels в/из Entities, вы также можете отобразить FormCollection/Request to Entities)

здесь один:

    public class TinyController :Controller
        {
            private readonly IModelBuilder<Person, PersonViewModel> modelBuilder;

            public TinyController()
            {
                modelBuilder = new PersonModelBuilder();
            }

            public ActionResult Index()
            {
                return View(modelBuilder.BuildModel(new PersonRepository().Get()));
            }

            [HttpPost]
            public ActionResult Index(PersonViewModel model)
            {
                if (!ModelState.IsValid)
                    return View(modelBuilder.RebuildModel(model));

                   var entity = modelBuilder.BuildEntity(model);
...
//save it or whatever
            }
        }