Reputation: 2021
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);
}
}
Upvotes: 1
Views: 4345
Reputation: 10851
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.
Upvotes: 1
Reputation: 3222
Grab NewtonSoft.JSON from NuGet and install it with your project. Then make the following:
Mark your CountryVM class with the [Serializable] or [DataContract] attribute (I always forget which goes where)
Then, you simply convert your Response.Content as JSON, and serialize it:
var rawData = Response.Content.ReadAll(); // forgot the proper syntax, just get the content as string
var myList = JsonConvert.DeserializeObject<IEnumerable<CountryVM>>(rawData);
"myList" now is an enumerable collection as you wanted. Please note that the syntax is probably wrong as I'm replying off the top of my head, but the procedure is valid and should solve your problem.
Upvotes: 1