Как создать клиентский код для нескольких служб WCF с общими типами

У меня есть несколько служб WCF, которые разделяют некоторые контракты данных и должны генерировать код на стороне клиента с помощью svcutil.exe. Я столкнулся с ошибками, используя два самых очевидных способа сделать это и нуждаюсь в некоторой помощи.

Но во-первых, вот услуги:

[ServiceContract( Namespace = "http://www.me.com/services/" )]
public interface IFooService {
    [OperationContract]
    Response RunFoo( Request request );
}
[ServiceContract( Namespace = "http://www.me.com/services/" )]
public interface IBarService {
    [OperationContract]
    Response RunBar( Request request );
}

Ответ и запрос определяются в отдельной сборке:

[DataContract( Namespace = "http://www.me.com/shared/" )]
public class Request {
    [DataMember]
    public int Input { get; set; }
}
[DataContract( Namespace = "http://www.me.com/shared/" )]
public class Response {
    [DataMember]
    public int Result { get; set; }
}

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

Включая обе службы в командной строке svcutil - например:

svcutil /o:Client.cs http://hostname.com/FooService.svc http://hostname.com/BarService.svc

приведет к многочисленным сообщениям об ошибках о дублированных типах данных, начиная с

Ошибка: произошла ошибка проверки схемы, сгенерированной во время экспорта:     Источник:     Строка: 1 Колонка: 9087    Ошибка проверки: глобальный элемент http://schemas.microsoft.com/2003/10/Serialization/:anyType 'уже объявлен.

и заканчивая

Ошибка: произошла ошибка проверки схемы, сгенерированной во время экспорта:     Источник:     Строка: 1 Колонка: 12817    Ошибка проверки: уже объявлен complexType 'http://www.me.com/shared/:Response'.

Создание клиентского файла отдельно для каждой службы позволяет избежать этих ошибок:

svcutil /o:Foo.cs http://hostname.com/FooService.svc
svcutil /o:Bar.cs http://hostname.com/BarService.svc

Но тогда определения общих типов (таких как Request and Response) будут дублироваться в Foo.cs, а затем в Bar.cs, что приведет, очевидно, к ошибкам компилятора.

Итак, , что является обычным способом создания клиентского кода, использующего такие службы?

Ограничения:

  • не может отправить клиенту сборку, содержащую общие типы (чтобы они могли использовать параметр svcutil.exe/r)
  • не может использовать команду "Добавить ссылку на службу..." в Visual Studio - нужна командная строка svcutil (или другой инструмент командной строки).

Ответ 1

Ну, в основном вы можете

  • либо поместить ваши общие типы в отдельную сборку, которую клиенты могут использовать при генерации кода клиента (который вы уже уволили как невозможно)

а затем:

  • вам нужно генерировать каждый прокси-сервер для служб отдельно, и каждая служба получит свою собственную "копию" классов "Запрос" и "Ответ"

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

Ответ 2

Поскольку у вас есть правила для общей сборки DTO (почему, btw?), самым простым вариантом в этом случае является генерация типов в разных пространствах имен С# (т.е. два вызова на svcutil) и отображение данных между двумя. По существу: относиться к DTO от двух сервисов как к совпадению.

Вы можете использовать такие вещи, как automapper, чтобы уменьшить работу, или вы можете вырезать сериализацию из типа A и десериализовать в тип B (при условии, что фактические пространства имен и т.д. идентичны).

Ответ 3

WSCF Blue может приблизиться к решению, если вы еще не нашли его.

http://wscfblue.codeplex.com/

Он может создавать отдельные файлы для каждого типа, перезаписывая последующие операции.

Ответ 4

Когда вы запустите клиентскую утилиту, как только вы получите файл XXXXService.cs и файл output.config.

Если вы соблюдаете класс XXXXService, у вас есть все в файле. Вы можете разделить их как отдельный файл IXXXService и XXXService и файл datacontracts.

Затем вы можете запустить утилиту для второй службы и добавить файлы IXXXService1.cs и 1XXXService.cs и те же данные, которые вы можете использовать для совместного использования для этих 2.

Я не уверен, может ли это ответить на ваш вопрос. Я использовал пример, который может вам помочь. Вы можете увидеть еще несколько примеров здесь, связанных с некоторыми материалами MVC и WCF.