ModelFactory в ASP.NET MVC для решения проблемы RenderPartial - PullRequest
9 голосов
/ 13 марта 2009

Метод RenderPartial () в ASP.NET MVC обладает очень низким уровнем функциональности. Он не предоставляет и не пытается обеспечить истинную модель «субконтроллера» *.

У меня все больше элементов управления, отображаемых с помощью RenderPartial (). Они делятся на 3 основные категории:

1) Элементы управления, которые являются прямыми потомки конкретной страницы, которая использовать модель этой страницы

2) Элементы управления, которые являются прямыми потомки конкретной страницы, которая использовать модель этой страницы с дополнительный ключ какого-то типа . Думаю реализация 'DataRepeater'.

3) Элементы управления, которые представляют собой не связанные функциональность на странице они появляются на. Это может быть что угодно от ротатор баннеров, к форме обратной связи, поиск магазина, регистрация в списке рассылки. Ключевым моментом является то, что это не волнует на какую страницу он ставится.

Из-за того, как работает модель ViewData, существует только один объект модели на запрос - то есть все, что нужно субконтролю, должно присутствовать в модели страницы.

В конечном счете, команда MVC, как мы надеемся, выйдет с настоящей моделью «субконтроллера», но до тех пор я просто добавляю в модель главной страницы все, что также необходимо дочерним элементам управления.

В случае (3) выше это означает, что моя модель для «ProductModel» может содержать поле для модели «MailingListSignup». Очевидно, что это не идеально, но я принял это в лучшем компромиссе с существующей структурой - и с наименьшей вероятностью «закрою все двери» для будущей модели субконтроллера.

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

То, что я начал делать, - это создание фабрики для создания модели. Эта фабрика вызывается контроллером (модель не знает о фабрике).

public static class JoinMailingListModelFactory {

        public static JoinMailingListModel CreateJoinMailingListModel() {

            return new JoinMailingListModel()
            {
                MailingLists = MailingListCache.GetPartnerMailingLists();
            };
        }
    }   

Итак, мой актуальный вопрос: как другие люди с такой же проблемой создают модели. Какой будет лучший подход для будущей совместимости с новыми функциями MVC?


  • NB: Есть проблемы с RenderAction(), которые я не буду здесь рассматривать - не в последнюю очередь, это только в MVCContrib и не будет в RTM-версии ASP.NET-MVC. Другие проблемы вызвали достаточных проблем , которые я решил не использовать. Итак, давайте теперь притворимся, что существует только RenderPartial() - или, по крайней мере, это то, что я решил использовать.

Ответы [ 4 ]

5 голосов
/ 16 марта 2009

Вместо добавления таких вещей, как MailingListSignup в качестве свойства вашего ProductModel, инкапсулируйте оба на одном уровне в класс, подобный ProductViewModel, который выглядит следующим образом:

public class ProductViewModel() {
    public ProductModel productModel;
    public MailingListSignup signup;
}

Тогда сделайте ваш View строго типизированным в класс ProductViewModel. Вы можете получить доступ к ProductModel, позвонив по номеру Model.productModel, и получить доступ к классу регистрации, используя Model.signup.

Это слабая интерпретация «Модели представления» Фаулера (http://martinfowler.com/eaaDev/PresentationModel.html),, но я видел, что ее использовали некоторые разработчики Microsoft, такие как Роб Конери и Стивен Уолтер.

2 голосов
/ 13 марта 2009

Один из подходов, которые я видел в этом сценарии, заключается в использовании фильтра действий для заполнения данных для частичного представления, то есть подкласса ActionFilterAttribute. В OnActionExecuting добавьте данные в ViewData. Тогда вам просто нужно украсить различные действия, которые использует , это частичное представление с помощью фильтра.

1 голос
/ 13 марта 2009

Я использую перегрузку RenderPartial, которая позволяет вам указать новые ViewData и Model:

RenderPartial code

Если вы посмотрите на предыдущую ссылку исходного кода MVC, а также на следующую (ищите метод RenderPartialInternal):

RenderPartialInternal код

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

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

0 голосов
/ 08 июля 2009

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

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IMailingListSignup>" %>

Viewmodel реализует интерфейс

 public class ProductViewModel:IMailingListSignup

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

У вас все еще есть проблема с заполнением модели. Если не поздно, я предпочитаю делать это в OnActionExecuted. Я не вижу, как вы можете заполнить модель в OnActionExecuting.

...