c# Api Json deserializes when 404, values are wrong - c#

I have a code that access a Api link and retrieves that Json values and stores them in a object list. However when there is nothing to retrieve (Link to the Api doesnt exist) it returns nothing.
However even though the Api link is wrong it still returns Json values. These are their default values that will always be there even though there is nothing that matches the ID requested.
Correct Api Json value
Below link will show values that will always return no matter what
INCorrect Api Json value
here is where i call to the Api
var spidyApi_idByName_result = api_Handler.objFromApi_nameToId(spidyApi_searchIdByName);
Here the Api is accessed and the Json is deserialized.
public RootObject objFromApi_nameToId(string url){
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
try{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream()){
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
var jsonReader = new JsonTextReader(reader);
var serializer = new JsonSerializer();
return serializer.Deserialize<RootObject>(jsonReader);
}
}
catch (WebException){
throw;
// used throw as otherwise i can not run code, function requires every path to return
// Catch never gets called
}
}
RootObject class
public RootObject GetApi(string url)
{
// ...
return serializer.Deserialize<RootObject>(jsonReader);
}
How do i go around and ignore their "default" json values? just do nothing.

You need to manage the defaults in your code. E.g. Your invalid API example will always return the count as 0. You can now use that condition to decide your program flow.
RootObject rootObject = serializer.Deserialize<RootObject>(jsonReader);
if (rootObject.count > 0)
return rootObject;
else
return null; //or any other program flow you need to execute.

Related

C# HttpClient - GET - Parse response and assert

I am using HttpClient to make a GET call and i want to parse the Json response and assert the key value pairs
This is my code
public partial class EntityClass
{
[JsonProperty("StatusCode")]
public string StatusCode { get; set; }
// more code
}
using (HttpClientHandler handler = new HttpClientHandler())
{
handler.Credentials = new NetworkCredential(#"Domain\user", "password");
using (HttpClient client = new HttpClient(handler))
{
client.BaseAddress = new Uri("https://baseURL");
client.DefaultRequestHeaders.Accept.Clear();
HttpResponseMessage response = await client.GetAsync("api/apiendpoint")
response.EnsureSuccessStatusCode();
string responsebody = response.Content.ReadAsStringAsync().Result;
var data = JsonConvert.DeserializeObject<EntityClass>(responsebody);
}
}
I can assert the response like this
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
However I want to assert each Key Value pair in the Json response. I cant get it to work with the above code
How can I access the key value pair and assert?
For example if the Json Response is:
{
StatusCode:200,
Key1: Value1,
Key2: Value2
}
I want to be able to assert like
Assert.AreEqual(200,data.StatusCode);
Assert.AreEqual(Value1, data.Key1);
Assert.AreEqual(Value2, data.Key2);
However in my code response.StatusCode returns OK and not 200
As the commenters noted, the status code is not part of the body, but you appear to be handling that part correctly.
To get to the key/value pairs as you call them, you can parse the string into an intermediate representation, and then iterate over the properties of that representation. This avoids having to have the native .NET type that would normally be populated, which may be preferable to avoid having the automation test depend on a specific type.
So, it depends on which serializer you can or have to use. Since I see JsonConvert in your code you're using Newtonsoft's code. In that case use JObject.Parse():
using Newtonsoft.Json.Linq;
...
var expectedValues = new Dictionary<string, object>();
var responsebody = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var root = JObject.Parse(responsebody);
foreach (var property in root.Properties)
{
// not tested, but you get the idea...
var expectedValue = expectedValues[property.Name];
if (expectedValue == null)
// null has to be checked via token type
Assert.IsTrue(property.Value.Type == JTokenType.Null);
else
// check they are same type AND value
Assert.AreEqual(property.Value.ToObject(expectedValue.GetType()), expectedValue);
}
The trick here is that you need to create a dictionary that maps expected keys to expected values, and then check these values against what's in the intermediate representation.
This can be used to prove that no unexpected key is in the output (because there would be no dictionary entry) and to prove that for the keys returned, their values are expected.
To also prove there are no missing keys, you can check the keys of the dictionary against the names of the returned properties.

Disable ModelBinder in .NetCore

HeyGuys
I'm working on a WebApi project that receives requests from clients and redirects these requests to other services that are not open for direct access.
By default, .Net serializes and deserializes the Json request parameters automatically, so I need to re-serialize them before calling the appropriate service. The same problem occurs when receiving the service response. I need to deserialize it before sending the response to the user; otherwise .Net framework will serialize it one more time, resulting in a "Json of Json" response.
I found this answer but it does not seem to work with .NetCore; so I tried to create my own ModelBinder that just reads the Json object and returns it.
class JsonUnformatterBinderProvider : Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
return new JsonUnformatterBinder(new SimpleTypeModelBinder(context.Metadata.ModelType));
}
}
and
class JsonUnformatterBinder : IModelBinder
{
private readonly IModelBinder _fallbackBinder;
public JsonUnformatterBinder(IModelBinder fallbackBinder)
{
_fallbackBinder = fallbackBinder;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
string currMethod = bindingContext.ActionContext.HttpContext.Request.Method;
if ("POST".Equals(currMethod) || "PUT".Equals(currMethod))
{
string strData = new StreamReader(bindingContext.ActionContext.HttpContext.Request.Body).ReadToEnd();
bindingContext.Result = ModelBindingResult.Success(strData);
return Task.CompletedTask;
}
return _fallbackBinder.BindModelAsync(bindingContext);
}
}
This code is very simple, it was my first attempt and it worked well for my purposes. However, I still get the "Json of Json" problem when I take the second service answer and returns back to the user.
I basically have no idea what I can do to overcome this, so any workaround is welcome here.
If you need just redirect a request without modification, you could read it from input stream directly and send it to inner service. You could also use such approach to read responce from inner service.
//1. Set empty parameter list in action then neither serializator nor model binder are not invoked.
public async Task<ContentResult> ProxyAction(/*empty parameter list*/)
{
var newUrl = #"https://stackoverflow.com";
var data = this.Request.Body;
using (var client = new HttpClient())
{
//2. Read request body from input stream.
var reader = new StreamReader(data);
var json = reader.ReadToEnd();
using (var content = new StringContent(json))
{
//3. Set correct content type
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(this.Request.ContentType);
//4. Post request to inner service
var response = await client.PostAsync(newUrl, content);
//5. Read response without deserialization
var innerResponse = await response.Content.ReadAsStringAsync();
var contentType = response.Content.Headers.ContentType.ToString();
var statusCode = response.StatusCode;
//6. Return inner response without serialization
var outerResponse = this.Content(innerResponse, contentType);
outerResponse.StatusCode = (int)statusCode;
return outerResponse;
}
}
}

Unable to Parse JSON Response

I have a service that sends JSON response. The controller method looks as follows:
string varStr = "{proper JSON here}";
public string GetListofResourcesInSubscription(string subscriptionId)
{
// Uncomment any option below to test. The error persists either way.
//return varStr; --- Option 1
return JsonConvert.SerializeObject(JObject.Parse(varStr)); // Option 2
}
The method that gets the response is like the following:
response = outgoingRequest.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
responseStream = response.GetResponseStream();
using (var reader = new StreamReader(responseStream))
{
string strResp = reader.ReadToEnd();
JObject joResponse = JObject.Parse(strResp); // throws error
JArray objArray = (JArray)joResponse["value"];
// other processing
}
}
Irrespective of the return statement selected in the controller method above, the response parser is always throwing an error while it is trying to parse the response.
Changing the parsing line to the following resolves the issue but it is not clear to me why it is so.
JObject joResponse = JObject.Parse(JsonConvert.DeserializeObject<string>(strResp));
Also, I want to know what is the correct way of sending a JSON response from an ASP.NET web api2 controller. I don't want to use models for creating the response because I have JSON strings that I want to return directly instead of creating models out of them.
Update 1:
The error is the following:
"Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '', line 1, position 6546."} System.Exception {Newtonsoft.Json.JsonReaderException}
You can't deserialize a complex JSON object back to a string. Your example won't work, because you are assuming the JSON evaluates to a string:
JObject joResponse = JObject.Parse(JsonConvert.DeserializeObject<string>(strResp))
You might have more success either using a JObject, or the alternative is to deserialize into a Dictionary, or into a known type.
var dictionary = JsonConvert.DeserializeObject<<Dictionary<string,object>>(strResp);
The problem here was the return type of the controller function. As it was returning string, the serialization to string was required to get correct result. The correct way of returning JSON is to return a JToken as explained here. So the controller needs to be changed to the following:
public JToken GetListofResourcesInSubscription(string subscriptionId)
{
return JObject.Parse(varStr);
}

What is the best way of reading/parsing WEB API 2 IHttpActionResult responses?

I have following web api method:
public IHttpActionResult Get(int id)
{
var person = _personRepository.GetPersonByID(id);
if (person == null)
return NotFound();
return Ok<Person>(person);
}
And following client calling method:
var data = default(IEnumerable<T>);
var response = _client.GetAsync(relativeUri).Result;
response.EnsureSuccessStatusCode(); // Throw on error code.
if (response.IsSuccessStatusCode)
{
//string dataString = response.Content.ReadAsStringAsync().Result;
data = response.Content.ReadAsAsync<IEnumerable<T>>().Result;
}
else
{
//return response status code/reason phrase
}
after ReadAsAsync call is finished, data variable indicates a collection of type T with count matching returned rows but all objects (elements) are having null valued properties or empty.
Actual values are not being populated in properties.
Fiddler shows the JSON string. Even, ReadAsStringAsAsync() method returns JSON string.
Is there a better way to parse JSON into T type using one of ReadAsXXXX() methods?
Thanks,
-Jignesh
I just wanted to update that I have found the root cause of the issue that I was facing.
The code sample that I mentioned is actually the correct way of calling web api methods.
In my case, JSON string was formatted in Camel Casing at server side and at client side, default formtting was used.
this is server side code which was causing the issue:
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
As soon as this was removed, it started working.
Clearly, ReadAsAsync method could not find the matching properties and therefore all values were being dropped.
Thanks,
-Jignesh

Using the contents of a JsonObject on aspx web page

I am trying to use a HTTP request to return the contents of a json string from google shopping api. What I have so far seems to be working but I would like to know how I can use the contents of the object to display the data on a page.
public string HttpGet(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
try
{
using (Stream stream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(stream);
return reader.ReadToEnd();
}
}
finally
{
response.Close();
}
}
protected void submit_Click(object sender, EventArgs e)
{
string json = HttpGet("https://www.googleapis.com/shopping/search/v1/public/products?key={KEY}4&country=UK&q=BX80637153570K&rankBy=price:ascending&maxResults=1&alt=json");
dynamic obj = JsonObject.Parse(json);
}
Ok looking at the responses it looks as though I need a C# class for the data returned in json. I have created a classes using json2csharp.com. This is the data I need to return from the Json and display on the page. Maybe it will help explain my problem better.
https://www.googleapis.com/shopping/search/v1/public/products?key=AIzaSyCC0j59RBeGNtf2W2ft6avhfoTdJ1FQ2c4&country=UK&q=BX80637153570K&rankBy=price:ascending&maxResults=1&alt=json
Can anyone advise how I can use this information on my website. I am a little lost now as I'm new to all this and have tried several different methods.I don't need all of the returned data if that makes a difference? Just price and link.
Supposing dynamic obj is rightly filled you can use it's content in web page
For examples, if json is:
{
"error" : {
"code": 400,
"message": "Bad Request"
}
}
You can access object properties with code like this:
Response.Write("Error code is" + obj.error.code);
Of course Response.Write is only a sample on how you can send retrieved data to the page.
Edit 1:
It seems json converter used in question is not working or not working right.
In many cases, it's overkill to create a concrete class only to parse a json, expecially since C# 4 that can use ExpandoObject
This is a sample on how you can deserialize in a dynamic object without the need to create a concrete object
var url = "http://www.google.com/ig/calculator?hl=en&q=100USD=?EUR";
string json = HttpGet(url);
//this is json string:
//{lhs: "100 U.S. dollars",rhs: "78.1799703 Euros",error: "",icc: true}
//now convert in a dynamic object
var jss = new DynamicJsonConverter();
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
dynamic obj = serializer.Deserialize(json, typeof(object));
//now you have access to json content
string text1 = obj.lhs;
string text2 = obj.rhs;
DynamicJsonConverter class can be created using code you can find here:
Deserialize JSON into C# dynamic object?
I think you need to deserialize the response
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
You will need to create a class with the property resulted by the response.
Say test class
class Test
{
//define a similar property here
// which you suppose it will be return in the response
}
Then
Test routes_list = (Test)json_serializer.DeserializeObject(yourjson);
Edit 1
Or you can go through this link
How to Convert JSON object to Custom C# object?

Categories