Как получить данные для выпадающего списка в viewmodel при использовании AutoMapper / AutoMapViewResult

После прочтения ASP.NET MVC 2 в действии и просмотра презентации Джимми Богарда из MvcConf (оба настоятельно рекомендуется!), Я начал реализовывать некоторые из их идей.

Одна из замечательных вещей, которые они делают, - это не только использовать AutoMapper для сопоставления ваших сущностей с некоторой моделью представления, но и автоматизировать это с помощью AutoMapViewResult:

public class EventsController : BaseController
{
    public ActionResult Show(Event id) // EntityModelBinder gets Event from repository
    {
        return AutoMapView(id); // AutoMapView(model) is a helper method on the BaseController, that calls AutoMapViewResult(...)
    }
}

// not exactly what you'll find in the book, but it also works :-)
public class AutoMapViewResult : ViewResult
{
    public AutoMapViewResult(string viewName, string masterName, object model)
    {
        ViewName = viewName;
        MasterName = masterName;

        ViewData.Model = Mapper.Map(model, model.GetType(), typeof(TDestination));
    }
}

Это все прекрасно работает, но теперь есть действие Edit с его EventsEditModel :

public class EventsEditModel
{
    // ... some properties ...
    public int LocationId { get; set; }
    public IList Locations { get; set; }
}

public class EventsController : BaseController
{
    public ActionResult Edit(Event id)
    {
        return AutoMapView(id); 
    }
}

И теперь (наконец) вопрос:

Что вы думаете, это лучший способ получить местоположения из какого-либо источника данных, такого как репозиторий, в свойство EventsEditModel Locations ?

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

Обновление:

Я согласился с идеей Некроса и создал собственный атрибут. Вы можете посмотреть код и загрузить его в моем блоге ASP.NET MVC: загрузка данных для выбранных списков в модель редактирования с использованием атрибутов .

10
задан davehauser 19 August 2010 в 21:52
поделиться

3 ответа

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

public abstract class LoadDataAttribute : Attribute
{
    public Type Type { get; set; }

    protected LoadDataAttribute(Type type)
    {
        Type = type;
    }

    public abstract object LoadData();
}

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

public class LoadLocationsAttribute : LoadDataAttribute
{
    public LoadLocationsAttribute() : base(typeof(IList<SelectListItem>))

    public override object LoadData()
    {
        // get locations and return IList<SelectListItem>
    }
}

В вашем ExecuteResult из AutoMappViewResult вы бы нашли все свойства с LoadDataAttribute, вызвали LoadData(), привели его к типу, указанному в атрибуте, и присвоили его свойству.

Если вы хотите таким образом загружать списки выбора, вы можете просто вернуть IList вместо object и избавить себя от проблем с приведением.

Ваша модель представления, очевидно, будет использовать атрибут.

public class EventsEditModel
{
    // ... some properties ...
    public int LocationId { get; set; }

    [LoadLocations]
    public IList<SelectListItem> Locations { get; set; }
}
5
ответ дан 4 December 2019 в 01:29
поделиться

Я бы порекомендовал вам взглянуть на пример приложения asp.net-mvc из здесь , которое делает это намного проще, чем автомобильная бумага

Особенно посмотрите на TinyController

0
ответ дан 4 December 2019 в 01:29
поделиться

Хорошо, добавьте конструктор с параметром и свойством в ваш контроллер и используйте DI (лично мне нравится Ninject) для внедрения правильной реализации репозитория:

public IEventsRepository _repo;

public EventsController(IEventsRepository repository)
{
  _repo = repository;
}

Wire (привязка) зависимости вверху в global.asax.cs в приложении Ninject и модуле сайта (если вам нужен расширенный ответ с включенным включением, дайте мне знать),

затем в действии Edit используйте репозиторий, чтобы получить Locations . Предположим, у вас есть метод LoadLocations () в интерфейсе вашего репозитория и его конкретная реализация, например, в SqlEventsRepository (реализует IEventsRepository ), вы делаете это просто вызывая метод:

public ActionResult Edit(Event id)
{
...
EventsEditModel model = new EventsEditModel();
_repo.GetInstance(id);
model.Locations = _repo.LoadLocations();
...
}

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

Также вы не указываете, является ли это действие редактирования GET или POST , но я предполагаю, что это GET . Предполагая, что это действительно GET , я не знаю, как вы можете загрузить что-нибудь, предоставив Entity действию.

Чаще всего методы GET используют параметры типа string или int (скорее всего, это slugs или id некоторого вида), а методы POST используют параметры типа ViewModel (не Entity) .

Итак, подпись метода POST должна быть такой.

[HttpPost]
public ActionResult Edit(EventsEditModel model)...

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

HTH

-1
ответ дан 4 December 2019 в 01:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: