gpt4 book ai didi

WCF:用于控制 xml namespace 的 IClientMessageFormatter SerializeRequest 的实现

转载 作者:行者123 更新时间:2023-12-03 14:35:59 26 4
gpt4 key购买 nike

我的 C#.NET 项目必须与外部 Java 平台 Web 服务 (Sonic ESB) 通信。对于开发和测试,我有一个在 SOAP UI 中运行的模拟服务。 Web 服务共享一个名为“ShipmentInformationMessage”的对象,我的代码必须实例化该对象并填充数据,然后将其传递到 Web 服务。

一段时间后,当我让它一起工作时,我注意到 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 命名空间被添加到多个节点,而不是在顶部声明,然后作为元素名称的前缀。这将导致必须使用的实际 Web 服务出现问题(不要问为什么)。

我们想要的是:

 <?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 方法,并且在 Internet 上找不到任何有用的示例,所以摸索了一下,最后得到了这个:

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 以帮助解决更多问题:

 <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>

编辑 下面分别是默认格式化程序和自定义格式化程序生成的消息的顶部部分:

默认的 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...

如您所见,与默认格式化程序的消息相比,自定义格式化程序的消息没有在主体节点中声明的 namespace 。我也尝试过不向序列化程序添加 namespace ,但这也没有使它工作。

最佳答案

您正在使用的 Message.CreateMessage 重载采用 MessageVersion、一个操作(字符串)和代表消息正文的 对象 . WCF 试图做的是序列化 StreamWriter 实例,这绝对不是您需要的。

您可以使用另一个重载,它采用包含正文信息的 XmlReader。那一个应该做你需要的:

    MemoryStream ms = new MemoryStream();
XmlWriterSettings writerSettings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
OmitXmlDeclaration = true
};
XmlWriter writer = new XmlWriter.Create(ms, writerSettings);
xs.Serialize(writer, sim, ns);
writer.Flush();
ms.Position = 0;
XmlReader reader = XmlReader.Create(ms);
Message requestMessage = Message.CreateMessage(messageVersion, sim.Action.ToString(), reader);

return requestMessage;

关于WCF:用于控制 xml namespace 的 IClientMessageFormatter SerializeRequest 的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6942864/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com