ReadAsAsync反序列化HttpResponseMessage结果

时间:2017-12-03 11:22:26

标签: c# .net serialization httpresponse

这个问题可能会重复,但我正在调用以下服务:

   HttpClient httpClinet = new HttpClient();
   httpClinet.DefaultRequestHeaders.Accept.Clear();
   httpClinet.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
   var str = "XrayService.asmx/GetOrdData?" + string.Format("ordId={0}&code={1}", range.ordId, range.code);
   HttpResponseMessage response; 
   httpClinet.BaseAddress = new Uri("http://172.16.203.27:6043/"); 
   response = httpClinet.GetAsync(str).Result;
   if (response.IsSuccessStatusCode)
         var caseInfos = response.Content.ReadAsAsync<IEnumerable<PI>>().Result;//Here is exception

一切都很顺利,但是当我想要运行ReadAsAsync时,我得到了如下例外情况:

  

错误:System.AggregateException:发生了一个或多个错误。 ---&GT; System.AggregateException:发生一个或多个错误。 ---&GT; System.Runtime.Serialization.SerializationException:第1行位置出错5.期待元素&#39; ArrayOfPI&#39;来自命名空间&#39; http://schemas.datacontract.org/2004/07/SATA_DTOs&#39; ..遇到&#39;元素&#39;名称&#39; PI&#39;,名称空间&#39;&#39;。      在System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader,Boolean verifyObjectName,DataContractResolver dataContractResolver)      在System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader,Boolean verifyObjectName,DataContractResolver dataContractResolver)      在System.Runtime.Serialization.DataContractSerializer.ReadObject(XmlReader reader)      在System.Net.Http.Formatting.XmlMediaTypeFormatter.ReadFromStream(类型类型,流readStream,HttpContent内容,IFormatterLogger formatterLogger)      在System.Net.Http.Formatting.XmlMediaTypeFormatter.ReadFromStreamAsync(类型类型,流readStream,HttpContent内容,IFormatterLogger formatterLogger)   ---从抛出异常的先前位置开始的堆栈跟踪结束---

我正在Google Advanced Rest Client测试该服务,并将结果显示为:

状态:200 OK

响应标题:

cache-control: private, max-age=0
content-length: 360
content-type: text/xml; charset=utf-8
server:Microsoft-IIS/8.5
x-aspnet-version:4.0.30319
x-powered-by: ASP.NET
date: Sun, 03 Dec 2017 08:37:21 GMT

和OutPut:

<?xml version="1.0" encoding="utf-8" ?>
<PI>
<ordId>950177248</ordId>
<fnm>بهسا</fnm>
<lnm>حسنی</lnm>
<fthNm>علی</fthNm>
<pId>p2535154</pId>
<sex>F</sex>
<brthD>2003-02-05</brthD>
<addrs />
<nId>0025351540</nId>
<srvNm>|دندان بصورت پانورک</srvNm>
<rfrPhy>مهرزاد اميري-41853</rfrPhy>
 </PI>

我还装饰了DTO,如:

namespace SATA_DTOs
{
    [DataContract(Name = "PI")]
    public class PI
    {
        [DataMember] public string ordId { get; set; }
        [DataMember] public string fnm { get; set; }
        [DataMember] public string lnm { get; set; }
        [DataMember] public string fthNm { get; set; }
        [DataMember] public string pId { get; set; }
        [DataMember] public string sex { get; set; }
        [DataMember] public string brthD { get; set; }
        [DataMember] public string addrs { get; set; }
        [DataMember] public string nId { get; set; }
        [DataMember] public string srvNm { get; set; }
        [DataMember] public string rfrPhy { get; set; }
    }
}

enter image description here

更新

正如另一次尝试一样,我想在JSONXML获得结果,但这也没有区别:

List<PI> model = null;
var client = new HttpClient();
var task = client.GetAsync(httpClinet.BaseAddress.ToString() + str)
      .ContinueWith((taskwithresponse) =>
       {
           var response1 = taskwithresponse.Result;
           var jsonString = response1.Content.ReadAsStringAsync();
                  m_Logging.Log(SharedLib.LoggingMode.Prompt, "JSON string created {0}...", jsonString);
           jsonString.Wait();
           model = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PI>>(jsonString.Result);
        });
task.Wait();

3 个答案:

答案 0 :(得分:0)

这可能很混乱。这可能看起来很明显,但仍然是一些人无法理解的。

看看这一行:

var caseInfos = response.Content.ReadAsAsync<IEnumerable<PI>>().Result

您将结果呈现为PI,从而产生<pi>标记。

因此,您收到以下错误:

  

System.Runtime.Serialization.SerializationException:第1行出错   位置5.期望来自命名空间的元素'ArrayOfPI'   'http://schemas.datacontract.org/2004/07/SATA_DTOs'遇到了   'Element',名称为'PI',名称空间''

解决方案就是这个,

更改您的数据合同您的班级名称:

namespace SATA_DTOs
{
    [DataContract(Name = "ArrayOfPI")]
    public class ArrayOfPI
    {
        [DataMember] public string ordId { get; set; }
        [DataMember] public string fnm { get; set; }
        [DataMember] public string lnm { get; set; }
        [DataMember] public string fthNm { get; set; }
        [DataMember] public string pId { get; set; }
        [DataMember] public string sex { get; set; }
        [DataMember] public string brthD { get; set; }
        [DataMember] public string addrs { get; set; }
        [DataMember] public string nId { get; set; }
        [DataMember] public string srvNm { get; set; }
        [DataMember] public string rfrPhy { get; set; }
    }
}

然后将其分配为

 var caseInfos = response.Content.ReadAsAsync<IEnumerable<ArrayOfPI>>().Result

因此,您将收到:

<?xml version="1.0" encoding="utf-8" ?>
<ArrayOfPI>
<ordId>950177248</ordId>
<fnm>بهسا</fnm>
<lnm>حسنی</lnm>
<fthNm>علی</fthNm>
<pId>p2535154</pId>
<sex>F</sex>
<brthD>2003-02-05</brthD>
<addrs />
<nId>0025351540</nId>
<srvNm>|دندان بصورت پانورک</srvNm>
<rfrPhy>مهرزاد اميري-41853</rfrPhy>
 </ArrayOfPI>

序列化寻找和期望找到的是什么。

答案 1 :(得分:0)

使用ReadAsAsync时,框架会尝试使用提供的媒体类型格式化程序解释所需的反序列化类型。

您有IEnumerable<PI>因此它假设正在阅读的内容是基于标准的集合ArrayOfPI

在您的示例中,当您告诉它期望收集以使其失败时,将返回单个对象。

我建议检查收集,如果失败则检查单个对象,给出可以返回的响应的动态性质。

简化示例

public async Task<IEnumerable<PI>> GetDataAsync() {
    var httpClinet = buildClient();
    var str = buildRequestUrl();
    var response = await httpClinet.GetAsync(str);
    IEnumerable<PI> caseInfos = Enumerable.Empty<PI>();
    if (response.IsSuccessStatusCode) {
        try {
            caseInfos = await response.Content.ReadAsAsync<IEnumerable<PI>>();
        } catch {
            //Log?
        }
        if (caseInfos == null) {
            try {
                var singleObject = await response.Content.ReadAsAsync<PI>();
                if (singleObject != null) {
                    caseInfos = new[] { singleObject };
                }
            } catch {
                //Log?
            }
        }
    }
    return caseInfos;
}

答案 2 :(得分:0)

在服务器上复制粘贴补丁并改进日志后,我终于解决了问题,

作为@NKosi提出的最后一次尝试,但几乎没有变化:

var response1 = httpClinet.GetAsync(str).Result;
IEnumerable<PI> caseInfos1 = Enumerable.Empty<PI>();
try
{
    caseInfos1 = response1.Content.ReadAsAsync<IEnumerable<PI>>().Result;
}
catch (Exception ex)
{
    try
    {
        m_Logging.Log(SharedLib.LoggingMode.Error, "IEnumerable failed, EXP:{0}", ex);
        var singleObject = response1.Content.ReadAsAsync<PI>().Result;
        if (singleObject != null)
        {
            m_Logging.Log(SharedLib.LoggingMode.Error, "singleObject succeeded...");
            caseInfos1 = new[] { singleObject };
        }
    }
    catch (Exception exp)
    {
        m_Logging.Log(SharedLib.LoggingMode.Error, "singleObject failed, EXP:{0}", exp);
    }
}

我还与下面的例外交叉:

  

System.Runtime.Serialization.SerializationException:第1行位置出错5.期待元素&#39; ArrayOfPI&#39;来自命名空间&#39; http://schemas.datacontract.org/2004/07/SATA_DTOs&#39; ..遇到&#39;元素&#39;名称&#39; PI&#39;,名称空间&#39; ....#/ p>      

.....

作为例外提及它无法反序列化结果我猜测输出类型可能是text/html而不是text/xml,尽管Rest Client Tester将其指定为{{1} },

因此我得出结论使用text/xml并将其反序列化为ReadAsStringAsync,所以通过下面的剪切代码我终于得到了结果:

PI

我感谢所有人越过这个问题,特别是那些在这次讨论中分享他/她知识的人!!!