2010-09-29 3 views
4

Контекст: создание интеллектуального клиентского приложения на платформе .NET, где у вас есть сложная модель базы данных с большим количеством задействованных столбцов. Естественный стиль приложения - типичный CRUD, управляемый данными. В некоторых случаях также есть справедливая битвая логика на стороне сервера и несколько сложные проверки. У вас есть полный контроль над клиентом и сервером, поэтому потребность в интероперабельности минимальна.


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


Еще несколько предположений
- Как не редкость в мире Microsoft, большинство предыдущих приложений были написаны с DataSets, так что это самая известная технология для разработчиков, участвующих. Но скажем, разработчики хорошо разбираются в мышлении ОО.
- Вам нужно будет выполнить проверки как на клиенте, так и на сервере.
- Вы не показываете большинство данных в табличной форме.
- Это не приложение для интрасети, поэтому вы не можете слишком много думать о пропускной способности


Самый большой вопрос: Наборы или объекты?Вопросы, связанные с распределенным распределенным распределенным .NET-архитектурой в CRUD-стиле


Если вы идете для наборов данных у вас есть несколько позитивов и негативов
- С точки зрения позитивов: Вы получаете немного поддержки Microsoft с точки зрения получения данных из базы данных, получение данные по сети и возврат измененных данных по сети в меньших частях - поскольку вы можете указать только для отправки изменений. Отправка меньших данных является хорошей, так как потенциально довольно много данных.
- Отрицательные стороны: с точки зрения валидации, бизнес-логики и т. Д. Вы получаете процедурную форму кода, и вы не получаете преимущества объектно-ориентированного кода - поведение и данные вместе, более естественный стиль работы и думая о том, что вы делаете, и, возможно, ближе к логике проверки. Вы также можете отвлечься от возможности размещения набора данных в сетке, поскольку это не обычный вариант использования.

Если вы идете на объекты, это же упражнение, но есть еще варианты включали:
Положительных: поведение и данные вместе. Логика проверки ближе. Легче видеть и понимать отношения между объектами. Более читаемый код. Простота тестирования. Но есть довольно много вариантов и работать, вы должны сделать так:


ИЛИ/Mapping
- Получение данных из реляционной модели к объектам. OR-mappers не так сложны и смогут справиться с этим. Но это добавляет к времени разработки.


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


Общий код
- Вы можете пойти для общего сценария кода, где сборка с данными домена и логика доступна как на клиенте, и на стороне сервера. Это жесткая связь, но это не обязательно плохо, когда у вас есть естественно тесно связанное приложение клиент-сервер.


Если вы выбираете добавление слоя контракта или нет, у вас есть большие структуры объектов, которые должны быть отправлены по проводу Поскольку мы контролируем как клиент, так и сервер, транспорт и кодирование должны быть бинарным кодированием по TCP. Это поможет. С наборами данных вы можете только отправить изменения обратно. Вероятная проблема с передачей всей структуры объекта назад и вперед. Опция отправки всей структуры объекта - это как-то идентифицировать связанные изменения (Create, Update, Delete) и отправлять только информацию об этом. Теоретически не так уж сложно отправить агрегированный корневой идентификатор на сервер, а также изменения, попросить сервер ленить загрузить агрегатный корень, выполнить сделанные изменения и затем снова сохранить. Но большая сложность связана с выявлением сделанных изменений. Вы когда-нибудь идете на этот подход? Зачем? Как именно вы это делаете?

Презентация
Точная технология UI не так уж важно для вопроса, WinForms, Silverlight или WPF возможно. Предположим, что мы используем WPF, так как это новый смарт-клиент. Это означает, что мы имеем двустороннюю привязку и можем использовать MVVM правильно.

Объектам, связанным в пользовательском интерфейсе, необходимо реализовать INotifyPropertyChanged и поднять событие каждый раз при обновлении свойства. Как вы это решаете? Если вы собираетесь использовать сценарий с общим кодом, вы можете добавить его в объекты домена, но это будет включать добавление кода и логики на стороне сервера, которые никогда не должны использоваться там. Разделение более естественно, если вы идете на контрактные объекты, но это не так много добавленной стоимости, просто чтобы добавить слой отображения.

Technologies
Есть несколько технологий, которые могут помочь при решении некоторых вопросов, но часто осложняют другие. Вы используете их или сами строите вещи?
**
- CSLA возможен, но он усложняет тестирование устройства и, похоже, упрощает связь с доступом к данным. Это помогает с рядом проблем, но лично у меня нет компетенции в этой технологии, так что это очень удобно, это сложно сказать.
- Услуги WCF RIA могут быть доступны для решения Silverlight, но есть определенные ограничения. Размер данных - один.
- WCF Data Services - это еще один способ получить что-то быстро, но REST не очень помогает, и вам также не хватает поддержки валидации в службах RIA.

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


Update

Спасибо за ответы, ребята! Я пытался задать вопрос достаточно открытым, чтобы открыть для разных ответов, но достаточно конкретный, чтобы иметь дело с несколькими нестандартными требованиями.

Существуют разные соображения, имеющие разные плюсы и минусы, которые варьируются от системы к системе. Каждый из них обычно усложняет поиск решения. Один из пунктов этого вопроса состоял в том, чтобы получить ответы особенно с несколькими дополнительными требованиями, которые не обязательно подходят непосредственно к одному ответу, который часто является правильным сегодня - с пользовательским интерфейсом на основе задач. Я не «CRUD-парень», если хотите. Но несколько систем, по разным причинам (чаще всего устаревшие), хорошо подходят для CRUD.

Многие бизнес-приложения имеют аналогичные требования, которые тянут в разные стороны:

Бизнес связанные
- Вид: Отображение данных для пользователя и обновления одни и те же данные (читает и жвачки - Create, Update, Delete)
- Проверка: Бизнес правило

, связанные с UI
- Проверка: правила UI
- обновление пользовательского интерфейса: код, специфичный для просто получить интерфейс для обновления на изменениях объекта (INotifyPropertyChanged)

сети связанной
- размера данных: Объем данных, вы отправляете по проводам

DB связанных
- Ленивая загрузка

SRP/повторное использование связанного
- Mapping: Вызванные несколько слоев объектов/разделяющие вопросы

Техническое обслуживание/изменение
- Изменения: Добавление новой информации (столбцы/поля)
- количество кода
- Повторное использование и «причины для изменения»

Технические limitions
- отслеживание изменений

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

Если я попытаюсь обобщить кое-что для большинства ситуаций, я бы сказал что-то вроде:

Client
- Использование MVVM для разделения и контролируемости
- Создайте виртуальную машину на вершине DTOS
- Реализовать INotifyPropertyChanged в виртуальной машине.
- Использование XamlPowerToys, PostSharp или некоторые другие способы помочь с этим может быть полезным
- Отдельные Считывает и жвачек в пользовательском интерфейсе
- Сделать жвачек задачу на основе, а также использовать команды или аналогичные для отправки этих операций на стороне сервера

Сервер
- Индивидуальные сделать DTO за экран
- или использовать подход мульти-запросов, описанный Ayende в http://msdn.microsoft.com/en-us/magazine/ff796225.aspx
- Использование Автоотображение, чтобы избежать утомительной, ручной и никак не связано с проблемой, которую вы пытаетесь решайте шаг, это сопоставление
- Пусть модель предметной области будет связана с бизнесом-операциями, в первую очередь, в том числе жвачки, связанные с операциями, а не читает
- Избегай повторную, что добавляет к ряду причин, чтобы изменить
- избежать проблем капсулирования
- (и что включить CQRS архитектуру стиля и, возможно, отдельное масштабирование чтения и жвачку во время)
- Попробуйте найти подход проверки, который хорошо вписывается в то, что должно быть сделано (хорошо читать: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/02/15/validation-in-a-ddd-world.aspx)

Является ли это ваш провайдер блокирует подход, который я бы в этой конкретной ситуации?

Ну, вот что я хотел начать обсуждение :) Но кажется, что это было тяжелее, чем я надеялся (помимо вас двоих).

ответ

1

Интересная проблема :)

Если вы начинаете с несколькими принципами:

  • Попробуйте уменьшить объем данных, передаваемых по проводам
  • Постарайтесь свести к минимуму количество времени, потраченное на написание сантехнические код
  • Попробуйте улучшить тестируемость

Исходя из этого, я бы:

  • Используйте объекты POCO для передачи данных. DataSets включают в себя много информации, которая не может понадобиться
  • Использования Entity Framework ПОКА для доступа к базе данных, экономит ваше отображение из контракта объектов для данных объектов
  • Места проверки в вспомогательных классах, легко проверить, и поддерживает общий код модель

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

на стороне сервера и на стороне клиента объекты, которые вы могли бы попробовать:

  • Клиентская объект наследует стороне сервера объекта и реализации INotifyPropertyChanged
  • Поместите на стороне клиента и на стороне сервера объект в DLL отдельной это тот путь на сервере нет неиспользуемого кода
  • использовать Automapper для сопоставления между двумя типами.(может быть лучший способ использования интерфейсов)
+0

Я, конечно же, не согласен с принципами :) Но особенно роль в том, что иметь довольно много данных, должна быть частью этой проблемы. Да, наборы данных включают отправку большего количества данных, чем объектная модель, и лично мне не нравится переход к набору данных, но у нее есть удобная функция только отправки изменений после изменения (= намного меньше данных). Не то, чтобы это была функция убийцы, но что-то подобное было бы хорошо для объектной модели, где путь команд не является действительно вариантом. –

+0

Вы можете попробовать объекты самообслеживания в инфраструктуре Entity http://blogs.msdn.com/b /efdesign/archive/2009/03/24/self-tracking-entities-in-entity-framework.aspx, это промежуточная точка между DTO и DataSets. –

7

Я могу ответить только по собственному опыту. Мы пробовали разные структуры (WCF RIA, Ideblade) и пришли к выводу, что рамки только ухудшат ситуацию. Я объясню дальше.

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

Я не рекомендую отображать весь объект-граф на стороне клиента. Это две отдельные проблемы.

Вы должны создать индивидуальные Dto для каждого контекста. Например. допустим, у вас есть OrderSearchView, тогда вы создадите OrderSearchDto и нанесите только нужные поля. В EditOrderView вместо этого вы должны использовать EditOrderDto - который содержит только нужные вам поля.

Я бы не рекомендовал использовать инструмент автонастройки между объектами и dto. Потому что часто нет взаимно-однозначного отношения между dto и сущностью. Dto часто строится различными несколькими объектами бэкэнд. В любом случае сопоставление настолько простое, поэтому я не вижу смысла в структуре отображения. И работа не является сопоставлением - она ​​записывает единичный тест, который вам все равно придется делать (с картой отображения или без него).

Dtos должен быть агностик относительно технологии клиентской стороны. И внедрение INotifyPropertyChanged на dto нарушает принцип единой ответственности. Существует resion, они называются Data Transfer Objects. Вместо этого вы создаете докладчиков на стороне клиента. Вы создаете EditOrderPresenter, который является оберткой вокруг EditOrderDto. Таким образом, dto будет просто частным полем пользователя внутри EditOrderPresenter. Презентатор предназначен для редактирования на клиентском уровне - поэтому он обычно реализует INotifyPropertyChanged. EditOrderPresenter обычно имеет те же имена свойств, что и dto.

Вы должны физически отделить проверку клиента от проверки сущности на стороне сервера. Остерегайтесь доли! Я думаю, что проверка клиента - это просто настройка графического интерфейса пользователя - чтобы улучшить работу gui. Не делайте большого смысла иметь общий код проверки между dto и сущностью - это может вызвать большую головную боль, чем полезность. Просто убедитесь, что вы всегда проверяете на стороне сервера независимо от того, какая проверка выполняется на стороне клиента. Существует два типа валидаций: простая проверка свойств и проверка целостности всего объекта (то же самое относится к dto). Аутентификация объекта должна выполняться только при переходе состояния. Ознакомьтесь с Jimmy Nilssons Domain Driven Design для получения базовых знаний. Я бы не рекомендовал использовать механизм правил проверки - просто используйте шаблон состояния.

Тогда как насчет обновлений, вставок, удалений? В наших реализациях мы используем WCF, а API WCF имеет только один метод: IResponse [] Process (параметры IRequest []); Что это значит? Это означает, что клиент выдает пакет запросов на сервер. На сервере вы реализуете RequestHandler для каждого запроса, который определен в системе. Затем вы возвращаете список ответов. Убедитесь, что метод Process() - это одна единица работы (~ одна транзакция). Это означает, что если один из запросов в пакете завершится неудачно - все они потерпят неудачу - и это приведет к откату транзакции - и никакого вреда для db не будет. (Не используйте коды ошибок в обработчиках ответов - исключение исключений вместо.)

Я бы порекомендовал вам заглянуть в сервер обмена сообщениями Agatha. Дэви Брион имеет отличные блог-посты о слое обмена сообщениями. В нашей компании мы решили реализовать собственный сервер обмена сообщениями, потому что нам не нужно было все, что предлагал Агата, мы сделали некоторые улучшения синтаксиса. Во всяком случае, внедрение сервера обмена сообщениями не очень сложно - и это хороший опыт обучения.Ссылка http://davybrion.com/blog/

Тогда что вы будете делать с Dto's. Ну, вы никогда не обновляете их, но вы меняете их на стороне клиента, чтобы получить правильную обратную связь с gui. Итак, вы делаете докладчиков отслеживать все, что происходит с dto (reqest) - в правильном порядке. Это будет ваш requestBatch. Затем отправьте requestbatch команде процесса в WCF - тогда запросы будут «переиграны» на сервере и обработаны обработчиками запросов. Это на самом деле означает, что вы никогда не обновляете dto. Но ведущие могут отредактировать dto на стороне клиента, чтобы дать правильную обратную связь с gui. Задача докладчиков также заключается в том, чтобы отслеживать все сделанные изменения, чтобы вернуть их на сервер как requestbatch (с запросами в том же порядке, в каком они редактируются). Подумайте о следующем сценарии, вы получите существующий заказ, который вы редактируете, затем вы вносите изменения обратно в db. Это приведет к двум партиям: одному для получения ордера и одному для внесения изменений назад.
RequestBatch 1: GetOrderByIdRequest

(..то пользователь редактирует данные ..)

ReqeuestBatch 2:
StartEditOrderRequest, состояние изменить, чтобы изменить модус, расслабленный проверки
AddConsigneeToOrderRequest
ChangeEarliestETDOnOrderRequest, нет необходимости в валидации, но еще не все!
DeleteOrderlineRequest
ChangeNumberOfUnitsOnOrderlineRequest
EndEditOrderRequest, состояние изменения в исходное состояние, выполнить проверку сущности здесь!
GetOrderByIdRequest, чтобы обновить gui с последними изменениями.

На обслуживании мы используем NHibernate. Nhibernate использует кеш первого уровня, чтобы избежать тяжелой нагрузки db. Таким образом, все запросы в одном и том же блоке (requestbatch) будут использовать кеш.

Каждый запрос должен содержать только минимальный объем данных. Это означает использование OrderId + некоторых других свойств вместо целого dto. Что касается оптимистического обновления, вы можете отправить некоторые из старыхValues ​​вместе с запросом - это называется набором параллелизма. Помните, что набор параллелизма обычно не содержит много полей. Поскольку порядок обновления, который был изменен в то же время, не обязательно означает, что у вас будет условие повышения. Например. добавление и упорядочение, в то время как получатель был отредактирован другим пользователем, не означает, что у вас есть условие повышения.

Ну, это не приводит к ужасной работе. У вас, конечно, будет намного больше уроков, но каждый класс будет небольшим и будет нести ответственность.

BTW мы пробовали услуги WCF RIA в проекте среднего размера. И это не так хорошо. Нам нужно было найти способы (хаки) вокруг рамки, чтобы делать то, что мы хотели. И это также основано на генерации кода, что довольно плохо для сервера сборки. Кроме того, вы никогда не должны делать видимость через слои. Вы должны иметь возможность изменять поддерживаемые объекты, не затрагивая клиентский уровень. С RIA это очень сложно. Я думаю, что OData относится к той же категории, что и WCF RIA.

Если вам нужно создавать запросы на стороне клиента, вы используете шаблон спецификации - не используйте iqueryable - тогда вы будете независимы от бэкэнд-объектов.

Удачи.
twitter: @lroal

Смежные вопросы