耗时Recurly REST API返回XML时的WebAPI序列化问题 [英] WebAPI Serialization problems when consuming Recurly Rest API which returns XML

查看:370
本文介绍了耗时Recurly REST API返回XML时的WebAPI序列化问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来的ASP.Net的Web API。我试图与基于Recurly REST API互动,我的电话ReadAsAsync这是我认为它会尝试序列化反应点时我收到类似下面的错误。

  {看齐错误1位置73.期待元素帐户从命名空间http://schemas.datacontract.org/2004/07/RecurlyWebApi.Recurly'..遇到元素名为'账户',命名空间'。}

下面是我HttpClient的实施,简化为简洁:

 公共类RecurlyClient
  {
    只读HttpClient的客户端=新的HttpClient();    公共RecurlyClient()
    {
      变种配置=(RecurlySection)ConfigurationManager.GetSection(recurly);      client.BaseAddress =新的URI(的String.Format(https://开头{0} .recurly.com / V2 /,config.Subdomain));      //添加认证头
      client.DefaultRequestHeaders.Authorization =新AuthenticationHeaderValue(基本,Convert.ToBase64String(Encoding.ASCII.GetBytes(config.ApiKey)));      //添加接受头为XML格式。
      client.DefaultRequestHeaders.Accept.Add(新MediaTypeWithQualityHeaderValue(应用程序/ XML));
    }    公众吨得到< T>(字符串ID)
    {
      VAR账户=默认(T);      //使该请求,并从服务的响应
      HTT presponseMessage响应= client.GetAsync(string.Concat(账户/,ID))结果。 //阻塞调用!      如果(response.IsSuccessStatus code)
      {
        //解析响应主体。堵!
        账户= response.Content.ReadAsAsync< T>()结果;
      }      返回账户;
    }
  }

和这里是我的模型:

  [XmlRoot(账户)]
  公共类帐户
  {
    [XmlAttribute(的href)]
    公共字符串HREF {搞定;组; }    [的XmlElement(account_ code)]
    公共字符串帐户code {搞定;组; }    [的XmlElement(国家)
    公共AccountState国家{搞定;组; }    [的XmlElement(用户名)]
    公共字符串用户名{获得;组; }    [的XmlElement(电子邮件)]
    公共字符串电子邮件{获得;组; }    [的XmlElement(FIRST_NAME)]
    公共字符串名字{获得;组; }    [的XmlElement(姓氏)]
    公共字符串名字{获得;组; }    [的XmlElement(COMPANY_NAME)]
    公共字符串公司{搞定;组; }    [XmlElement的(accept_language)]
    公共字符串语言code {搞定;组; }    [XmlElement的(hosted_login_token)]
    公共字符串HostedLoginToken {搞定;组; }    [XmlElement的(created_at)]
    公众的DateTime CreatedDate {搞定;组; }    [的XmlElement(地址)]
    公共地址地址{搞定;组; }
  }

和来自服务的XML响应的例子:

 <占HREF =htt​​ps://mysubdomain.recurly.com/v2/accounts/SDTEST01>
  <调整HREF =htt​​ps://mysubdomain.recurly.com/v2/accounts/SDTEST01/adjustments/>
  <发票HREF =htt​​ps://mysubdomain.recurly.com/v2/accounts/SDTEST01/invoices/>
  <订阅HREF =htt​​ps://mysubdomain.recurly.com/v2/accounts/SDTEST01/subscriptions/>
  <交易HREF =htt​​ps://mysubdomain.recurly.com/v2/accounts/SDTEST01/transactions/>
  < account_ code基SDTEST01< / account_ code>
  <州及GT;积极< /州>
  <用户名>&名为myusername LT; /用户名>
  &LT;电子邮件和GT; simon@example.co.uk< /电子邮件&GT;
  &LT; FIRST_NAME&gt;首先名称和LT; / FIRST_NAME&GT;
  &LT;&姓氏GT;姓&LT; /姓氏&GT;
  &LT; COMPANY_NAME&gt;我公司名称及LT; / COMPANY_NAME&GT;
  &LT; VAT_NUMBER零=无&GT;&LT; / VAT_NUMBER&GT;
  &LT;地址&gt;
    &LT;地址1&gt;我地址1 /地址1&GT;
    &LT;地址2&gt;我地址行2'; /地址2&GT;
    &LT;城市&gt;我的城市&LT; /城市&GT;
    &LT;状态&gt;我州与LT; /州&GT;
    &LT;邮编及GT; PL7 1AB&LT; /拉链&GT;
    &LT;国家&GT; GB&LT; /国家&GT;
    &LT;电话&GT; 0123456789&LT; /电话&GT;
  &LT; /地址&gt;
  &LT; accept_language零=无&GT;&LT; / accept_language&GT;
  &所述; hosted_login_token&GT ***下; / hosted_login_token&GT;
  &LT; created_at类型=日期时间&GT; 2013-08-22T15:58:17Z&LT; / created_at&GT;
&LT; /账户&GT;


解决方案

我认为这个问题是因为默认情况下正在使用的DataContractSerializer的反序列化XML,默认情况下DataContractSerializer的使用空间的 http://schemas.datacontract.org/2004/07/Clr.Namespace 。 (在这种情况下Clr.Namepace是RecurlyWebApi.Recurly。)

由于您的XML具有属性,您需要使用XmlSerializer的,而不是DataContractSerializer的,而你建立,因为您的帐户类装饰使用XML *属性来做到这一点。但是,你必须使用它使用XmlSerializer的XmlMediaTypeFormatter。作为<一个描述可以通过对全球XMLFormatter设置一个标志做到这一点href=\"http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization#xml_media_type_formatter\"相对=nofollow>此页面:

  VAR XML = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = TRUE;

或通过提供一个MediaTypeFormatter作为参数传递给您的通话ReadAsAsync:

  VAR xmlFormatter = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xmlFormatter.UseXmlSerializer = TRUE;
账户= response.ReadAsAsync&LT; T&GT;(xmlFormatter)。结果

不是100%肯定这一点,因为这并不能解释为什么在你的错误消息,第一个账户是小写 - DataContractSerializer的应该忽略XmlRoot属性

I'm new to the ASP.Net Web API. I'm trying to interact with the Recurly REST based API and I am getting errors like below during my ReadAsAsync call which is the point I believe it attempts to serialize the response.

{"Error in line 1 position 73. Expecting element 'account' from namespace 'http://schemas.datacontract.org/2004/07/RecurlyWebApi.Recurly'.. Encountered 'Element'  with name 'account', namespace ''. "}

Here is my HttpClient implementation, simplified for brevity:

  public class RecurlyClient
  {
    readonly HttpClient client = new HttpClient();

    public RecurlyClient()
    {
      var config = (RecurlySection)ConfigurationManager.GetSection("recurly");

      client.BaseAddress = new Uri(string.Format("https://{0}.recurly.com/v2/", config.Subdomain));

      // Add the authentication header
      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(config.ApiKey)));

      // Add an Accept header for XML format.
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
    }

    public T Get<T>(string id)
    {
      var accounts = default(T);

      // Make the request and get the response from the service
      HttpResponseMessage response = client.GetAsync(string.Concat("accounts/", id)).Result;  // Blocking call!

      if (response.IsSuccessStatusCode)
      {
        // Parse the response body. Blocking!
        accounts = response.Content.ReadAsAsync<T>().Result;
      }

      return accounts;
    }
  }

And here is my model:

  [XmlRoot("account")]
  public class Account
  {
    [XmlAttribute("href")]
    public string Href { get; set; }

    [XmlElement("account_code")]
    public string AccountCode { get; set; }

    [XmlElement("state")]
    public AccountState State { get; set; }

    [XmlElement("username")]
    public string Username { get; set; }

    [XmlElement("email")]
    public string Email { get; set; }

    [XmlElement("first_name")]
    public string FirstName { get; set; }

    [XmlElement("last_name")]
    public string LastName { get; set; }

    [XmlElement("company_name")]
    public string Company { get; set; }

    [XmlElement("accept_language")]
    public string LanguageCode { get; set; }

    [XmlElement("hosted_login_token")]
    public string HostedLoginToken { get; set; }

    [XmlElement("created_at")]
    public DateTime CreatedDate { get; set; }

    [XmlElement("address")]
    public Address Address { get; set; }
  }

And an example of the XML response from the service:

<account href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01">
  <adjustments href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01/adjustments"/>
  <invoices href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01/invoices"/>
  <subscriptions href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01/subscriptions"/>
  <transactions href="https://mysubdomain.recurly.com/v2/accounts/SDTEST01/transactions"/>
  <account_code>SDTEST01</account_code>
  <state>active</state>
  <username>myusername</username>
  <email>simon@example.co.uk</email>
  <first_name>First name</first_name>
  <last_name>Last name</last_name>
  <company_name>My Company Name</company_name>
  <vat_number nil="nil"></vat_number>
  <address>
    <address1>My Address Line 1/address1>
    <address2>My Address Line 2</address2>
    <city>My City</city>
    <state>My State</state>
    <zip>PL7 1AB</zip>
    <country>GB</country>
    <phone>0123456789</phone>
  </address>
  <accept_language nil="nil"></accept_language>
  <hosted_login_token>***</hosted_login_token>
  <created_at type="datetime">2013-08-22T15:58:17Z</created_at>
</account>

解决方案

I think the problem is because by default the DataContractSerializer is being used to deserialize the XML, and by default the DataContractSerializer uses a namespace of namespace http://schemas.datacontract.org/2004/07/Clr.Namespace. (In this case Clr.Namepace is RecurlyWebApi.Recurly.)

Because your XML has attributes, you need to use the XmlSerializer instead of the DataContractSerializer, and you're set up to do this because your account class is decorated with Xml* attributes. However, you have to use an XmlMediaTypeFormatter which is using the XmlSerializer. You can do this by setting a flag on the global XMLFormatter as described on this page:

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;

or by supplying a MediaTypeFormatter as a parameter to your ReadAsAsync call:

var xmlFormatter = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xmlFormatter.UseXmlSerializer = true;
accounts = response.ReadAsAsync<T>(xmlFormatter).Result

Not 100% sure of this because this doesn't explain why the first 'account' in your error message is lower case - the DataContractSerializer should ignore the XmlRoot attribute.

这篇关于耗时Recurly REST API返回XML时的WebAPI序列化问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆