Надежный подход к загрузке справочных данных в модели представлений в ASP.NET MVC - PullRequest
2 голосов
/ 04 марта 2011

Мне нужен способ отделить загрузку эталонных данных в модель представления от контроллера.На данный момент у меня есть модель представления со свойством для выбранного значения и справочных данных:

public IEnumerable<SelectListItem> DayTypes { get; set; }
public int DayTypeId { get; set; }

, и данные заполняются из соответствующего репозитория в действии контроллера:

model.DayTypes = _dayTypeRepository.GetAll().ToSelectList(d => d.Description, d => d.Identifier.ToString());

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

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

Другой подход, который, на мой взгляд, был бы хорош, намекается на CodeCampServer , но он неполный и закомментирован с использованием атрибутов поля в модели представления:

[SelectListProvided(typeof(AllDaysSelectListProvider))]
public IEnumerable<SelectListItem> DayTypes { get; set; }

однако я изо всех сил пытаюсь выяснить, как это могло бы быть реализовано таким образом, чтобы не потребовалось какого-либо серьезного изменения структуры MVC.

Как вы решаете эту проблему?

РЕДАКТИРОВАТЬ: я хочу придерживаться строго типизированных представлений и избегать вставки данных в данные представления.

ДОПОЛНИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ: Мне также хотелось бы решение, которое идеально не зависит от модели, под которым я подразумеваюесли одни и те же справочные данные необходимы для нескольких моделей представлений, это может быть достигнуто с помощью одного фрагмента кода.Подход Мэтта интересен, но тесно связан с моделью представления.

Ответы [ 2 ]

3 голосов
/ 04 марта 2011

Я бы использовал сервисный слой, который вернул бы мне объект POCO, который я бы отобразил в модель представления.Таким образом, мое действие контроллера будет выглядеть так:

public ActionResult Index(int id)
{
    var model = _service.GetModel(id);
    var viewModel = Mapper.Map<Model, ViewModel>(model);
    return View();
}

Мне также нравится использовать фильтры действий, чтобы избежать повторного отображения кода так:

[AutoMap(typeof(Model), typeof(ViewModel))]
public ActionResult Index(int id)
{
    var model = _service.GetModel(id);
    return View(model);
}

Этоесли только служба взаимодействует с репозиториями CRUD, а контроллер взаимодействует со службой и уровнем отображения.

0 голосов
/ 04 марта 2011

Вы можете написать новый ActionFilter, которым вы можете украсить метод действия;этот фильтр действий загрузит справочные данные в данные представления, к которым вы можете получить доступ из своего представления.

Подробнее о фильтрах действий здесь .


РЕДАКТИРОВАТЬ: На основе комментариев пользователей теперь включается строго типизированный параметр.

Во-первых, вам нужно создать SharedViewModel для хранения общих данных.

public class SharedViewModel
{
  public List<string> Days { get; set; }
  public List<string> Months { get; set; }
  public List<string> Years { get; set; }
}

Далее мы создадим представлениемодель, которая будет использоваться представлением Index, которое использует эту модель общего представления.

public class HomeViewModel
{
  public string ViewName { get; set; }
  public SharedViewModel SharedViewModel { get; set; }
}

Важным является следующий шаг, он реализует фильтр действий SharedData (), который будет применять общие данные.

public class SharedDataActionFilter : ActionFilterAttribute
{
  public override void OnActionExecuted(ActionExecutedContext filterContext)
  {
    var currentModel = ((HomeViewModel) filterContext.Controller.ViewData.Model);

    currentModel.SharedViewModel = new SharedViewModel
    {
      Days = new List<string> {"Mon"},
      Months = new List<string> {"Jan"},
      Years = new List<string> {"2011"}
    };

    base.OnActionExecuted(filterContext);
  }
}

В данный момент он просто применяет все общие данные, но вы можете добавить параметры в метод для выбора.

Когда действие выполнено, этот метод принимает текущую модельи добавляет общие данные.

Вот действие контроллера.

[SharedDataActionFilter]
public ActionResult Index()
{
  return View("Index", new HomeViewModel { ViewName = "HomePage" });
}

Вы можете получить доступ к данным, как любое другое строго типизированное представление, и общие данные не будут влиять наданные уже в модели (в данном случае «ViewName»).Вы также можете использовать фильтры действий на контроллерах и по всему сайту с помощью mvc 3.

Надеюсь, это поможет, Мэтт.

...