我正在调用网络服务。它接受 Http Post。它是基于 Http 的简单 XML。您在请求正文中向它发送一个 XML 请求文档,然后在响应正文中返回一个 XML 响应文档。我的代码库中有一个很好的库,我们多年来构建了它,它对请求和响应文档进行强类型序列化。一切正常。
现在,我正在集成的新服务并不总是在响应中发回相同的对象类型。在某些错误条件下,它会返回一个特殊的错误文档。当然,在这些情况下,我的反序列化失败并且响应数据丢失。我知道我有一个反序列化错误,但由于响应丢失,我不知道根本原因是什么。
我认为问题在于 GetResponseStream() 返回的流不支持查找操作,所以当我收到错误时,我不能简单地倒回流并重新读取数据并以不同方式处理它。
我正在寻找更好地处理这个问题的策略。
我想我要做的是将响应流复制到在我尝试反序列化之前可搜索的内存流。然后,如果发生错误,我可以倒回内存流并以不同的方式处理响应数据。https://stackoverflow.com/a/3434077/90236中有一个很好的例子。
有一个更好的方法吗?将响应流复制到内存流似乎有点浪费。
原始代码的简化版本:
AccountRequest requestVal = new AccountRequest();
// initialize requestVal object
var request = (HttpWebRequest)WebRequest.Create("http://example.com/service");
request.Method = "POST";
request.ContentType = "text/xml";
using (Stream webStream = request.GetRequestStream())
{
var serializer = new XmlSerializer(typeof(AccountRequest));
serializer.Serialize(webStream, requestVal);
webStream.Flush();
webStream.Close();
}
AccountResponse returnVal;
using (var response = (HttpWebResponse)request.GetResponse())
{
Stream responseStream = response.GetResponseStream();
var serializer = new XmlSerializer(typeof(responseStream));
try
{
returnVal = (AccountResponse)serializer.Deserialize(responseStream);
}
catch (Exception ex)
{
// if an exception occurs, the response stream data is lost.
// The responseStream is not seekable.
logger.ErrorFormat("After Exception:\n{0}", ex.ToString());
throw;
}
}
建议代码的简化版本:
AccountRequest requestVal = new AccountRequest();
// initialize requestVal object
var request = (HttpWebRequest)WebRequest.Create("http://example.com/service");
request.Method = "POST";
request.ContentType = "text/xml";
using (Stream webStream = request.GetRequestStream())
{
var serializer = new XmlSerializer(typeof(AccountRequest));
serializer.Serialize(webStream, requestVal);
webStream.Flush();
webStream.Close();
}
AccountResponse returnVal;
using (var response = (HttpWebResponse)request.GetResponse())
{
Stream responseStream = response.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
// copy response stream to a seekable memorystream
int count = 0;
do
{
byte[] buf = new byte[1024];
count = responseStream.Read(buf, 0, 1024);
ms.Write(buf, 0, count);
} while (responseStream.CanRead && count > 0);
ms.Position = 0;
// now attempt to desrialize from the memory stream
var serializer = new XmlSerializer(typeof(AccountResponse));
try
{
returnVal = (AccountResponse)serializer.Deserialize(ms);
}
catch (Exception ex)
{
// if an exception occured, rewind the stream and write an error to the log
ms.Position = 0;
using (var reader = new StreamReader(ms, Encoding.UTF8))
{
logger.ErrorFormat("After Exception:\n{0}\n\nRespons:\n{1}",
ex.ToString(), reader.ReadToEnd());
}
throw;
}
}
}