Лучший способ заполнить SelectList для ViewModel на GET / POST - PullRequest
3 голосов
/ 30 сентября 2011

У меня есть следующая модель представления:

public class EditViewModel
{
    public int FooType { get; set; }
    public IEnumerable<SelectListItem> FooTypes { get; set; }
}

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

public ActionResult Edit(int id)
{
    EditViewModel model = new EditViewModel();
    model.FooTypes = new SelectList(repository.GetFooTypes(), "Id", "Value");

    return View(model);
}

Когда я создал действие для POST значений, мне пришлось повторить тот же код:

public ActionResult Edit(int id, EditViewModel model)
{
    if( !ModelState.IsValid )
    {
        model.FooTypes = new SelectList(repository.GetFooTypes(), "Id", "Value");

        return View(model);
    }

    return RedirectToAction("Index");
}

Мне не нравится иметь этот код в двух разных местах. Есть ли распространенная практика рефакторинга этого в одном месте, поэтому мне не нужно повторять этот код?

Ответы [ 3 ]

1 голос
/ 30 сентября 2011

Учитывая, что c # является объектно-ориентированным языком, существует множество доступных опций.

Самым простым было бы просто обернуть его в метод внутри контроллера:

private SelectList GetFooTypesList()
{
    return new SelectList(repository.GetFooTypes(), "Id", "Value);
}

и звоните при настройке вашей модели

или если вы используете его в нескольких классах, вы можете создать вспомогательный метод в другом классе, который принимает хранилище или IEnumerable в качестве параметра.

Если вы хотите по-настоящему продвинуться, вы можете использовать ModelFactory для создания модели FooType для вас с предварительно заполненным свойством FooType, чтобы контроллеру вообще не приходилось об этом беспокоиться.

Есть много вариантов, вам просто нужно выбрать тот, который подходит вам лучше всего.

Мое личное предпочтение - простой вспомогательный метод в контроллере.

0 голосов
/ 30 декабря 2011

В ответе "nekno" (отвечено 30 сентября в 22:19) есть две альтернативы ViewModel, которая либо возвращает IEnumerable , либо IEnumerable.».Обе эти альтернативы используют репозиторий, но без его фактического создания, поэтому я хотел бы немного расширить пример кода и выбрать второй вариант, то есть класс со свойством, типизированным IEnumerable.':

using Microsoft.Practices.ServiceLocation; // ServiceLocator , http://commonservicelocator.codeplex.com/
using MyOwnRepositoryNameSpace; // IRepository
public class EditViewModel
{
    public int? FooType { get; set; }

    public IEnumerable<int?> FooTypes
    {
        get
        {
            return Repository.GetFooTypes();
        }
    }

    private IRepository Repository
    {
        get
        {
            return ServiceLocator.Current.GetInstance<IRepository>();
        }
    }   
}

Код вышеупомянутого типа с «Поиск зависимости» теперь использует зависимость от библиотеки третьей части, в данном случае библиотеки Common Service Locator.

MyВопрос в том, как заменить вышеприведенный код на «Внедрение зависимостей»?Сама ViewModel действительно очень проста в реализации, просто так:

using MyOwnRepositoryNameSpace; // IRepository
public class EditViewModel
{
    private readonly IRepository _repository;

    public EditViewModel(IRepository repository) 
    {
        _repository = repository;
    }

    public int? FooType { get; set; }

    public IEnumerable<int?> FooTypes
    {
        get
        {
            return _repository.GetFooTypes();
        }
    }
}

Проблема в том, как заставить ViewModel внедриться с реализацией, когда среда ASP.NET MVC будет создавать экземпляр EditViewModel'и отправьте его в качестве параметра в метод Action, такой как сигнатура метода tihs:

public ActionResult Edit(int id, EditViewModel model)  {
// How do we make the framework instantiate the above 'EditViewModel' with an implementation of 'IRepository' when the Action method is invoked ???

Официальный учебник MVC, по-моему, не дает какого-либо приятного решения.В разделе «Обработка изменений» (методы «public ActionResult Edit (...)») на страницах ниже они дублируют создание параметров аналогично тому, как это делается в постере этого вопроса stackoverflow, который вы сейчас читаете.

http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-5

http://mvcmusicstore.codeplex.com/SourceControl/changeset/view/d9f25c5263ed#MvcMusicStore%2fControllers%2fStoreManagerController.cs

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

Итак, кто-нибудь может предоставить ссылку на полный рабочий пример с ASP.NETКод MVC 3, который позволяет внедрить средство извлечения данных в конструктор модели представления, который создается платформой и отправляет в качестве параметра в метод действия?

Обновление 2012-01-01 :Для тех, кто заинтересован в решении этого конкретного вопроса о внедрении конструктора экземпляра ViewModel, когда инфраструктураоценивает его и отправляет в качестве параметра параметра метода действия MVC. Я создал новый вопрос с более конкретной темой и, следовательно, более вероятно, что кто-то с решением найдет его и отправит хороший ответ: Внедрение в конструкторэкземпляра модели представления, используемого в качестве параметра метода Action

0 голосов
/ 01 октября 2011

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

Модель, где вам нужен обнуляемый тип для FooType:

public class EditViewModel
{
    public int? FooType { get; set; }
    public IEnumerable<SelectListItem> GetFooTypes(object selectedFooType = null)
    {
        return new SelectList(repository.GetFooTypes(), "Id", "Value", selectedFooType);
    }
}

Контроллер «Get», где вам нужно сначала создать модель, чтобы обеспечить* Представление Model доступно в представлении:

public ActionResult Edit(int id)
{
    EditViewModel model = new EditViewModel();

    return View(model);
}

Представление (без Barbara Wawa):

@Html.DropDownListFor(m => m.FooType, Model.GetFooTypes(Model.FooType))

Альтернатива, которая убирает «представление» измодель может выглядеть так:

Модель:

public class EditViewModel
{
    public int? FooType { get; set; }
    public IEnumerable<int?> FooTypes
    {
        get
        {
            // declare/define repository in your model somewhere    
            return repository.GetFooTypes();
        }
    }
}

Вид:

@Html.DropDownListFor(m => m.FooType, new SelectList(Model.FooTypes, "Id", "Value", Model.FooType))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...