我正在与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 & Canada)) on Jun 6, 2014 are subject to a 1 Night Room & 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 & Canada)"
},
{
"versionId":208778550,
"cancelTime":"18:00:00",
"startWindowHours":24,
"nightCount":0,
"currencyCode":"USD",
"timeZoneDescription":"(GMT-05:00) Eastern Time (US & 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&standardCheckin=06\/07\/2014&standardCheckout=06\/20\/2014&selectedPrice=1654.190000&supplierType=E&rateCode=14587&roomTypeCode=14587&roomsCount=1&rooms[0].adultsCount=2&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中的@符号有关,如果是这样,我该如何解决这个问题呢?
答案 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。我希望有所帮助。