Reputation: 107
I am trying to call two API's and store their response. Below is the API response type:
API1 response:
{
"Name": "Apple",
"Expiry": "2008-12-28T00:00:00",
"Price": 3.99,
"Sizes": [
"Small",
"Medium",
"Large"
]
}
API2 Response:
["Name=xyz, Id=1, Version=1","Name=abc, Id=1, Version=2","Name=hgf, Id=1, Version=3","Name=utgds, Id=1, Version=4","Name=kfgf, Id=2, Version=1"]
below is the code to call an API and get the result set.
var jsonObj = Get<SomeClass>("API_URL1");
var jsonObj2 = Get<Test>("API_URL2");
public T Get<T>(string requestUri)
{
T response = default(T);
using (var handler = new HttpClientHandler { Credentials = CredentialCache.DefaultNetworkCredentials })
{
using (var httpClient = CreateNewRequest(handler))
{
var httpTask = httpClient.GetAsync(requestUri);
var response = task.Result;
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
var res = JsonConvert.DeserializeObject<T>(result);
}
}
}
return res;
}
private HttpClient CreateNewRequest(HttpClientHandler handler)
{
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
public class Test
{
public string Name { get; set; }
public int Id { get; set; }
public int Version { get; set; }
}
Similarly i have created a class to hold the API1 response. I am able to store API1 Response however while storing API2 response i am getting this error message.
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface..
any idea/hints on this?
Thanks!
Upvotes: 2
Views: 3156
Reputation: 9143
I tested what i said in comment. Second response is JSON array of strings. You should deserialize it as array of string (string[]
) or collection of strings (List<string>
). Following works as expected:
var response = "[\"Name=xyz, Id=1, Version=1\", \"Name=abc, Id=1, Version=2\", \"Name=hgf, Id=1, Version=3\", \"Name=utgds, Id=1, Version=4\", \"Name=kfgf, Id=2, Version=1\"]";
var result = JsonConvert.DeserializeObject<string[]>(response);
To summarise: instead of Get<Test>
use Get<string[]>
. You just have to parse strings, but this seems to be another problem.
Full demo below (url invocations intentionally mocked):
class Program
{
static void Main(string[] args)
{
var invoker = new JsonMockInvoker();
var jsonObj = invoker.Get<SomeClass>("API_URL1");
var jsonObj2 = invoker.Get<string[]>("API_URL2");
}
}
class SomeClass
{
public string Name { get; set; }
//other properties
}
public class JsonMockInvoker:JsonInvoker
{
public override string InvokeRest(string url)
{
if (url == "API_URL1")
return "{\"Name\": \"Apple\",\"Expiry\": \"2008-12-28T00:00:00\",\"Price\": 3.99,\"Sizes\": [\"Small\",\"Medium\",\"Large\"]}";
if (url == "API_URL2")
return "[\"Name=xyz, Id=1, Version=1\", \"Name=abc, Id=1, Version=2\", \"Name=hgf, Id=1, Version=3\", \"Name=utgds, Id=1, Version=4\", \"Name=kfgf, Id=2, Version=1\"]";
throw new NotImplementedException();
}
}
public class JsonInvoker
{
public T Get<T>(string requestUri)
{
var result = InvokeRest(requestUri);
return result != null ? JsonConvert.DeserializeObject<T>(result) : default(T);
}
public virtual string InvokeRest(string url)
{
using (var handler = new HttpClientHandler { Credentials = CredentialCache.DefaultNetworkCredentials })
using (var httpClient = CreateNewRequest(handler))
{
var httpTask = httpClient.GetAsync(url);
var response = httpTask.Result;
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsStringAsync().Result;
}
}
return null;
}
private HttpClient CreateNewRequest(HttpClientHandler handler)
{
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
}
String values are not in JSON format - you have to parse them manually:
//parse to typed object
var parsedObject = jsonObj2.Select(a => new
{
Id = Regex.Match(a, "(?<=Id=)[^,]*").Value,
Name = Regex.Match(a, "(?<=Name=)[^,]*").Value
});
//parse to dictionary
var regex = new Regex("([\\s]|^)(?<key>[^=]+)=(?<value>[^,]*)");
var parsed = jsonObj2.Select(a =>
{
var dictionary = new Dictionary<string, string>();
foreach (Match match in regex.Matches(a))
dictionary[match.Groups["key"].Value] = match.Groups["value"].Value;
return dictionary;
});
Upvotes: 2