2012-02-09 2 views
1

Я создаю службу WCF (.Net 3.5, IIS Hosted), чтобы заменить старую службу стиля ASMX. Он должен быть очень, совместимый со старым интерфейсом стиля, чтобы избежать усилий со стороны поставщиков, которые пишут программное обеспечение, которое его вызывает. (Некоторые из них создают простую структуру данных XML, помещают ее в предварительно подготовленный «шаблон» SOAP и бросают ее на моем сервисе. Мне нужно принять их существующую структуру XML).Принять простой формат null для параметра XmlElement

Для совместимости с тем, как эти клиенты называют услугу я должен был определить операцию как:

[ServiceContract(Namespace = "urn:namespacex")] 
public interface IServices 
{ 
    [OperationContract] 
    System.Xml.XmlElement OperationA(int parmB, System.Xml.XmlElement parmC); 
} 

т.е. параметры находятся в OperationContract, не вытянута на отдельные элементы DataMember в DataContract. Используемый здесь XmlElement заменяет параметр XmlNode, используемый в старой службе ASMX.

Он реализован как:

[ServiceBehavior(Namespace = "urn:namespacey")] 
public class TheService : IServices 
{ 
    public System.Xml.XmlElement OperationA(int parmB, System.Xml.XmlElement parmC) 
    { 
     ... code to handle call 
    } 
} 

Он работает отлично ... когда есть данные для отправки.

Проблема, с которой я сталкиваюсь, - это когда вход parmC равен null, что разрешено. Иногда у него есть данные, иногда это не так. Один абонент посылает это сообщение SOAP для нулевой parmC:

<parmC/> 

т.е. простой пустой элемент XML.

Это поднимает следующее сообщение об ошибке с WCF:

Ожидая состояние 'Element' .. Засада 'EndElement' с именем 'parmC', имен 'урн: namespacex'.

Так что кажется, что это не нравится простой ввод нулевого элемента. (Служба работает нормально, если на самом деле там есть какие-то данные.)

Отслеживание моего собственного тестового звонящего (который работает с информацией и без информации в параметре parmC), я вижу, что для нулевого моего (. Net WCF) тестера посылает:

<parmC xmlns:i="http://www.w3.org/2001/XMLSchema-instance" i:nil="true"/> 

Попытка 1:

Нужна помощь, я отметил «[XmlSerializerFormat]» атрибут, который должен совершить акт службы больше как старый стиль ASMX, не используя более новый сериализатор данных. Мой тестовый вызов (.Net, WCF) затем ничего не посылает за нуль. Но этот клиент по-прежнему получает сообщение об ошибке, хотя теперь это относится к этому элементу:

Отсутствует соответствующий начальный элемент.

Попытка 2:

Тогда я вспомнил старую версию оригинального сервиса ASMX использовал строку, чтобы принять эти данные. (Он загрузил эту строку в серверную часть объекта XML, внутри обработчика операции). Поэтому я изменил контракт и операцию, чтобы определить parmC как строку, а не XmlElement.

Внезапно служба принимает различные формы пустого пармC. (Используя приложение быстрого тестирования, которое отправляет raw SOAP на мой сервис, поэтому я смогу имитировать то, что делают эти поставщики).

Но - если есть на самом деле данные там, это не удается, с:

Ошибка десериализации тела сообщения запроса для операции 'OperatonA. ---> System.InvalidOperationException: в документе XML есть ошибка (99, 99). ---> System.Xml.XmlException: Конечный элемент «parmC» из пространства имен «urn: namespacex» ожидается. Найдено элемент 'а' из пространства имен ''

(когда данные XML отправляются в parmC, это выглядит, как это в SOAP:

<parmC> 
    <a xmlns="">bbb</a> 
</parmC> 

)

Ясно, что не ждет в этом случае найти XML внутри строки (элемент «a»); но это использовалось для работы в ASMX, поэтому «стоит того».


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

Должен ли я выполнять собственный десериализатор? Есть где-нибудь где-нибудь, что поможет?

(До сих пор мне удалось сохранить все WCF, связанные исключительно в конфигурации, я хотел бы сохранить его таким образом, если я могу.)

В заключение, я нужна служба WCF, которая будет справляться с либо из них идет по проводам:

<s:Body> 
    <OperationA xmlns="urn:namespacex"> 
    <parmB>1</parmB> 
    <parmC> { this works fine } 
    <a xmlns=""> 
     <b>bbb</b> 
    </a> 
    </parmC> 
    </OperationA> 
</s:Body> 

<s:Body> 
    <OperationA xmlns="urn:namespacex"> 
    <parmB>1</parmB> 
    <parmC/> { I need this to be accepted } 
    </OperationA> 
</s:Body> 
+0

Пожалуйста, не префиксы ваши ответы с «WCF» и т. д. Для этого нужны теги. –

ответ

1

XML, для двух вариантов вы представить это не эквивалент. Существует очень тонкая разница между этими двумя, что, вероятно, является причиной вашей проблемы. Опция с <a xmlns=""> устанавливает элемент a, а его дочерние элементы не имеют значения по умолчанию XML-пространство имен. Другая опция (параметр «null») не содержит «переопределения» пространства имен XML по умолчанию от «urn: namespacex» до «», поэтому, когда процесс десериализации обрабатывается parmC для элемента <a xmlns="">, он не может Найди это. Если вы внимательно прочитаете сообщение об исключении, на самом деле вам это будет сказано.

О том, как поддержать два сценария, попытайтесь получить свой клиент, чтобы отправить это вместо того, что они посылают прямо сейчас:

<parmC> 
<a xmlns=""> 
    <b /> 
</a> 
</parmC> 

или, возможно:

<parmC> 
<a xmlns="" /> 
</parmC> 
+0

Самая большая проблема, с которой я сталкиваюсь, - я не могу - заставить клиента изменить то, что они отправляют. Если бы я мог, я бы просто попросил их отправить тот же ', который мой тестовый абонент отправляет значение null. – pzkpfw

+0

Похоже, вам нужно подключить пользовательский десериализатор, чтобы настроить входящее мыло в соответствии с тем, что ищет WCF. Это (длинное) [сообщение в блоге о сериализаторах] (http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/) поможет вам начать , Другой вариант - использовать MessageContract вместо DataContract, но этот путь тоже болезнен. Вам нужно будет выбрать свой яд :( –

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