Структура приложения с использованием WCF

У меня есть приложение WPF, которое до сих пор было только клиентским, но теперь я работаю над его разделением на клиентскую и серверную части. В этой работе я представляю WCF для взаимодействия клиент-сервер. В моем приложении несколько проектов, и требуются ссылки на службы более чем в одном из них.

Первоначальное усилие при разделении состоит в том, чтобы делать все «прямо вперед». Все проекты, которым необходимо взаимодействовать со службой, получают ссылку на службу, как и основной проект приложения WPF - чтобы получить там app.config. Я считаю, что это довольно быстро превращается в беспорядок, и я не могу представить, что это типичная архитектура, которую используют люди? Я также видел проблемы с тем фактом, что каждая из ссылок на сервисы генерирует новую реализацию классов DataContract - следовательно, нет общего понимания классов DataContract в перекрестных проектах. У меня есть несколько классов ViewModel в одном проекте, а в другом проекте создается экземпляр ViewModel. Я хотел бы передать объект, полученный от службы, но не могу, поскольку сгенерированное клиентское представление полученного объекта отличается в каждом проекте.

Итак, есть ли рекомендуемый способ структурирования такого разделения клиент / сервер с использованием WCF? Или принципы, которым нужно следовать? Я думаю об одном общем проекте Proxy, используемом на стороне клиента, который осуществляет связь со службами, обертывает полученные данные и возвращает данные в форме, хорошо известной клиентским библиотекам. Должна быть указана только одна ссылка на службу, и я думаю, мне нужен только App.config в проекте wpfApp? Имеет ли это смысл?


person stiank81    schedule 11.12.2009    source источник


Ответы (3)


Мне нравится структурировать свои решения WCF следующим образом:

Контракты (библиотека классов)
содержит все контракты на обслуживание, операции, ошибки и данные. Может использоваться совместно сервером и клиентом в чистом сценарии преобразования .NET в .NET.

Реализация службы (библиотека классов)
Содержит код для реализации служб и любые вспомогательные / вспомогательные методы, необходимые для этого. Ничего больше.

Хост (ы) службы (необязательно - может быть Winforms, Консольное приложение, Служба NT)
Содержит хост (ы) службы для отладки / тестирования или, возможно, также для производства.

Это в основном дает мне серверную часть вещей.

На стороне клиента:

Клиентские прокси (библиотека классов). Мне нравится упаковывать свои клиентские прокси в отдельную библиотеку классов, чтобы их можно было повторно использовать в нескольких реальных клиентских приложениях. Это можно сделать с помощью svcutil или «Добавить ссылку на службу» и вручную настроить получившийся ужасный файл app.config или вручную реализовать клиентские прокси (при совместном использовании сборки контрактов) с использованием конструкций ClientBase<T> или ChannelFactory<T>.

1-n фактических клиентов (приложение любого типа)
обычно будет ссылаться только на сборку прокси-серверов клиента или, возможно, и на сборку контрактов, если она является общей. Это может быть ASP.NET, WPF, Winforms, консольное приложение, другие службы - что угодно.

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

Это было вдохновлено Extreme WCF screen cast на DotNet Rocks TV с Карлом Франклином. - Настоятельно рекомендуется снимать экран!

person marc_s    schedule 11.12.2009
comment
Спасибо за очень хороший ответ! Несколько вопросов назад: имея сервисный хост, вам нужно запускать и хост, и клиент при запуске вашего приложения? Или есть способ обойти это? Что касается клиентских прокси - что бы вы предпочли? Ручная импликация звучит более последовательно, поскольку вам не нужно иметь дело с устаревшими ссылками на услуги. - person stiank81; 11.12.2009
comment
@bambuska: конечно, вам нужно запустить и хост службы, и клиент для тестирования; для этого выберите запускать несколько проектов в Visual Studio - вы можете запустить как узел службы, так и клиент, нажав F5. - person marc_s; 11.12.2009
comment
Клиентские прокси: мне нравится полный контроль, который у меня есть, когда я выполняю ручную реализацию клиентских прокси - для этого требуется, хотя я могу поделиться контрактом между сервером и клиентом (так как ручное использование клиентских прокси должно есть доступ к актуальным контрактам) - person marc_s; 11.12.2009
comment
Ответ, на который я надеялся :-) Просто боролся с реализацией функций асинхронного сервиса ... - person stiank81; 11.12.2009
comment
Что касается тестирования - вы можете добавить ссылку на реализацию Сервиса и использовать класс реализации вместо прокси. Как только все заработает, удалите ссылку на реализацию Сервиса и вернитесь к использованию прокси. - person Goran; 11.12.2009
comment
+1 за ссылку на трансляцию экрана Extreme WCF - стоит посмотреть. - person Jeff; 31.10.2013

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

Но для такого простого приложения, как ваше, когда вас не волнуют такие вещи, как взаимодействие Java или универсальное взаимодействие веб-сервисов, я делаю вот что:

Все классы DataContract и интерфейсы ServiceContract попадают в библиотеку (или библиотеки), которые используются совместно клиентом и сервером. Обратите внимание, что вам, вероятно, не следует украшать свою Реализацию службы с помощью ServiceContract, вы должны создать отдельный интерфейс с атрибутами ServiceContract, которые вы можете поместить в общую сборку.

Так что, похоже, вы почти все делаете правильно. Что вам, вероятно, НЕ нужно, так это автоматически генерировать прокси в этом случае. Это просто причиняет тебе боль. Поэтому не используйте диалоговое окно «Добавить ссылку на службу» для того, что вы делаете. Просто включите свои общие сборки DataContract и используйте ChannelFactory, чтобы получить прокси-сервер для интерфейса вашей службы, определенного в общей библиотеке. Это также избавляет вас от необходимости повторно генерировать прокси в Visual Studio, который для любого проекта приличного размера становится ОЧЕНЬ БЫСТРО.

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

person Dave Markle    schedule 11.12.2009
comment
Спасибо! Звучит очень заманчиво. Автоматически сгенерированные прокси-серверы действительно уже вызвали боль ... Я на самом деле пробую реализацию, аналогичную той, которую вы уже описываете, но она остановилась, когда мне понадобились асинхронные службы. Могу ли я легко использовать ChannelFactory для создания асинхронных сервисов? - person stiank81; 11.12.2009
comment
Да, и JavaInterop и т. Д. Вообще не актуален. Это будет все от .net к .net! Имея DataContracts в общей библиотеке, я действительно могу вернуть, например. объект MyClass из службы, и будет ли он получен точно такого же типа? - person stiank81; 11.12.2009

Обычно я использую следующую структуру:

Common - содержит интерфейсы, данные-контракты, сервисные контракты, абстрактные классы и т. Д .; Клиент - ссылки Common, содержит класс прокси сервера; Сервер - ссылки Common, содержит актуальные классы реализации;

person Goran    schedule 11.12.2009
comment
Согласованный. Хотя я часто заставлял общую библиотеку включать DTO, которые можно использовать на обеих сторонах службы, а затем не использовать сгенерированные прокси-классы. - person asgerhallas; 11.12.2009
comment
Похоже, мне нужен общий проект для общего доступа ...! Вы используете автоматически сгенерированные прокси или опускаете их, например @asgerhallas? Конечно, я бы не стал их использовать, если смогу. Они уже причинили слишком много боли ... - person stiank81; 11.12.2009
comment
Я унаследовал класс прокси от ClientBase ‹T› и реализую интерфейс для переадресации вызовов на канал. - person Goran; 11.12.2009
comment
Звучит отлично. Можете ли вы реализовать асинхронные службы, унаследованные от ClientBase, или я должен использовать вместо этого ClientFactory? Если я правильно понял, сервис должен быть асинхронным на стороне сервера - в каком случае, думаю, это не будет иметь значения? .. - person stiank81; 11.12.2009
comment
Вы можете реализовать асинхронные сервисы. Просто создайте методы beginX и endX (в интерфейсе, реализации и прокси). - person Goran; 12.12.2009
comment
@Goran: Значит, на стороне сервера? Изучу это, но не так много времени в эти выходные .. У меня есть вопрос по этому поводу, если вы хотите сделать небольшой образец :-) stackoverflow.com/questions/1890679/ - person stiank81; 12.12.2009