1

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.


UPDATE

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);
    }
}
3
  • json2csharp.com Is a tool enable you to create models from jsonresult Commented Jun 13, 2016 at 6:45
  • @Eldho the model it generate is complex, it generate one model per each result, if the array returns 200 row, it generate 200 class per each row, and one for container :| Commented Jun 13, 2016 at 6:49
  • try to map to a dictionary object on this case Commented Jun 13, 2016 at 6:51

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

7 Comments

unfortunately it's not a restful service, it's just a normal call a url and receive data service, which use query strings
It should work anyway. You can still use the code provided by using parameters in the method signature.
here's waht i did: var client2 = new RestClient(); RestRequest req = new RestRequest(command); var executeAsGet = client2.Execute<CityResponseVM>(req).Data; i tried to pass command to either of RestClient or RestRequest, i also tried to use both CityVM, and CityResponseVM, all of them returns null.
I've updated my answer. I think the problem is the JSON-format.
I suggest that you try to deserialize as Dictionary.
|
1

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.

4 Comments

With either CountryVM or CountryResponseVM or even CityResponseVM or CityVM: Additional information: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[Otrams.Controllers.CountryVM]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
Also, make sure ALL your objects in code are [Serializable]. This is important.
well it did worked but through what smokednes said, and i test it, it didn't required serializable attribute, BTW thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.