Является ли абстрактный CRUD-контроллер хорошей идеей? - PullRequest
4 голосов
/ 14 июля 2009

Мы разрабатываем довольно большое приложение с использованием ASP.NET MVC, и в начале мы увидели, что было бы полезно иметь абстрактный базовый контроллер с общими действиями CRUD (new, save, delete ...) плюс список по умолчанию действие. В нашем случае у нас более 20 сущностей, которые управляются с помощью контроллеров такого типа.

Это работает и позволяет избежать дублирования некоторого кода и делает приложение более однородным, но когда вы видите контроллер, трудно понять, какие именно действия он выполняет, и он может реализовывать некоторые действия, которые не должны существовать. И, например, представьте, что вы хотите редактировать, передавая имя, а не идентификатор, вы должны создать новое EditByName (имя) и даже делать это, у вас все еще есть доступное действие Edit (id), потому что оно в базе.

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

Ответы [ 5 ]

3 голосов
/ 14 июля 2009

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

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

2 голосов
/ 14 июля 2009

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

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

protected ActionResult DisplayValidateAndEditModel<TModel>(TModel model, string modelPrefix,
                                        string editViewName, string successActionName, object routeValues, string successMessage,
                                        string[] includeProperties, bool acceptFiles
                                ) where TModel : class

и

protected ActionResult DisplayValidateAndEditModel<TModel>(TModel model, string modelPrefix,
                                        string editViewName, string successActionName, string successMessage,
                                        string[] includeProperties
                                ) where TModel : class

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

Оба метода проверяют, является ли это сообщение. Если нет, они возвращают вид. Если так:

  • редактировать вызывает TryUpdateModel, а также выполняет некоторую проверку xVal. Если все в порядке, он перенаправляет на successAction с любым routeValues. Если нет, он снова показывает вид. includeProperties можно передать так, чтобы мой контроллер мог точно указать, что может получать обновления. А acceptFiles добавляет дополнительные функциональные возможности, где ищет запись файла и, если она есть, помещает ее в базу данных и создает ссылку между записью файла и моделью.

  • delete обновляет свойства модели Cancel_Date и Cancel_User (у меня есть интерфейс ICancelable) и перенаправляет на успешное действие

1 голос
/ 14 июля 2009

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

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

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

Только вот: как вы знаете, ASP.NET MVC поддерживает базовые леса, такие как Ruby on Rails. Что вы можете рассмотреть, так это настроить файлы T4, используемые для создания представлений «Создать», «Обновить» и «Подробности», в соответствии с вашими конкретными потребностями.

http://blogs.msdn.com/webdevtools/archive/2009/01/29/t4-templates-a-quick-start-guide-for-asp-net-mvc-developers.aspx

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

Для меня все это немного пахнет ..

Тот же запах здесь: -)

Это обычная практика - иметь мало кода в контроллере. Его основная цель - решить, какой вид будет отображен с какой моделью следующим.

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

Попробуйте переместить логику в модель. Используйте фильтры и CustomModelBinder.

...