Мой проект на C # .NET должен общаться с внешним веб-сервисом на платформе Java (Sonic ESB).Для разработки и тестирования у меня есть фиктивный сервис, работающий в SOAP UI.Веб-сервис совместно использует объект с именем «ShipmentInformationMessage», который мой код должен создать и заполнить данными, а затем передать их веб-сервису.
Когда я через некоторое время заставил его работать вместе, я заметил, что сообщения с запросами, зарегистрированные в SOAP UI, имели следующий формат:
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ShipmentInformationMessage
xmlns="http://www.noneofyour.biz/message/Transportation/2011/01">
<SenderId>NOSOTROS</SenderId>
<RecipientId>PARTNER</RecipientId>
<CreationTimeStamp>2011-08-03T11:53:36.6505521+02:00</CreationTimeStamp>
<Version>2.0</Version>
<TestIndicator>true</TestIndicator>
<ControlParty>
<Name xmlns="http://www.noneofyour.biz/schema/Common/2011/01">PrimaryContact</Name>
<Contact xsi:nil="true" xmlns="http://www.noneofyour.biz/schema/Common/2011/01"/>
</ControlParty>
<Action>new</Action>
<Shipments>
<Shipment>
<MasterSystemId xmlns="http://www.noneofyour.biz/schema/Transportation/2011/01">FargoGateInbound</MasterSystemId>
<OwnerId xmlns="http://www.noneofyour.biz/schema/Transportation/2011/01">DKPARCELS</OwnerId>
<TrackingCode xmlns="http://www.noneofyour.biz/schema/Transportation/2011/01">ConsignmentNo</TrackingCode>
<DatesAndTimes xmlns="http://www.noneofyour.biz/schema/Transportation/2011/01">
<ShipmentDateTime>2011-01-23T12:34:00</ShipmentDateTime>
</DatesAndTimes>
etcetera...
и так далее ...
Как видите, пространства имен xml добавляются к нескольким узлам, а не объявляются вверху, а затем добавляются к именам элементов с префиксами.Это вызовет проблемы в реальном веб-сервисе, с которым ему придется работать (не спрашивайте меня почему).
Вместо этого нам хотелось бы получить следующее:
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ShipmentInformationMessage
xmlns:ns1="http://www.noneofyour.biz/message/Transportation/2011/01"
xmlns:ns2="http://www.noneofyour.biz/schema/Transportation/2011/01"
xmlns:ns3="http://www.noneofyour.biz/schema/Common/2011/01">
<ns1:SenderId>NOSOTROS</ns1:SenderId>
<ns1:RecipientId>PARTNER</ns1:RecipientId>
<ns1:CreationTimeStamp>2011-07-01T13:31:14.7164012+02:00</ns1:CreationTimeStamp>
<ns1:Version>2.0</ns1:Version>
<ns1:TestIndicator>true</ns1:TestIndicator>
<ns1:ControlParty>
<ns3:Name>PrimaryContact</ns3:Name>
<ns3:Contact d6p1:nil="true" />
</ns1:ControlParty>
<ns1:Action>new</ns1:Action>
<ns1:Shipments>
<ns1:Shipment>
<ns2:MasterSystemId>FargoGateInbound</ns2:MasterSystemId>
<ns2:OwnerId>DKPARCELS</ns2:OwnerId>
<ns2:TrackingCode>ConsignmentNo</ns2:TrackingCode>
<ns2:DatesAndTimes>
<ns2:ShipmentDateTime>2011-01-23T12:34:00</ns2:ShipmentDateTime>
</ns2:DatesAndTimes>
etcetera...
и так далее ...
После некоторых исследований я приступил к разработке своего пользовательского средства форматирования запросов, расширив IClientMessageFormatter,а затем подключить его, добавив его к поведению операций.По крайней мере, это прошло хорошо.Тем не менее, я не был уверен, как реализовать метод SerializeRequest, и не смог найти никаких полезных примеров в интернете, поэтому немного побрел вперед и в итоге получил следующее:
public class SonicMessageFormatter : IClientMessageFormatter
{
private IClientMessageFormatter _InnerFormatter;
public SonicMessageFormatter(IClientMessageFormatter innerFormatter)
{
_InnerFormatter = innerFormatter;
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
PutShipmentInformationMessage operation = (PutShipmentInformationMessage)parameters[0];
ShipmentInformationMessage sim = operation.ShipmentInformationMessage;
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("ns1", "http://www.noneofyour.biz/message/Transportation/2011/01");
ns.Add("ns2", "http://www.noneofyour.biz/schema/Transportation/2011/01");
ns.Add("ns3", "http://www.noneofyour.biz/schema/Common/2011/01");
XmlSerializer xs = new XmlSerializer(sim.GetType());
MemoryStream ms = new MemoryStream();
StreamWriter writer = new StreamWriter(ms, Encoding.UTF8);
xs.Serialize(writer, sim);
Message requestMessage = Message.CreateMessage(messageVersion, sim.Action.ToString(), writer);
writer.Flush();
return requestMessage;
}
public object DeserializeReply(Message message, object[] parameters)
{
return _InnerFormatter.DeserializeReply(message, parameters);
}
}
При тестировании с этимЯ получил следующую ошибку:
System.Runtime.Serialization.SerializationException: Type 'System.Text.UTF8Encoding+UTF8Encoder' with data contract name 'UTF8Encoding.UTF8Encoder:http://schemas.datacontract.org/2004/07/System.Text' is not expected. Add any types not known statically to the list of known types
Поэтому я изменил код, добавив (изменив следующие строки:
Type[] knownTypes = new Type[1];
knownTypes[0] = Encoding.UTF8.GetEncoder().GetType();
XmlSerializer xs = new XmlSerializer(sim.GetType(), knownTypes);
Но теперь я получаю следующую ошибку:
System.InvalidOperationException: System.Text.UTF8Encoding.UTF8Encoder cannot be serialized because it does not have a parameterless constructor.
Ну, черт! Что мне теперь делать ??
РЕДАКТИРОВАТЬ Я добавляю wsdl службы mock для помощи в решении следующих проблем:
<wsdl:definitions xmlns:ns="http://www.noneofyour.biz/message/Transportation/2011/01" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:auto1="http://www.noneofyour.biz/message/Transportation/2011/01" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://www.noneofyour.biz/message/Transportation/2011/01">
<wsdl:types>
<xsd:schema>
<xsd:import namespace="http://www.noneofyour.biz/message/Transportation/2011/01" schemaLocation="/mockShipmentInformationService_SOAPBinding?WSDL&interface=ShipmentInformationService_SOAPBinding&part=ShipmentInformationMessage.xsd"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="ShipmentInformationMessage">
<wsdl:part name="ShipmentInformationMessage" element="ns:ShipmentInformationMessage"></wsdl:part>
</wsdl:message>
<wsdl:portType name="ShipmentInformationService">
<wsdl:operation name="PutShipmentInformationMessage">
<wsdl:input message="ns:ShipmentInformationMessage"></wsdl:input>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ShipmentInformationService_SOAPBinding" type="ns:ShipmentInformationService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="PutShipmentInformationMessage">
<soap:operation soapAction="http://www.noneofyour.biz/ShipmentInformationService/PutShipmentInformationMessage" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ShipmentInformationService_Service">
<wsdl:port name="ShipmentInformationServicePort" binding="ns:ShipmentInformationService_SOAPBinding">
<soap:address location="http://localhost:8088/mockShipmentInformationService_SOAPBinding"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
РЕДАКТИРОВАТЬ Здесь следуют верхние части для сообщений, генерируемых форматером по умолчанию и пользовательским форматером, соответственно:
Default ClientMessageFormatter (InnerFormatter), который работает:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://www.noneofyour.biz/ShipmentInformationService/PutShipmentInformationMessage</Action>
</s:Header>
<s:Body
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ShipmentInformationMessage
xmlns="http://www.noneofyour.biz/message/Transportation/2011/01">
<SenderId>NOSOTROS</SenderId>
<RecipientId>PARTNER</RecipientId>
<CreationTimeStamp>2011-08-05T10:42:38.9344907+02:00</CreationTimeStamp>
<Version>2.0</Version>
<TestIndicator>true</TestIndicator>
<ControlParty>
<Name xmlns="http://www.noneofyour.biz/schema/Common/2011/01">PrimaryContact</Name>
<Contact xsi:nil="true" xmlns="http://www.noneofyour.biz/schema/Common/2011/01" />
</ControlParty>
<Action>new</Action>
etcetera...
Пользовательский ClientMessageFormatter (SonicMessageFormatter), который не работает:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://www.noneofyour.biz/ShipmentInformationService/PutShipmentInformationMessage</Action>
</s:Header>
<s:Body>
<ShipmentInformationMessage
xmlns:ns1="http://www.noneofyour.biz/message/Transportation/2011/01"
xmlns:ns2="http://www.noneofyour.biz/schema/Transportation/2011/01"
xmlns:ns3="http://www.noneofyour.biz/schema/Common/2011/01">
<ns1:SenderId>NOSOTROS</ns1:SenderId>
<ns1:RecipientId>PARTNER</ns1:RecipientId>
<ns1:CreationTimeStamp>2011-08-05T13:45:36.9134685+02:00</ns1:CreationTimeStamp>
<ns1:Version>2.0</ns1:Version>
<ns1:TestIndicator>true</ns1:TestIndicator>
<ns1:ControlParty>
<ns3:Name>PrimaryContact</ns3:Name>
<ns3:Contact d6p1:nil="true">
</ns3:Contact>
</ns1:ControlParty>
<ns1:Action>new</ns1:Action>
etcetera...
Как видите, сообщение пользовательского форматера не имеет пространств имен, объявленных в узле Body в отличие отсообщение форматера по умолчанию.Я также пытался без добавления пространств имен в сериализатор, но это тоже не помогло.