异常 de-serializing SOAP XML 到对象
Exception de-serializing SOAP XML into Object
我正在开发可以接受和 return SOAP 1.1 消息的 WCF 服务。但是,我在将 SOAP 主体反序列化为我的对象时遇到问题。目前我有;
namespace MyAPI
{
[ServiceContract]
public interface IMyService
{
[OperationContract(IsOneWay = false, Action = "*", ReplyAction = "*")]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare, RequestFormat=WebMessageFormat.Xml)]
Message ProcessMessgae(Message message);
}
}
public class MyService : IMyService
{
public Message ProcessMessgae(Message message)
{
MessageBuffer buffer = message.CreateBufferedCopy(8192);
// Get a copy of the original message.
Message msgCopy = buffer.CreateMessage();
// Take another copy of the same message.
Message returnMsg = buffer.CreateMessage();
// Use the msgCopy to get an XML and extract the body contents. Once this message has been read and consumed,
System.Xml.XmlDictionaryReader xrdr = msgCopy.GetReaderAtBodyContents();
string bodyData = xrdr.ReadOuterXml();
var reader = new StringReader(bodyData);
var serializer = new XmlSerializer(typeof(OTA_HotelAvailRQ));
var instance = (OTA_HotelAvailRQ)serializer.Deserialize(reader);
return returnMsg;
}
}
这是我的auto-generated对象
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.2046.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.opentravel.org/OTA/2003/05")]
public partial class OTA_HotelAvailRQ : object, System.ComponentModel.INotifyPropertyChanged
{
private string echoTokenField;
private System.DateTime timeStampField;
private bool timeStampFieldSpecified;
private bool targetFieldSpecified;
private decimal versionField;
private bool availRatesOnlyField;
private bool availRatesOnlyFieldSpecified;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string EchoToken
{
get
{
return this.echoTokenField;
}
set
{
this.echoTokenField = value;
this.RaisePropertyChanged("EchoToken");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public System.DateTime TimeStamp
{
get
{
return this.timeStampField;
}
set
{
this.timeStampField = value;
this.RaisePropertyChanged("TimeStamp");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool TimeStampSpecified
{
get
{
return this.timeStampFieldSpecified;
}
set
{
this.timeStampFieldSpecified = value;
this.RaisePropertyChanged("TimeStampSpecified");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public decimal Version
{
get
{
return this.versionField;
}
set
{
this.versionField = value;
this.RaisePropertyChanged("Version");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public bool AvailRatesOnly
{
get
{
return this.availRatesOnlyField;
}
set
{
this.availRatesOnlyField = value;
this.RaisePropertyChanged("AvailRatesOnly");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool AvailRatesOnlySpecified
{
get
{
return this.availRatesOnlyFieldSpecified;
}
set
{
this.availRatesOnlyFieldSpecified = value;
this.RaisePropertyChanged("AvailRatesOnlySpecified");
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null))
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
但是,当我 运行 代码时,我在以下行中遇到异常 var instance = (OTA_HotelAvailRQ)serializer.Deserialize(reader);
我发布的 SOAP XML 是;
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:UsernameToken>
<wsse:Username>test</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">thebest</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<OTA_HotelAvailRQ xmlns="http://www.opentravel.org/OTA/2003/05" Version="1.0" TimeStamp="2005-08-01T09:30:47+02:00" EchoToken="fb57388d" AvailRatesOnly="true">
</OTA_HotelAvailRQ>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
实际异常是;
如果将命名空间添加到 xmlserializer 会发生什么情况?
var instance = (OTA_HotelAvailRQ)serializer.Deserialize(reader, "http://www.opentravel.org/OTA/2003/05");
另一种选择是执行类似下面的操作,您可能必须使用 ReadOuterXml() 而不是 ReadInnerXml,命名空间也可以从此方法中删除:
System.Xml.Linq.XElement body = System.Xml.Linq.XElement.Parse(msgCopy.GetReaderAtBodyContents().ReadInnerXml());
var instance = Deserialize<OTA_HotelAvailRQ>(body, "http://www.opentravel.org/OTA/2003/05");
public static T Deserialize<T>(XElement xElement, string nameSpace)
{
using (MemoryStream memoryStream = new MemoryStream(Encoding.ASCII.GetBytes(xElement.ToString())))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T), nameSpace);
return (T)xmlSerializer.Deserialize(memoryStream);
}
}
如果您仍然遇到问题,还有一种使用 DataContractSerializer
或 SoapreflectionImporter
的方法,但您没有非常复杂的对象,这些方法可能有点矫枉过正。
我正在开发可以接受和 return SOAP 1.1 消息的 WCF 服务。但是,我在将 SOAP 主体反序列化为我的对象时遇到问题。目前我有;
namespace MyAPI
{
[ServiceContract]
public interface IMyService
{
[OperationContract(IsOneWay = false, Action = "*", ReplyAction = "*")]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare, RequestFormat=WebMessageFormat.Xml)]
Message ProcessMessgae(Message message);
}
}
public class MyService : IMyService
{
public Message ProcessMessgae(Message message)
{
MessageBuffer buffer = message.CreateBufferedCopy(8192);
// Get a copy of the original message.
Message msgCopy = buffer.CreateMessage();
// Take another copy of the same message.
Message returnMsg = buffer.CreateMessage();
// Use the msgCopy to get an XML and extract the body contents. Once this message has been read and consumed,
System.Xml.XmlDictionaryReader xrdr = msgCopy.GetReaderAtBodyContents();
string bodyData = xrdr.ReadOuterXml();
var reader = new StringReader(bodyData);
var serializer = new XmlSerializer(typeof(OTA_HotelAvailRQ));
var instance = (OTA_HotelAvailRQ)serializer.Deserialize(reader);
return returnMsg;
}
}
这是我的auto-generated对象
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.2046.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.opentravel.org/OTA/2003/05")]
public partial class OTA_HotelAvailRQ : object, System.ComponentModel.INotifyPropertyChanged
{
private string echoTokenField;
private System.DateTime timeStampField;
private bool timeStampFieldSpecified;
private bool targetFieldSpecified;
private decimal versionField;
private bool availRatesOnlyField;
private bool availRatesOnlyFieldSpecified;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string EchoToken
{
get
{
return this.echoTokenField;
}
set
{
this.echoTokenField = value;
this.RaisePropertyChanged("EchoToken");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public System.DateTime TimeStamp
{
get
{
return this.timeStampField;
}
set
{
this.timeStampField = value;
this.RaisePropertyChanged("TimeStamp");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool TimeStampSpecified
{
get
{
return this.timeStampFieldSpecified;
}
set
{
this.timeStampFieldSpecified = value;
this.RaisePropertyChanged("TimeStampSpecified");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public decimal Version
{
get
{
return this.versionField;
}
set
{
this.versionField = value;
this.RaisePropertyChanged("Version");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public bool AvailRatesOnly
{
get
{
return this.availRatesOnlyField;
}
set
{
this.availRatesOnlyField = value;
this.RaisePropertyChanged("AvailRatesOnly");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool AvailRatesOnlySpecified
{
get
{
return this.availRatesOnlyFieldSpecified;
}
set
{
this.availRatesOnlyFieldSpecified = value;
this.RaisePropertyChanged("AvailRatesOnlySpecified");
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null))
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
但是,当我 运行 代码时,我在以下行中遇到异常 var instance = (OTA_HotelAvailRQ)serializer.Deserialize(reader);
我发布的 SOAP XML 是;
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:UsernameToken>
<wsse:Username>test</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">thebest</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<OTA_HotelAvailRQ xmlns="http://www.opentravel.org/OTA/2003/05" Version="1.0" TimeStamp="2005-08-01T09:30:47+02:00" EchoToken="fb57388d" AvailRatesOnly="true">
</OTA_HotelAvailRQ>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
实际异常是;
如果将命名空间添加到 xmlserializer 会发生什么情况?
var instance = (OTA_HotelAvailRQ)serializer.Deserialize(reader, "http://www.opentravel.org/OTA/2003/05");
另一种选择是执行类似下面的操作,您可能必须使用 ReadOuterXml() 而不是 ReadInnerXml,命名空间也可以从此方法中删除:
System.Xml.Linq.XElement body = System.Xml.Linq.XElement.Parse(msgCopy.GetReaderAtBodyContents().ReadInnerXml());
var instance = Deserialize<OTA_HotelAvailRQ>(body, "http://www.opentravel.org/OTA/2003/05");
public static T Deserialize<T>(XElement xElement, string nameSpace)
{
using (MemoryStream memoryStream = new MemoryStream(Encoding.ASCII.GetBytes(xElement.ToString())))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T), nameSpace);
return (T)xmlSerializer.Deserialize(memoryStream);
}
}
如果您仍然遇到问题,还有一种使用 DataContractSerializer
或 SoapreflectionImporter
的方法,但您没有非常复杂的对象,这些方法可能有点矫枉过正。