WCF MessageContract Наследование

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

[MessageContract]
public abstract class BaseMessage
{ }

[MessageContract]
public class TestMessage : BaseMessage
{ }

Затем у меня есть асинхронный OperationContract для ServiceContract, определенный как:

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginFindRequest(BaseMessage request, AsyncCallback callback, object asyncState);

Проблема, которую я получаю, заключается в том, что при вызове метода BeginFindRequest и передаче экземпляра TestMessage для параметра запроса платформа WCF десериализует экземпляр TestMessage в BaseMessage на стороне службы / сервера. Поскольку это определяется как абстрактный класс, это приводит к следующей ошибке:

"Сообщение не может быть десериализовано в MessageContract типа BaseMessage, так как оно не имеет конструктора по умолчанию (без параметров)".

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

Итак, мой вопрос - что мне не хватает, чтобы заставить это работать; или я должен, возможно, лучше определить отдельный OperationContract для ServiceContract специально для этого типа - недостаток в том, что я мог бы получить много дополнительных OperationContracts?

6 ответов

В конце концов я нашел этот пост, который ударил по голове -

К сожалению, способ выражения контрактов в WCF позволяет очень легко забыть, какова их цель: определить сообщения, отправляемые операции и возвращаемые из операции. В действительности вы должны подумать "как бы я выразил эти данные в XML?". XML не поддерживает наследование, поэтому все, что вы добавляете в контракт, должно иметь какой-то способ сопоставления с XML. Контракты на данные, используемые для определения сообщений, - это просто удобство, типизированное для.NET, для генерации XML для данных, которые вы хотите передать - если вы просматриваете их любым другим способом, которым вам суждено оказаться в мире боли. Так что подумайте о данных, которые вы хотите передать, а не о том, как они могут быть представлены на вашем бизнес-уровне, и разработайте соответствующие DataContracts.

http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a3775eb1-b441-43ad-b9f1-e4aaba404235.aspx

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

Спасибо за помощь.

Хорошо, первый вопрос: почему вы действительно используете контракты на сообщения? Вы действительно нуждаетесь в этом??

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

"Нормальный" вызов WCF вряд ли когда-либо должен будет использовать контракт сообщения.

Вы определяете свои сервисные вызовы (методы вашего сервиса), используя [ServiceContract]и структуры данных передаются как [DataContract], Если у вас есть DataContract, у вас есть больше вариантов того, как обращаться с наследованием / полиморфизмом в вашем сервисе (больше, чем с конструкцией контракта сообщения).

Марк

Что ж, я точно объявил этот конструктор по умолчанию (без параметров), но он все еще не работал нормально для меня, для меня проблема заключалась в том, что модификатор доступа был защищен, хотя он должен быть общедоступным:

      public constructor() { }
^^^^

Можно ли изменить BaseMessage так, чтобы это был конкретный класс с конструктором без параметров?

Сообщение об ошибке говорит о том, что невозможно инициализировать объект типа BaseMessage, поскольку он является абстрактным.

Ошибка просто хочет, чтобы у вас был пустой конструктор по умолчанию, который он может использовать. Тем не менее, я согласен с marc_s; в проектах, над которыми я работал, я редко использовал контракт сообщений, единственный случай, который я запомнил, был частью службы передачи файлов, где фрагменты файлов передавались в сообщениях.

Попробуйте украсить свой [ServiceContract] с атрибутом KnownType. Поскольку TestMessage не является "видимым" из публичной операции, это помогает сантехнику знать, как обращаться с ним, когда он его видит.

Если это должно позволить [DataContract] чтобы быть сериализованным как TestMessage, вам по-прежнему, вероятно, придется обрабатывать несколько сообщений по-разному через 'is aили другой кастинг.

Другие вопросы по тегам