One of our customer require some data, which should be obtained from a service provider. the service is written in PHP, and is more like a web api than a soap or wcf service, and the response is in following format:
{"0":{"Code":"AL","Name":"ALBANIA"},"1":{"Code":"DZ","Name":"ALGERIA"},"2":{"Code":"AD","Name":"ANDORRA"},"3":{"Code":"AO","Name":"ANGOLA"},"4":{"Code":"AI","Name":"ANGUILLA"},"5":{"Code":"AG","Name":"ANTIGUA"},"6":{"Code":"AR","Name":"ARGENTINA"},"7":{"Code":"AM","Name":"ARMENIA"},"8":{"Code":"AW","Name":"ARUBA"},"9":{"Code":"AU","Name":"AUSTRALIA"},"10":{"Code":"AT","Name":"AUSTRIA"},"11":{"Code":"AZ","Name":"AZERBAIJAN"},"12":{"Code":"BS","Name":"BAHAMAS"},"StartTime":"2016-06-13 04:57:15","EndTime":"2016-06-13 04:57:15"}
As you can see it's an array but in a format of an object, that's what cause me issues.
I use HttpClient and my model is like this:
public class CountryVM
{
public string Code { get; set; }
public string Name { get; set; }
}
i also extend it to make it part of following model:
public class CountryResponseVM
{
public List<CountryVM> CountryVMs { get; set; }
public string StartTime { get; set; }
public string EndTime { get; set; }
}
when i run the following code:
using (var client = new HttpClient())
{
var response = client.PostAsync(command, new StringContent(string.Empty)).Result;
if (response.IsSuccessStatusCode)
{
List<CountryVM> readAsAsync = response.Content.ReadAsAsync<List<CountryVM>>().Result;
}
}
Either with 'CountryVM' or with 'CountryResponseVM' class, it throw following exception:
An exception of type 'System.Net.Http.UnsupportedMediaTypeException' occurred in System.Net.Http.Formatting.dll but was not handled in user code
Additional information: No MediaTypeFormatter is available to read an object of type 'List`1' from content with media type 'text/html'.
How can i reformat the response, or parse json object as an array before calling
ReadAsAsync
method.
I also have another model, The city which is listed under countries. The city model seem to be more right, it has array instead of object, and gave the array a name, but still i have same issue with it as i had with the countries, in all cases.
Response:
{"CityInfo":[{"CityCode":"TIA-","Name":"Albania"},{"CityCode":"TIA-7","Name":"Berat"},{"CityCode":"TIA-3","Name":"Durres"},{"CityCode":"TIA-4","Name":"Korce"},{"CityCode":"TIA-8","Name":"Pogradec"},{"CityCode":"TIA-2","Name":"Sarande"},{"CityCode":"TIA-6","Name":"Shkoder"},{"CityCode":"TIA-1","Name":"Tirana"},{"CityCode":"TIA-5","Name":"Vlore"}],"StartTime":"2016-06-13 06:03:34","EndTime":"2016-06-13 06:03:34"}
Models:
public class CityResponseVM
{
public List<CityVM> CityInfo { get; set; }
public string StartTime { get; set; }
public string EndTime { get; set; }
}
public class CityVM
{
public string CityCode { get; set; }
public string Name { get; set; }
}
And Request:
string command = Otrams.Url+Otrams.GetAction(ServiceAction.CityList) +"&username="+Otrams.Username+"&password="+Otrams.Password+"&gzip=no&country=AL";
using (var client = new HttpClient())
{
var response = client.PostAsync(command, new StringContent(string.Empty)).Result;
if (response.IsSuccessStatusCode)
{
//CityResponseVM readAsAsync = response.Content.ReadAsAsync<CityResponseVM>().Result;
var rawData = response.Content.ReadAsStringAsync().Result;
var myList = JsonConvert.DeserializeObject<IEnumerable<CityVM>>(rawData);
}
}
Use two objects, one for deserializing, and one to actually contain the result.
public class MyTempModel
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
[JsonExtensionData]
public Dictionary<string, object> Countries { get; set; }
}
public class MyRealModel : Dictionary<int, CountryVM>
{
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
}
Deserialize:
var myList = JsonConvert.DeserializeObject<MyTempModel>(jsonResult);
var model = new MyRealModel
{
StartTime = myList.StartTime,
EndTime = myList.EndTime
};
foreach (var temp in myList.Countries)
{
// Deserialize the actual ContryVm.
var obj = JsonConvert.DeserializeObject<CountryVM>(temp.Value.ToString());
int key = 0;
int.TryParse(temp.Key, out key);
model.Add(key, obj);
}
The key component here is to use JsonExtensionData
, as suggested here: How to serialize a Dictionary as part of its parent object using Json.Net. It will enable the dictionary format, with extra properties such as StartTime
and EndTime
.
A more advanced solution would be to use a JsonConverter.
See chat for more info.