JsonDeserializer check before try to convert Model - c#

Read simple api call code bellow. Here i am getting call response in- IRestResponse response and its a json response. Then using JsonDeserializer() i am trying to convert it to a C# Model which is WallMartData model. ( i think i dont need to share model code here bcoz it doesn't matter for this question ). Now from this same response sometime i will get a json response which match with my model WallMartData and some time it will return other json response. Now my question is- before i try to convert my json response to WallMartData Model i want to check if this is a valid convertable json. If its not valid convartable for this WallMartData model then it will skip try to convert. Bcoz when its fails to convert i am getting invalid json exception on c#. Thats why i need to check before try to convert. Any solution?
string url = "http://api.example.com/v1/items?apiKey=" + Token + "&upc=" + UPC;
var client = new RestClient(url);
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
var deserializer = new JsonDeserializer();
var wmr = deserializer.Deserialize<WallMartData>(response);

You can try to create a method use try .... catch to check the JSON string is or isn't valid.
private static bool IsValidJson<T>(string strInput,out T obj)
{
obj = default(T);
try
{
obj = JsonConvert.DeserializeObject<T>(strInput);
return true;
}
catch (JsonReaderException jex)
{
return false;
}
catch (Exception ex)
{
return false;
}
}
Then you can use bool to check the DeserializeObject whether success.
WallMartData wmr;
if(IsValidJson<WallMartData>(response,out wmr)){
//... your logic with wmr
}

I think you can just use try catch block and it will be enough. But if you really need to validate your JSON, you can use JSON Schema. You can generate schema for your class using JsonSchemaGenerator

I suggest using JsonSchema by Json.Net
more info here
let's say that your WallMartData class looks like this
public class WallMartData
{
[JsonProperty("email", Required = Required.Always)]
public string Email;
[JsonProperty("first_name")]
public string firstName;
[JsonProperty("last_name")]
public string lastName;
}
Then you can easily use the schema checker
JSchemaGenerator generator = new JSchemaGenerator();
JSchema schema = generator.Generate(typeof(WallMartData));
string json = #"...";
JObject wallMartData = JObject.Parse(json);
if(wallMartData.IsValid(schema))
{
//if json matching the schema aka the class account
}
else
{
//the json is invalid
}

Related

C# Extracting JSON data

My code here to get data from Wikipedia:
string URL = $"https://en.wikipedia.org/w/api.php?action=query&format=json&list=&titles={query}&redirects=1";
WebRequest wrREQUEST;
wrREQUEST = WebRequest.Create(URL);
wrREQUEST.Proxy = null;
wrREQUEST.Method = "GET";
WebResponse response = wrREQUEST.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream());
string responseData = streamReader.ReadToEnd();
JObject jsonData = JObject.Parse(responseData);
var jsonQuery = jsonData["query"];
string pageID = (string)jsonQuery;
But I keep getting
Exception thrown: 'System.ArgumentException' in Newtonsoft.Json.dll
and the json data looks like this:
{
"batchcomplete":"",
"query":{
"pages":{
"31717":{
"pageid":31717,
"ns":0,
"title":"United Kingdom"
}
}
}
}
I also want to know since "pages":{"31717":{}} is an ID which I will not know in advance, how can I get that 31717 from enumerating the data?
The error is because you are trying to explicitly convert JObject into a string, which is not possible using conversion, only by using Serilization.
But I understand you actually want the "PageId", which by the json structure, look like you need to take the "first key" from the response.
(Actually there are more ways)
So instead of
string pageID = (string)jsonQuery;
One possible way, will be using this
((JProperty)jsonQuery["pages"].First()).Name
Please find resolution of yout request, it might be possible that some time u will not get the first element value and it will trigger some exception.
Please replace your line :
string pageID = (string)jsonQuery;
with
**var jToken = jsonQuery["pages"].First;
if (jToken != null)
{
string pageID = ((JProperty) jToken).Name;
}**

Parse JSON response where the object starts with a number in c#

I'm trying to deserialise a response from a REST service into C# Strongly typed classes - however I've ran into the same issue has in this post:
How do I output this JSON value where the key starts with a number?
However I have the issue that you cannot start a variable name in c# with a number - meaning that the class at that level just deserialises into null.
I need to know how to get into the objects and deserialise them into the c# classes.
My Current code is below:
public static async Task<T> MakeAPIGetRequest<T>(string uri)
{
Uri requestURI = new Uri(uri);
using (HttpClient client = new HttpClient())
{
HttpResponseMessage responseGet = await client.GetAsync(requestURI);
if (responseGet.StatusCode != HttpStatusCode.OK)
{
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
responseGet.StatusCode,
responseGet.Content));
}
else
{
string response = await responseGet.Content.ReadAsStringAsync();
T objects = (JsonConvert.DeserializeObject<T>(response));
return objects;
}
}
}
EDIT: I cannot change the way the service is pushing the data back
The correct way to deal with this was to use the JsonProperty tag on the target classes to define what Json property to listen for, as shown below (referenced from https://stackoverflow.com/questions/24218536/deserialize-json-that-has-some-property-name-starting-with-a-number
public class MyClass
{
[JsonProperty(PropertyName = "24hhigh")]
public string Highest { get; set; }
...
Thanks to #HebeleHododo for the comment answer
While there is no direct way to construct a strongly typed C# object in this case, You could still have the capabilities to parse the json string manually and extract values -
var json = "{'1':{'name':'test','age':'test'}}";
var t = JObject.Parse(json)["1"];
Console.WriteLine(t["name"]); //test
Console.WriteLine(t["age"]); //test

ASP.NET MVC handle request error

In my .Net MVC app I need to handle server side validation. If there was something wrong with request I get this:
{
"validationMessage": message
}
with StatusCode = 200.
Otherwise of course I get response proper for the call. My issue is that I have troubles checking for validation messages and then deserializing response (I always get null there though fiddler shows me that response comes back).
public static async Task<Response<T>> Response<T>(HttpResponseMessage response)
{
var res = new Response<T>();
if (response.IsSuccessStatusCode)
{
//check for validation messages
var serverErrorInfo = await response.Content.ReadAsAsync<ServerError>();
if (serverErrorInfo.ValidationMessage != null)
{
res.ErrorInfo = new ErrorInfo(serverErrorInfo.ValidationMessage);
}
else
{
var result = await response.Content.ReadAsAsync<T>();
res.IsSuccess = true;
res.Result = result;
}
return res;
}
What am I doing wrong? Does the response get disposed after first attempt to read it as a ServerError? Since I use generics I cannot first check if there is response and than read the validationMessage.
ServerError Code:
[JsonObject]
public class ServerError
{
public string validationMessage{ get; set; }
}
Probably a deserialization issue. Have you tried ValidationMessage with a capital V in the json response? Also, is serverErrorInfo null entirely, or is just the property ValidationMessage null? Can you check what the value of response.Content is, right before deserialization to ServerError?
In the end the solution was just using some ugly code:
var serverErrorInfo = JsonConvert.DeserializeObject<ServerError>(await response.Content.ReadAsStringAsync());
I am very unsure why ReadAsAsync fails there.

Web API json responds faulty json [duplicate]

I am trying to fix an ASP.NET WebAPI method where a Json response is required. However it's returning a string instead.
Initially it was returing XML format, but I've added this line to the mvc code in App_Start\WebApiConfig.cs in order to return Json by default.
config.Formatters.Remove(config.Formatters.XmlFormatter);
We've updated the c# method as follows to use NewtonSoft:
public string Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
string resp = DynAggrClientAPI.openSession(userid, pwd);
JsonSerializer ser = new JsonSerializer();
string jsonresp = JsonConvert.SerializeObject(resp);
return resp;
}
The resp var is coming back as a string type:
"{status:\"SUCCESS\",data:[\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\"]}"
and jsonresp var looks like this :
"\"{status:\\\"SUCCESS\\\",data:[\\\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\\\"]}\""
and in Chrome's F12 dev tools, the data object is :
""{status:\"SUCCESS\",data:[\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\"]}""
and in Console tools, the result of angular.fromJson(data) :
"{status:"SUCCESS",data:["4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d"]}"
I would appreciate some advice on how to properly return the Json object, and NOT in any string type.
UPDATE
By intercepting the resp var, and using Mr. Chu's suggestion below, I can successfully achieve a nice clean Json object on the client.
The key is that resp needs to contains double quotes around both key:value pairs:
public HttpResponseMessage Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
string resp = DynAggrClientAPI.openSession(userid, pwd);
resp = "{\"status\":\"SUCCESS\",\"data\":[\"194f66366a6dee8738428bf1d730691a9babb77920ec9dfa06cf\"]}"; // TEST !!!!!
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(resp, System.Text.Encoding.UTF8, "application/json");
return response;
}
in Chrome console, the response is :
Object {status: "SUCCESS", data: Array[1]}
data: Array[1]
status: "SUCCESS"
__proto__: Object
resp is already a JSON string, but it is not valid JSON (the keys are not wrapped in quotes ("). If it is returned to angular, the JavaScript JSON.parse() method is unable to deserialize it. However, you can use JSON.NET in deserialize it to a JObject and serialize it again into valid JSON and create your own HttpResponseMessage...
public HttpResponseMessage Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
var jObject = JObject.Parse(resp);
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(jObject.ToString(), Encoding.UTF8, "application/json");
return response;
}
Or you can just return the JObject and have Web API serialize it for you...
public JObject Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
var jObject = JObject.Parse(resp);
return jObject;
}
In either case, the Web API call should return this JSON, which is now valid...
{
"status": "SUCCESS",
"data": [
"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d"
]
}
In the angular code, you'd have to dig out the session id which is stored in an array called data...
userService.openUserSession(rzEnvJson).then(function (response) {
var sessionResponse = response.data; // or simply response, depending if this is a promise returned from $http
$rootScope.rgSessionVars.sessionID = sessionResponse.data[0];
});
The key to what is going on here is in the comment made by Mike Cheel; serialization is happening twice, once in the OP's code and once by Asp.Net WebAPI. That is why a string is returned instead of a Json object.
I was encountering the exact same thing. Here is a hello world example showing the problem. I first did something like this:
[Route("getall")]
public string GetAllItems()
{
var result = new
{
x = "hello",
y = "world"
};
return JsonConvert.SerializeObject(result);
}
I then tried to so something like this, thinking that I needed to return IHttpActionResult to resolve this:
[Route("getall")]
public IHttpActionResult GetAllItems()
{
var result = new
{
x = "hello",
y = "world"
};
return Ok(JsonConvert.SerializeObject(result));
}
Both these controller actions gave me a string rather than the Json object that I was wanting; so I go this:
"{\"x\":\"hello\",\"y\":\"world\"}"
Finally I saw the comment by Mike and realized that I needed to return the .Net object directly and just let WebAPI handle the serialization. So instead of returning this:
return Ok(JsonConvert.SerializeObject(result));
return this:
return Ok(result);
Then I got the result that I was expecting:
{"x":"hello","y":"world"}
I don't see what this has to do with AngularJS, but your problem is simple. Your data object is JSON encoded. So you could almost certainly access data.JsonRequestBehavior and it would be 1. But your Data field inside it is AGAIN JSON-encoded. You need to decode it before trying to use it - it's just a string when you get to this callback:
var myData = angular.fromJson(data.Data);
console.log(myData.data);
Note that your data.Data object is itself another wrapper - an array. You almost certainly want myData.data[0] to go into that sessionID field...
These other solutions weren't working for me, but I was able to get something like this to work:
[HttpGet]
public async Task Get(CancellationToken cancellationToken)
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
await using (Stream contentStream = await DynAggrClientAPI.openSessionStreamAsync(userid, pwd, cancellationToken))
{
Response.StatusCode = (int)HttpStatusCode.OK;
Response.ContentType = "application/json";
await contentStream.CopyToAsync(Response.Body, cancellationToken);
}
}
I had a similar problem (raw json in string, like resp) and this worked fine for me in .Net 6. I haven't checked previous versions.
[HttpGet]
public IActionResult Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
return Content(resp, "application/json"):
}

Consuming json input from url ,deserialize into c# & retrieve values from web API

I have been stuck in trying figure out the syntax for a particular scenario.
Scenario: When I give a JSON string as argument in the URL, I want the url to consume an API and retrieve the details from that API, as per the given input.
My project needs deserialization into c# so, I used JSON.NET for the same.
Say: input is - Profile-id : 123456789
The output should consume details pertaining to that Pid and display.
The i/p given in url:
https://www.docscores.com/widget/api/org-profile/demo-health/npi/123456789
The expected o/p:
json string
What i have been doing is :
string url = "https://www.docscores.com/widget/api/org-profile/demo-health/npi/?profile-id=ShowProfile";
string data = GET(url);
dynamic jsonDe = JsonConvert.DeserializeObject(data);
var phyRatings = Convert.ToString(jsonDe.profile.averageRating);
Console.WriteLine(phyRatings);
public string ShowProfile(string pid)
{
}
public static string GET(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string data = reader.ReadToEnd();
reader.Close();
stream.Close();
return data;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
So, when I pass profile-id as 123456789 in the url, I want the syntax to extract other info with this Profile-id
I AM totally confused with the syntax in C#. How can I pass the argument and write inside the ShowProfile function? I searched everywhere but not able to find the correct syntax.
Can someone please tell me if this is the right way to do it?
EDIT: Sounds like you have two questions here. First is how to pass your Profile-Id in the URL, and the second is how to deserialize the JSON result into a C# object. But let me know if I'm misunderstanding.
For passing 123456789 as your profile ID, you just need to concatenate it into the URL string. So you might have
public string ShowProfile(string pid)
{
ProfileInfo info = GET(pid);
// Do what you want with the info here.
}
public static ProfileInfo GET(int profileId)
{
try
// Note this ends in "=" now.
string basePath = "/widget/api/org-profile/demo-health/npi/?profile-id=";
string path = basePath + profileId.ToString();
//...
ProfileInfo would be your custom class to match the JSON structure.
Then to deserialize the result, in your GET() method, you might instead try calling the service using HttpClient from the Microsoft.AspNet.WebApi.Client NuGet package, and then read that directly into a C# object whose structure maps to the JSON response you get (see example below). Your GET() method could then return that object, and then it'd be trivial for the ShowProfile() method to read the properties you want from that C# object.
public static ProfileInfo GET(int profileId)
{
try
{
// Note this ends in "=" now.
string basePath = "/widget/api/org-profile/demo-health/npi/?profile-id=";
string path = basePath + profileId.ToString();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://www.docscores.com");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
ProfileInfo info = await response.Content.ReadAsAsync<ProfileInfo>();
return info;
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
More code and info at MSDN: Calling a Web API From a .NET Client in ASP.NET Web API 2 (C#)

Categories

Resources