Должен ли сервисный уровень возвращать модели представления для приложения MVC? - PullRequest
61 голосов
/ 09 июня 2010

Допустим, у вас есть проект ASP.NET MVC и вы используете уровень обслуживания, например, в этом руководстве по диспетчеру контактов на сайте asp.net: http://www.asp.net/mvc/tutorials/iteration-4-make-the-application-loosely-coupled-cs

Если у вас есть модели представления для ваших представлений,Является ли сервисный уровень подходящим местом для предоставления каждой модели представления?Например, в примере кода уровня сервиса есть метод

    public IEnumerable<Contact> ListContacts()
    {
        return _repository.ListContacts();
    }

Если вместо этого вы хотели IEnumerable, он должен идти на уровне сервиса или есть где-то еще, что является «правильным» местом?

Возможно, более уместно, если у вас есть отдельная модель представления для каждого представления, связанного с ContactController, должен ли ContactManagerService иметь отдельный метод для возврата каждой модели представления?Если сервисный уровень не является подходящим местом, где должны быть инициализированы объекты viewmodel для использования контроллером?

Ответы [ 5 ]

47 голосов
/ 09 июня 2010

Как правило, нет.

Модели представлений предназначены для предоставления информации в представления и из представлений и должны быть специфическими для приложения, а не для общей области.Контроллеры должны координировать взаимодействие с репозиториями, сервисами (я делаю некоторые предположения об определении сервиса здесь) и т. Д. И обрабатывать построение и проверку моделей представлений, а также содержать логику определения представлений для визуализации.

По утечкамрассматривая модели в «сервисном» слое, вы размываете свои слои, и теперь у вас есть возможные приложения и особенности презентации, смешанные с тем, что должно быть сфокусировано на обязанностях на уровне домена.

25 голосов
/ 09 июня 2010

Нет, я так не думаю. Службы должны заботиться только о проблемной области, а не о представлении результатов Возвращаемые значения должны быть выражены в виде объектов домена, а не представлений.

21 голосов
/ 04 июля 2012

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

Но когда вы приступаете к реализации этого самостоятельно с помощью Entity Framework, MVC, Repository и т. Д., Тогда вы понимаете что-то еще.

Кто-то должен сопоставить модели Entity / DB с ViewModels (DTO упоминается в конце). Должно ли это быть сделано на [A] уровне пользовательского интерфейса (Контроллером) или на [B] уровне Сервиса?

Я выбрал вариант B. Вариант A - это нет, нет, потому что тот простой факт, что несколько моделей сущностей объединяются в одну ViewModel. Мы не можем передавать ненужные данные на уровень пользовательского интерфейса, тогда как в варианте B служба может воспроизводить данные и передавать только требуемый / минимум на уровень пользовательского интерфейса после сопоставления (в ViewModel).

Опять же, давайте перейдем к варианту A, поместим ViewModel на уровень пользовательского интерфейса (и модель сущностей на уровень Service).

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

Но что, если есть другое приложение пользовательского интерфейса, использующее этот сервис? Что делать, если есть мобильное приложение? Насколько может отличаться ViewModel? Должна ли Служба получать доступ к одному и тому же проекту модели представления? Будут ли все проекты пользовательского интерфейса иметь доступ к одному и тому же проекту ViewModel или у них есть свой собственный?

После этих соображений мой ответ будет состоять в том, чтобы поместить проект Viewmodel в Service Layer. Каждый уровень пользовательского интерфейса в любом случае должен иметь доступ к уровню сервиса! И может быть много похожих ViewModel, которые они все могут использовать (следовательно, отображение становится проще для уровня обслуживания). В наши дни сопоставления выполняются через linq, что является еще одним плюсом.

Наконец, есть обсуждение DTO. А также об аннотации данных во ViewModels. Модели представления с аннотациями данных (Microsoft.Web.Mvc.DataAnnotations.dll) не могут находиться на уровне службы, вместо этого они находятся на уровне пользовательского интерфейса (но ComponentModel.DataAnnotations.dll может находиться на уровне службы). Если все проекты находятся в одном решении (.sln), то не имеет значения, какой слой вы поместите. В корпоративных приложениях каждый уровень будет иметь свое собственное решение.

Таким образом, DTO на самом деле является ViewModel, потому что в большинстве случаев между ними будет отображаться один на один (скажем, с AutoMapper). Опять же, DTO по-прежнему обладает логикой, необходимой для пользовательского интерфейса (или нескольких приложений), и находится на уровне обслуживания. А слой пользовательского интерфейса ViewModel (если мы используем Microsoft.Web.Mvc.DataAnnotations.dll) предназначен только для копирования данных из DTO с добавлением некоторых «поведений» / атрибутов.

[Теперь эта дискуссия собирается принять интересный поворот, читайте дальше ...: I]

И не думайте, что атрибуты аннотации данных предназначены только для пользовательского интерфейса. Если вы ограничите проверку с помощью System.ComponentModel.DataAnnotations.dll затем тот же ViewModel также можно использовать для проверки внешнего интерфейса и внутреннего интерфейса (таким образом, удаляя UI-residing-ViewModel-copy-of-DTO). Более того, атрибуты также могут использоваться в моделях сущностей. Например: используя .tt, модели данных Entity Framework могут быть автоматически сгенерированы с атрибутами проверки для выполнения некоторых проверок БД, таких как максимальная длина, перед отправкой на серверную часть. Другое преимущество состоит в том, что если в БД изменяется внутренняя валидация, то .tt (читает специфику БД и создает атрибут для класса сущности) автоматически подхватит это. Это также может привести к сбою модульных тестов проверки пользовательского интерфейса, что является большим плюсом (поэтому мы можем исправить это и сообщить всем пользовательским интерфейсам / потребителям вместо того, чтобы случайно забыть и потерпеть неудачу). Да, обсуждение движется в направлении хорошего дизайна рамок. Как вы видите, все это связано: многоуровневая проверка, стратегия модульного тестирования, стратегия кэширования и т. Д.

Хотя это не имеет прямого отношения к вопросу.«ViewModel Façade», упомянутый в этом разделе, должен смотреть канал 9, ссылка также заслуживает изучения.Это начинается ровно в 11 минут 49 секунд в видео.Потому что это будет следующий шаг / мысль, как только ваш текущий вопрос, рассмотренный выше, будет рассмотрен: «Как организовать ViewModels?»

Также в вашем примере "_repository.ListContacts ()" возвращает ViewModel из хранилища.Это не зрелый путь.Хранилища должны предоставлять модели сущностей или модели БД.Это преобразуется в модели представления, и именно эта модель представления возвращается уровнем обслуживания.

5 голосов
/ 25 июля 2013

Это стало чем-то вроде «это зависит» от того, где я работаю - у нас обычно был контроллер, потребляющий некоторые услуги (и), - затем объединение возвращенных DTO в «ViewModel», которая затем передавалась бы клиенту - либо через результат JSON или связанный с шаблоном Razor.

Дело в том, что около 80% времени - отображение DTO на ViewModel было 1-1. Мы начинаем двигаться в направлении «Где необходимо, просто потреблять DTO напрямую, но когда DTO и то, что нам нужно в нашем клиенте / представлении, не совпадают - тогда мы создаем ViewModel и делаем сопоставление между объектами по мере необходимости».

Хотя я до сих пор не убежден, что это лучшее или правильное решение - поскольку в итоге оно приводит к некоторым горячим дискуссиям: «Мы просто добавляем X в DTO, чтобы удовлетворить потребности представления?»

5 голосов
/ 09 июня 2010

Полагаю, это зависит от того, что вы считаете "услугами".Мне никогда не нравился термин услуга в контексте одного класса;это невероятно расплывчато и мало что говорит о реальном назначении класса.

Если «уровень обслуживания» - это физический уровень, такой как веб-служба, то абсолютно нет;сервисы в контексте SOA должны раскрывать предметные / бизнес-операции, а не данные и не логику представления.Но если service просто используется в качестве абстрактной концепции для дальнейшего уровня инкапсуляции, я не вижу никаких проблем с его использованием так, как вы описываете.

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

...