Использование моделей представления в ASP.NET MVC 3 - PullRequest
17 голосов
/ 15 марта 2011

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

Я помещаю всю информацию, необходимую представлению, в модель представления. Вот пример - прошу прощения за любые ошибки, это закодировано на макушке моей головы.

public ActionResult Edit(int id)
{
    var project = ProjectService.GetProject(id);

    if (project == null)
        // Something about not found, possibly a redirect to 404.

    var model = new ProjectEdit();
    model.MapFrom(project); // Extension method using AutoMapper.

    return View(model);
}

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

[HttpPost]
public ActionResult Edit(int id, ProjectEdit model)
{
    var project = ProjectService.GetProject(id);

    if (project == null)
        // Something about not found, possibly a redirect to 404.

    try
    {
        if (!ModelState.IsValid)
            return View(model) // Won't work, view model is incomplete.

        model.MapTo(project); // Extension method using AutoMapper.
        ProjectService.UpdateProject(project);
        // Add a message for the user to temp data.

        return RedirectToAction("details", new { project.Id });
    }
    catch (Exception exception)
    {
        // Add a message for the user to temp data.

        return View(model) // Won't work, view model is incomplete.
    }
}

Мое временное решение - воссоздать модель представления с нуля, заново заполнить ее из модели предметной области, повторно применить к ней данные формы, а затем продолжить работу в обычном режиме. Но это делает параметр модели представления несколько бессмысленным.

[HttpPost]
public ActionResult Edit(int id, ProjectEdit model)
{
    var project = ProjectService.GetProject(id);

    if (project == null)
        // Something about not found, possibly a redirect to 404.

    // Recreate the view model from scratch.
    model = new ProjectEdit();
    model.MapFrom(project); // Extension method using AutoMapper.

    try
    {
        TryUpdateModel(model); // Reapply the form data.

        if (!ModelState.IsValid)
            return View(model) // View model is complete this time.

        model.MapTo(project); // Extension method using AutoMapper.
        ProjectService.UpdateProject(project);
        // Add a message for the user to temp data.

        return RedirectToAction("details", new { project.Id });
    }
    catch (Exception exception)
    {
        // Add a message for the user to temp data.

        return View(model) // View model is complete this time.
    }
}

Есть ли более элегантный способ?

EDIT

Оба ответа верны, поэтому я бы наградил их обоих, если бы мог. Однако кивнул МДж, так как после проб и ошибок я нашел его решение самым худшим.

Я все еще могу использовать помощников, Джимми. Если я добавлю то, что мне нужно, чтобы отобразить в сумке просмотра (или просмотреть данные), например, так ...

ViewBag.Project= project;

Тогда я могу сделать следующее ...

@Html.LabelFor(model => ((Project)ViewData["Project"]).Name)
@Html.DisplayFor(model => ((Project)ViewData["Project"]).Name)

Немного хак, и в некоторых случаях требуется, чтобы модель домена была украшена System.ComponentModel.DisplayNameAttribute, но я уже это делаю.

Я бы хотел позвонить ...

@Html.LabelFor(model => ViewBag.Project.Name)

Но динамика вызывает проблему в выражениях.

Ответы [ 2 ]

13 голосов
/ 15 марта 2011

После некоторого обучения методом проб и ошибок (он же кодирует, а затем ненавидит) мой предпочтительный в настоящее время подход:

Я использую только модели представления * для привязки полей ввода.Так что в вашем случае, если ваш вид редактирует только два поля, тогда ваша модель вида будет иметь только два свойства.Для данных, необходимых для заполнения представления (раскрывающиеся списки, метки и т. Д.), Я использую динамический ViewBag.

Я считаю, что отображение представления (т. Е. Заполнение всего, что необходимо отобразить в представлении), и захватопубликованные значения формы (привязка, проверка и т. д.) представляют собой две отдельные проблемы.И я нахожу, что смешивание данных, необходимых для заполнения представления с тем, что отправлено обратно из представления, становится беспорядочным и создает именно вашу ситуацию чаще, чем нет.Мне не нравятся частично населенные объекты, передаваемые вокруг.

Я не уверен, как это работает с Automapper (для сопоставления объекта домена с динамическим ViewBag), так как я не использовал его.Я считаю, что у него есть метод DynamicMap, который может работать?У вас не должно быть проблем с автоматическим отображением опубликованной строго типизированной ViewModel в объект Domain.

8 голосов
/ 15 марта 2011

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

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

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

Edit: Вы также можете принять другую модель представления в вашем действии Edit / POST, отличную от той, которую выполняет действие Edit / GET. Я считаю, что это должно работать до тех пор, пока модель связующего может понять это.

...