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);
}
Related
I have a service that accepts JSON, and as a part of forwarding the requests from the Browser to a web server to the service (also an HTTP Server), I have this code:
if (Request.HttpMethod.ToLower() == "post")
{
var jsonObj = ObjectFromRequestBody<Dictionary<string, string>>();
if (jsonObj != null)
{
// uses Newtonsoft JSON Serializer to re-serialize the object; this is RestSharp
requestToForward.AddJsonBody(jsonObj);
}
}
ObjectFromRequestBody looks like this:
protected T ObjectFromRequestBody<T>()
{
Stream requestStream = Request.InputStream;
requestStream.Seek(0, SeekOrigin.Begin);
string json = new StreamReader(requestStream).ReadToEnd();
var payload = JsonConvert.DeserializeObject<T>(json);
return payload;
}
Now, this works fine, assuming that it -is- a JSON object being posted. (a KVP collection)
However, I imagine in the case that the payload is simply a value (int, string, boolean, or heck, even an array), this will error out.
I've tried simply deserializing to a type of Object results in it being re-serialized into an array of empty arrays; probably because Newtonsoft's JSON Serializer by default deserializes Objects to JObjects, which is essentially an enumerable of KVPs.
Is there a type agnostic way to get from Object to serializing to the appropriate type without essentially writing a series of conditional statements?
In this case a much better solution is to simply pipe the request body directly into the RestSharp request.
if (Request.HttpMethod.ToLower() == "post")
{
var requestBody = new StreamReader(Request.InputStream).ReadToEnd();
if (!string.IsNullOrWhiteSpace(requestBody))
{
request.AddHeader("Content-Type", "application/json");
request.AddParameter("", requestBody, RestSharp.ParameterType.RequestBody);
}
}
Though, would still be interested in hearing how to type-agnostically serialize a JObject properly.
Background
I'm sending JSON in my body to my API controller but keep getting the following error.
{"":["Unexpected character encountered while parsing value: {. Path
'', line 1, position 1."]}
My HTTP request
HttpClient client = new HttpClient();
HttpRequest httpRequest;
HttpResponseMessage httpResponse = null;
httpRequest = new HttpRequest("", HostnameTb.Text, null);
var values = new Dictionary<string, string>
{
{ "APIKey", APIKeyTb.Text }
};
string json = JsonConvert.SerializeObject(values);
StringContent content = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
httpResponse = client.PostAsync(HostnameTb.Text, content).Result;
var responseString = await httpResponse.Content.ReadAsStringAsync();
My Controller looks like this.
[HttpPost]
public void Post([FromBody] string value)
{
//Never gets here.
}
The Json in the body.
{"APIKey":"1283f0f8..."}
Question
I would prefer to use the .Net Core [From Body] functionality, rather than getting the content manually.
I would expect the JSON string to be available in the string Value parameter.
What am I missing?
ASP.NET Core tries to deserialize {"APIKey":"1283f0f8..."} from JSON into a string value, and fails, because it expects the input to be a valid JSON string.
In other words, if your body was "{\"APIKey\":\"1283f0f8...\"}" you would have the JSON string in the input variable as you expect.
In order to get the APIKey value without changing the HTTP request, create an input type:
public class Input
{
public string ApiKey { get; set; }
}
and use that as the input of your controller action:
[HttpPost]
public void Post([FromBody] Input input)
{
var apiKey = input.ApiKey;
// etc
}
Alternatively, change your HTTP request to send a string:
// ...
var content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");
// ...
Note the use of JsonConvert.SerializeObject() instead of ToString(); "foo".ToString() is still just "foo", while you want "\"foo\"".
That's not how this works. [FromBody] invokes a serializer to deserialize the request body. Then, the modelbinder attempts to bind that to the param. Here, it cannot do that because you're binding to a string, and the request body is a dictionary. Essentially what's happening under the hood (pseudo-code) is:
value = JsonConvert.DeserializeObject<string>(dictionaryAsJson);
You're getting a deserialization error from JSON.NET because it can't parse the JSON into a string.
If you want the value as a string, then you should post is as something like text/plain instead of application/json. Otherwise, you'll need to bind to a type that actually represents the JSON object coming in, which would be a Dictionary<string, string> here.
I had the same issue with ASP.NET Core 3.1. I was POSTing a JSON to my API controller that looked like:
public JsonResult Save([FromBody]MainDetails obj){ ... }
The problem in my case was that a property ChildDetails.StartDate of my MainDetails object was of type DateTime, and I was sending a null value in JSON. This was causing the deserialization to fail at the controller. I changed the property type to DateTime? from DateTime to make it work.
Basically, one needs to check and ensure that the JSON that you POST is valid for the target object to which you are deserializing it. If you have non-nullable properties for which the value sent in JSON is null, then your deserialization will fail (without telling you why).
Hope this helps.
I have this simple method which suppose to get weather data, when I call it this error occur:
System.Runtime.Serialization.SerializationException was unhandled by user code
HResult=-2146233076
Message=There was an error deserializing the object of type UWpWeather.RootObject. Encountered unexpected character '<'.
public async static Task <RootObject> GetWeather(double lat, double lng) {
var http = new HttpClient();
var response = await http.GetAsync("http://api.openweathermap.org/data/2.5/forecast/daily?q=leeds&type=accurate&mode=xml&units=metric&cnt=3&appid= MY AIP-KEY");
string result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof (RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject) serializer.ReadObject(ms);
return data;
}
The API does not honour any of the HTTP content or Accept headers you pass through on the request, but rather it sets the content-type of the response based on the query string parameter.
Your initial URL:
http://api.openweathermap.org/data/2.5/forecast/daily?q=leeds&type=accurate&mode=xml&units=metric&cnt=3&appid=
MY AIP-KEY"
What it should be:
http://api.openweathermap.org/data/2.5/forecast/daily?q=leeds&type=accurate&mode=json&units=metric&cnt=3&appid=
MY AIP-KEY"
That should allow you to deserialize it into your RootObject correctly.
Caveat: I don't have your root object implementation, so I could only verify up until getting a JSON-formatted response back.
I found the answer, my first mistake was using Xml instead of Json when calling my data. second, when I used this website (json2csharp) to convert Json to series of classes that represent my Json it created it fine except one which created as a list public List<List> list { get; set; }
I simply removed that one and my code now is working just fine. thanks all for your support.
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.
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?