反序列化时ServiceStack JsonServiceClient无声失败

时间:2014-05-30 12:30:52

标签: c# json serialization servicestack servicestack-text

我正在与Expedia API集成。我对ServiceStack相对比较新,但到目前为止管理得还不错,但是,我已经遇到了API的JSON响应的反序列化问题,尽管启用了JsConfig.ThrowOnDeserializationError,但似乎失败了。

  JsConfig.Reset();
  JsConfig.ThrowOnDeserializationError = true;
  var availability = _client.Get<ExpediaHotelRoomAvailability>("avail?" + querystring);

要查看我正在使用的API响应,请使用以下请求:

GET http://dev.api.ean.com/ean-services/rs/hotel/v3/avail?minorRev=26&cid=55505&apiKey=cbrzfta369qwyrm9t5b8y8kf&customerUserAgent=Mozilla%2f5.0+(Windows+NT+6.3%3b+WOW64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f35.0.1916.114+Safari%2f537.36&customerIpAddress=%3a%3a1&hotelId=135857&arrivalDate=06%2f07%2f2014&departureDate=06%2f20%2f2014&includeDetails=true&includeRoomImages=true&room1=2 HTTP/1.1
User-Agent: Fiddler
Content-Type: text/json
Host: dev.api.ean.com

这是一个典型的回应:

{
   "HotelRoomAvailabilityResponse":{
      "@size":"1",
      "customerSessionId":"0ABAAA7A-D42E-2914-64D2-01C0F09040D8",
      "hotelId":135857,
      "arrivalDate":"06\/07\/2014",
      "departureDate":"06\/20\/2014",
      "hotelName":"La Quinta Inn and Suites Raleigh Cary",
      "hotelAddress":"191 Crescent Commons",
      "hotelCity":"Cary",
      "hotelStateProvince":"NC",
      "hotelCountry":"US",
      "numberOfRoomsRequested":1,
      "checkInInstructions":"",
      "tripAdvisorRating":4.5,
      "tripAdvisorReviewCount":189,
      "tripAdvisorRatingUrl":"http:\/\/www.tripadvisor.com\/img\/cdsi\/img2\/ratings\/traveler\/4.5-12345-4.gif",
      "HotelRoomResponse":{
         "rateCode":14587,
         "roomTypeCode":14587,
         "rateDescription":"Standard Room, 1 King Bed",
         "roomTypeDescription":"Standard Room, 1 King Bed",
         "supplierType":"E",
         "propertyId":67977,
         "BedTypes":{
            "@size":"1",
            "BedType":{
               "@id":"14",
               "description":"1 king"
            }
         },
         "smokingPreferences":"S,NS",
         "rateOccupancyPerRoom":3,
         "quotedOccupancy":2,
         "minGuestAge":0,
         "RateInfos":{
            "@size":"1",
            "RateInfo":{
               "@priceBreakdown":"true",
               "@promo":"false",
               "@rateChange":"true",
               "RoomGroup":{
                  "Room":{
                     "numberOfAdults":2,
                     "numberOfChildren":0,
                     "rateKey":"0214364d-6819-4631-aa97-a162c43e0297"
                  }
               },
               "ChargeableRateInfo":{
                  "@averageBaseRate":"109.61539",
                  "@averageRate":"109.61539",
                  "@commissionableUsdTotal":"1425.0",
                  "@currencyCode":"USD",
                  "@maxNightlyRate":"165.0",
                  "@nightlyRateTotal":"1425.0",
                  "@surchargeTotal":"229.19",
                  "@total":"1654.19",
                  "NightlyRatesPerRoom":{
                     "@size":"13",
                     "NightlyRate":[
                        {
                           "@baseRate":"90.0",
                           "@rate":"90.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"90.0",
                           "@rate":"90.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"100.0",
                           "@rate":"100.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"115.0",
                           "@rate":"115.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"115.0",
                           "@rate":"115.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"115.0",
                           "@rate":"115.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"165.0",
                           "@rate":"165.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"165.0",
                           "@rate":"165.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"90.0",
                           "@rate":"90.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"95.0",
                           "@rate":"95.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"95.0",
                           "@rate":"95.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"95.0",
                           "@rate":"95.0",
                           "@promo":"false"
                        },
                        {
                           "@baseRate":"95.0",
                           "@rate":"95.0",
                           "@promo":"false"
                        }
                     ]
                  },
                  "Surcharges":{
                     "@size":"1",
                     "Surcharge":{
                        "@type":"TaxAndServiceFee",
                        "@amount":"229.19"
                     }
                  }
               },
               "cancellationPolicy":"We understand that sometimes your travel plans change. We do not charge a change or cancel fee. However, this property (La Quinta Inn and Suites Raleigh Cary) imposes the following penalty to its customers that we are required to pass on: Cancellations or changes made after 6:00 PM ((GMT-05:00) Eastern Time (US &amp; Canada)) on Jun 6, 2014 are subject to a 1 Night Room &amp; Tax penalty. The property makes no refunds for no shows or early checkouts.",
               "CancelPolicyInfoList":{
                  "CancelPolicyInfo":[
                     {
                        "versionId":208699803,
                        "cancelTime":"18:00:00",
                        "startWindowHours":0,
                        "nightCount":1,
                        "currencyCode":"USD",
                        "timeZoneDescription":"(GMT-05:00) Eastern Time (US &amp; Canada)"
                     },
                     {
                        "versionId":208778550,
                        "cancelTime":"18:00:00",
                        "startWindowHours":24,
                        "nightCount":0,
                        "currencyCode":"USD",
                        "timeZoneDescription":"(GMT-05:00) Eastern Time (US &amp; Canada)"
                     }
                  ]
               },
               "nonRefundable":false,
               "rateType":"MerchantStandard",
               "currentAllotment":0,
               "guaranteeRequired":false,
               "depositRequired":true,
               "taxRate":229.19
            }
         },
         "ValueAdds":{
            "@size":"3",
            "ValueAdd":[
               {
                  "@id":"2048",
                  "description":"Free Wireless Internet"
               },
               {
                  "@id":"2",
                  "description":"Continental Breakfast"
               },
               {
                  "@id":"128",
                  "description":"Free Parking"
               }
            ]
         },
         "deepLink":"https:\/\/travel.ian.com\/templates\/55505\/hotels\/135857\/book?lang=en&amp;standardCheckin=06\/07\/2014&amp;standardCheckout=06\/20\/2014&amp;selectedPrice=1654.190000&amp;supplierType=E&amp;rateCode=14587&amp;roomTypeCode=14587&amp;roomsCount=1&amp;rooms[0].adultsCount=2&amp;rateKey=0214364d-6819-4631-aa97-a162c43e0297",
         "RoomImages":{
            "@size":"1",
            "RoomImage":{
               "url":"http:\/\/media.expedia.com\/hotels\/1000000\/70000\/68000\/67977\/67977_103_s.jpg"
            }
         }
      }
   }
}

除了我真正感兴趣的所有速率信息之外,很大一部分响应都是反序列化的。在反序列化过程中不会抛出任何异常,所以我在追踪确切问题方面几乎没有什么可继续的。更具体地说,让我们来看看ChargeableRateInfo - 其中包含的所有值都是null或零。

这是我的课程,我试图将响应反序列化为:

namespace MyCustomNamespace
{
  using System.Collections.Generic;

  public class BedType
  {
    public string description { get; set; }
    public string id { get; set; }
  }

  public class BedTypes
  {
    public BedType BedType { get; set; }
    public int size { get; set; }
  }

  public class Room
  {
    public int numberOfAdults { get; set; }
    public int numberOfChildren { get; set; }
    public string rateKey { get; set; }
  }

  public class RoomGroup
  {
    public Room Room { get; set; }
  }

  public class NightlyRate
  {
    public string baseRate { get; set; }
    public string promo { get; set; }
    public string rate { get; set; }
  }

  public class NightlyRatesPerRoom
  {
    public List<NightlyRate> NightlyRate { get; set; }
    public int size { get; set; }
  }

  public class Surcharge
  {
    public decimal amount { get; set; }
    public string type { get; set; }
  }

  public class Surcharges
  {
    public Surcharge Surcharge { get; set; }
    public int size { get; set; }
  }

  public class ChargeableRateInfo
  {
    public NightlyRatesPerRoom NightlyRatesPerRoom { get; set; }
    public Surcharges Surcharges { get; set; }
    public decimal averageBaseRate { get; set; }
    public decimal averageRate { get; set; }
    public decimal commissionableUsdTotal { get; set; }
    public string currencyCode { get; set; }
    public decimal maxNightlyRate { get; set; }
    public decimal nightlyRateTotal { get; set; }
    public decimal surchargeTotal { get; set; }
    public decimal total { get; set; }
  }

  public class CancelPolicyInfo
  {
    public string cancelTime { get; set; }
    public string currencyCode { get; set; }
    public int nightCount { get; set; }
    public int percent { get; set; }
    public int startWindowHours { get; set; }
    public string timeZoneDescription { get; set; }
    public int versionId { get; set; }
  }

  public class CancelPolicyInfoList
  {
    public List<CancelPolicyInfo> CancelPolicyInfo { get; set; }
  }

  public class RateInfo
  {
    public CancelPolicyInfoList CancelPolicyInfoList { get; set; }
    public ChargeableRateInfo ChargeableRateInfo { get; set; }
    public RoomGroup RoomGroup { get; set; }
    public string cancellationPolicy { get; set; }
    public int currentAllotment { get; set; }
    public bool depositRequired { get; set; }
    public bool guaranteeRequired { get; set; }
    public bool nonRefundable { get; set; }
    public string priceBreakdown { get; set; }
    public string promo { get; set; }
    public string promoType { get; set; }
    public string rateChange { get; set; }
    public string rateType { get; set; }
    public decimal taxRate { get; set; }
  }

  public class RateInfos
  {
    public RateInfo RateInfo { get; set; }
    public int size { get; set; }
  }

  public class ValueAdd
  {
    public string description { get; set; }
    public string id { get; set; }
  }

  public class ValueAdds
  {
    public List<ValueAdd> ValueAdd { get; set; }
    public int size { get; set; }
  }

  public class RoomImage
  {
    public string url { get; set; }
  }

  public class RoomImages
  {
    public RoomImage RoomImage { get; set; }
    public int size { get; set; }
  }

  public class HotelRoomResponse
  {
    public BedTypes BedTypes { get; set; }
    public RateInfos RateInfos { get; set; }
    public RoomImages RoomImages { get; set; }
    public ValueAdds ValueAdds { get; set; }
    public string deepLink { get; set; }
    public int minGuestAge { get; set; }
    public int propertyId { get; set; }
    public int quotedOccupancy { get; set; }
    public int rateCode { get; set; }
    public string rateDescription { get; set; }
    public int rateOccupancyPerRoom { get; set; }
    public int roomTypeCode { get; set; }
    public string roomTypeDescription { get; set; }
    public string smokingPreferences { get; set; }
    public string supplierType { get; set; }
  }

  public class HotelRoomAvailabilityResponse
  {
    public List<HotelRoomResponse> HotelRoomResponse { get; set; }
    public string arrivalDate { get; set; }
    public string checkInInstructions { get; set; }
    public string customerSessionId { get; set; }
    public string departureDate { get; set; }
    public string hotelAddress { get; set; }
    public string hotelCity { get; set; }
    public string hotelCountry { get; set; }
    public int hotelId { get; set; }
    public string hotelName { get; set; }
    public string hotelStateProvince { get; set; }
    public int numberOfRoomsRequested { get; set; }
    public int size { get; set; }
    public decimal tripAdvisorRating { get; set; }
    public string tripAdvisorRatingUrl { get; set; }
    public int tripAdvisorReviewCount { get; set; }
  }

  public class ExpediaHotelRoomAvailability
  {
    public HotelRoomAvailabilityResponse HotelRoomAvailabilityResponse { get; set; }
  }
}

这可能与JSON中的@符号有关,如果是这样,我该如何解决这个问题呢?

1 个答案:

答案 0 :(得分:2)

您可以使用@属性提供名称来处理[DataMember(Name=...)]符号命名字段。

不幸的是,这意味着您必须在DTO上提供[DataContract]属性,这意味着所有属性都会成为选择加入。因此,所有属性都需要包含[DataMember]会使DTO的可读性降低。

所以你的NightlyRate DTO变成了:

[DataContract]
public class NightlyRate
{
    [DataMember(Name="@baseRate")]
    public string baseRate { get; set; }

    [DataMember(Name="@promo")]
    public string promo { get; set; }

    [DataMember(Name="@rate")]
    public string rate { get; set; }
}

NightlyRatesPerRoom将是:

[DataContract]
public class NightlyRatesPerRoom
{
    [DataMember]
    public List<NightlyRate> NightlyRate { get; set; }

    [DataMember(Name="@size")]
    public int size { get; set; }
}

显然,您必须酌情标记其他DTO。我希望有所帮助。