Access JSON keys in C# from ServiceNow Rest API - c#

I am calling the ServiceNow Incidents table and pulling back one incident like this. https://mydevInstance.service-now.com/api/now/v1/table/incident?sysparm_limit=1
var client = new RestClient("https://mydevInstance.service-now.com/api/now/v1/table/incident?sysparm_limit=1");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Basic myAuthKey");
IRestResponse response = client.Execute(request);
The JSON it returns in RESTSharp looks like this.
{
"result": [
{
"parent": "",
"made_sla": "true",
"caused_by": "",
"watch_list": "",
"upon_reject": "cancel",
"resolved_by": {
"link": "https://mydevInstance.service-now.com/api/now/v1/table/sys_user/5137153cc611227c000bbd1bd8cd2007",
"value": "5137153cc611227c000bbd1bd8cd2007"
},
"approval_history": "",
"number": "INC0000060"
}
]
}
How do I create a C# list or array of all the Keys under result? I can't Serialize the object with JSON.Net because additional keys can be added over time.

You need to grab the sample of the JSON content, then make a C# class using the 'Paste Special' option I described.
Then you can use the JsonConvert.DeserializeObject<T> (in a nuget package by Newtonsoft) to deserialize your web service response in a C# object instance.
Here are the C# classes I generated with your JSON object unaltered:
public class Rootobject
{
public Result[] result { get; set; }
}
public class Result
{
public string parent { get; set; }
public string made_sla { get; set; }
public string caused_by { get; set; }
public string watch_list { get; set; }
public string upon_reject { get; set; }
public Resolved_By resolved_by { get; set; }
public string approval_history { get; set; }
public string number { get; set; }
}
public class Resolved_By
{
public string link { get; set; }
public string value { get; set; }
}
You use this type like this:
var json = "t-b-d"; // From Web Service call
Rootobject response = JsonConvert.DeserializeObject<Rootobject>(json);
// use the response object.
** UPDATED **
If you need a more flexible model, all JSON will deserialize into Dictionary<string, string>, but I have found that serialization / deserialization results are more reliable when the model is consistent
var response = JsonConvert.DeserializeObject<Dictionary<string,string>>(json);

Here is what does work using System.Text.Json
var incidentFields = new List<string>();
var doc = JsonDocument.Parse(json);
foreach (var o in doc.RootElement.GetProperty("result").EnumerateArray())
{
foreach (var p in o.EnumerateObject())
{
incidentFields.Add(p.Name.ToString());
}
}

I created a library that handles that by default. (You can add custom types also)
https://autodati.github.io/ServiceNow.Core/

Related

Unable to use JSON array for Azure Function

I have below JSON input for My azure function but unable to pass it in after deserialize object
{
"name": [{
"SiteName": "Site1",
"SiteUrl": "https://site1.com/"
},
{
"SiteName": "Site2",
"SiteUrl": "https://site2.com/"
},
]
}
after deserialize I am getting count as 2 but inside array value I am not getting for deserializing using below code
string requestBody = new StreamReader(req.Body).ReadToEnd();
dynamic data = JsonConvert.DeserializeObject(requestBody);
var Root = data["name"].ToObject<List<Constant>>();
and for Constant class declared like below
class Constant
{
public Dictionary<string, string> name { get; set; }
}
Try to create class like below.
class JsonResponse
{
public List<Constant> name { get; set; }
}
class Constant
{
public string SiteName { get; set; }
public string SiteUrl { get; set; }
}
And try to Deserialize response with JsonConvert.DeserializeObject<JsonResponse>(requestBody).
string requestBody = new StreamReader(req.Body).ReadToEnd();
JsonResponse data = JsonConvert.DeserializeObject<JsonResponse>(requestBody);
var Root = data.name;
Solution 1: Deserialize as object list
The model class should be:
public class Site
{
public string SiteName { get; set; }
public string SiteUrl { get; set; }
}
And deserialize as below:
var Root = data["name"].ToObject<List<Site>>();
Sample program (Site class)
Solution 2: Deserialize as Dictionary
var Root = data["name"].ToObject<List<Dictionary<string, string>>>();
Sample program (Dictionary)

SendGrid: Deserialization of Email Activity API JSON Response Not Populating Objects

I am calling SendGrid's Email Activity API using the RestSharp RestClient and it is properly returning data via a standard JSON response.
However, I'd like to deserialize that into a C# object since it would be much easier to work with than a raw JSON string. So I created a C# class that has public properties for each field in the JSON response, and gave them annotations with the exact name of the JSON fields.
But when I call JsonDeserializer().Deserialize>(response), while there's no error/exception, all of the fields in the objects are NULL.
Any ideas what's wrong? (You can just take out the "EventType" references as it's not really relevant here). Relevant code is below.
I'm using RestSharp v106.6.10.0 and Newtonsoft.Json v9.0.0.0 (the latter probably older but that's the library we normally use).
Project is .NET v4.6.1
private void QuerySendGridForEmailActivity(EventType eventType)
{
string query = string.Empty;
RestClient client = null;//new RestClient(emailActivityEndpoint);
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer " + apiKey);
request.AddParameter("limit", "1000");
if (eventType == EventType.Opens)
{
// request.AddParameter("query", WebUtility.UrlEncode("(Contains(events,\"open\"))"));
client = new RestClient(emailActivityEndpoint + "?limit=10&query=" + System.Web.HttpUtility.UrlPathEncode("(Contains(events,\"open\"))"));
}
IRestResponse response = client.Execute(request);
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
this.emailActivityEvents = new JsonDeserializer().Deserialize<List<EmailActivityEvent>>(response);
int i = 0;
}
else
{
}
}
public class EmailActivityEvent
{
[DeserializeAs(Name = "from_email")]
public string FromEmail { get;set; }
[DeserializeAs(Name = "msg_id")]
public string MessageId { get; set; }
[DeserializeAs(Name = "subject")]
public string Subject { get; set; }
[DeserializeAs(Name = "to_email")]
public string ToEmail { get; set; }
[DeserializeAs(Name = "status")]
public string Status { get; set; }
[DeserializeAs(Name = "opens_count")]
public int OpensCount { get; set; }
[DeserializeAs(Name = "clicks_count")]
public int ClicksCount { get; set; }
[DeserializeAs(Name = "last_event_time")]
public DateTime LastEventTime { get; set; }
}
Ok, I should've gotten this earlier but I didn't think I needed to do this.
I had to add another class that I named "EmailActivity" that just has a List<> of the email events, with a deserialize annotation matching the actual name of the item in JSON. Like this:
public class EmailActivity
{
[DeserializeAs(Name = "messages")]
public List<EmailActivityEvent> Events { get; set; }
}
Then just adjust the deserialize call slightly to this:
var emailActivity = new JsonDeserializer().Deserialize<EmailActivity>(response);
And that did it. Duh.
Just FYI, the JSON being returned was in this format:
{"messages":
[{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-26T20:30:02Z"
},
{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-26T20:30:01Z"
},
{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-25T22:06:25Z"
}
]}
Thanks for your comments!

HttpClient ObjectContent JSON: format with root class name in json object?

I generate a C# class for a json source using json2csharp.com. My json is:
{
"email_verified": true,
"user_id": "gg2323",
"app_metadata": {
"tc_app_user": {
"user_guid": "c0fb150f6er344df98ea3a06114e1e4a",
"cto_admin_a_user_id": "551294d4f6cfb46e65a5aq71",
"lang": "EN",
"country": "USA",
"disabled": false
}
and my resulting C# is:
public class TcAppUser
{
public string user_guid { get; set; }
public string cto_admin_a_user_id { get; set; }
public string lang { get; set; }
public string country { get; set; }
public bool disabled { get; set; }
}
public class AppMetadata
{
public TcAppUser tc_app_user { get; set; }
public int logins_count { get; set; }
}
public class RootObject
{
public bool email_verified { get; set; }
public string user_id { get; set; }
public AppMetadata app_metadata { get; set; }
}
Using the .NET HttpClient GET, I can read into this C# structure from the JSON API quite nicely. Going the other way (POST, PATCH) poses a problem: my app_metadata property name is dropped in the generated JSON output when I use a common approach like:
//Would be nice: var contentIn = new ObjectContent<string>(RootObjectInstance.app_metadata, new JsonMediaTypeFormatter());
string json = JsonConvert.SerializeObject(RootObjectInstance.app_metadata);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" + user_id, new StringContent(json, Encoding.UTF8, "application/json"));
The resulting JSON is now:
{
"tc_app_user": {
"lang": "en-en",
"country": "GER",
"disabled": false
}
}
My quick hack is to use the following additional wrapper to dynamically repackage the app_metadata property so it has the same format going out that it had coming in. The rest remains the same as above:
dynamic wireFormatFix = new ExpandoObject();
wireFormatFix.app_metadata = usr.app_metadata;
string json = JsonConvert.SerializeObject(wireFormatFix);
Now my JSON output corresponds to the JSON input. My question: what is best-practice to achieve symmetric json input and output here without a pesky format fix?
EDIT: If I try to PATCH the entire structure (RootObjectInstance instead of RootObjecInstance.app_metadata) I get:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Payload validation error: 'Additional properties not allowed: 'user_id'."
}
So, I must either send the app_metadata subset/property of the C# RootObject, properly packaged, or I must selectively delete fields from the RootObject to meet the API's requirements.
Thanks!
The root app_metadata tag is being removed from your JSON because you're simply not serializing it. This:
string json = JsonConvert.SerializeObject(RootObjectInstance.app_metadata);
Will serialize everything that is inside app_metadata.
If you serialized the entire object graph, you wouldn't need to patch anything:
string json = JsonConvert.SerializeObject(RootObjectInstance);
As a side note, you should follow C# naming conventions. You can use JsonProperty to help you with that.
Edit:
Ok, after your edit i see the actual problem. You're calling an API by user_id in your query string, and you also have a user_id property inside your object. This seems like you need two different objects for the job.
You have a couple of possibilities:
Create an object hierarchy:
public class BaseObject
{
[JsonProperty(email_verified)]
public bool EmailVerified { get; set; }
[JsonProperty(app_metadata)]
public AppMetadata AppMetadata { get; set; }
}
public class ExtendedObject : BaseObject
{
[JsonProperty(user_id)]
public string UserId { get; set; }
}
And then use the base type to serialize the data:
var baseObj = new BaseObject(); // Fill the object properties.
var json = JsonConvert.SerializeObject(intermidiateObj);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" +
user_id,
new StringContent(json,
Encoding.UTF8,
"application/json"));
Use an anonymous object which includes only properties you actually need:
var intermidiateObj = new { app_metadata = usr.app_metadata };
var json = JsonConvert.SerializeObject(intermidiateObj);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" +
user_id,
new StringContent(json,
Encoding.UTF8,
"application/json"));

How to get value from JSON Dictionary using Newtonsoft.Json

I'm new in json and I have a little problem here that I can't solve.
In other json I have {"certificate":"123456789",} and I get the value of that using.
model.cs
class Login //this code is working.
{
[JsonProperty("certificate")]
public string certificate { get; set; }
}
But my problem is when I come up with json dictionary I don't have any Idea how can i get the value from it.
this is my code from controller.cs to get the json from Saba/api/component/location
using(var client = new HttpClient()) //I'm sure this code is working.
{
client.BaseAddress = new Uri(string.Format("https://{0}/", HostUrl));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("SabaCertificate", certificate);
//HTTP GET: /Saba/api/componet/location
HttpResponseMessage response = await client.GetAsync("Saba/api/component/location");
if(response.IsSuccessStatusCode)
{
Location saba = await response.Content.ReadAsAsync<Location>();
//I always get empty location when I try to run the app.
}
}
This is JSON with dictionary.
{
"results": [
{
"loc_name": "Aberdeen - Aberdeen Town Square_489",
"id": "locat000000000001877",
"href": "https://na1.sabacloud.com/Saba/api/component/location/locat000000000001877"
}]
}
How can I get the value of json dictionary?
What I've tried is
Model.cs
[JsonProperty("results")] \\ AggregateException Error
class Location
{
[JsonProperty("loc_name")]
public string loc_name { get; set; }
[JsonProperty("id")]
public string id { get; set; }
[JsonProperty("href")]
public string href { get; set; }
}
But I can't retrieve the value.
Based on the JSON posted in your question you should have something like
public class Result
{
public string loc_name { get; set; }
public string id { get; set; }
public string href { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
then just call
var rootObject = JsonConvert.DeserializeObject<RootObject>(jsonData);
You can always use JSON Formatter & Validator to test if your JSON is valid, and json2csharp to generate c# classes from json.

write data from JSON in C#

I have JSON like this:
{
'surveys': [
{
'title': 'first',
'id': 100,
},
{
'title': 'second',
'id': 101,
},
{
'title': 'third',
'id': 102,
},
]
}
I want to have the output like this:
title: first
title: second
title: third
and my program in C# is like this:
WebClient client = new WebClient();
var json = client.DownloadString("http://www.test.com/api/surveys/?api_key=123");
Debug.WriteLine(json); //write all data from json
//add
var example = JsonConvert.DeserializeObject<Example>(json);
Debug.WriteLine(example.Data.Length);
class Example
{
public surveys[] Data { get; set; }
}
class surveys
{
public string title { get; set; }
public int id { get; set; }
}
I get this error:
Thrown: "Object reference not set to an instance of an object." (System.NullReferenceException) Exception Message = "Object reference not set to an instance of an object.", Exception Type = "System.NullReferenceException", Exception WinRT Data = ""
at this line: Debug.WriteLine(example.Data.Length);
where is the problem?
One problem I see is that your outer class has a property named Data, which is an array of 'surveys' objects, but your Json has a list of 'surverys' objects under the property 'surveys'. Hence the 'Data' property is never populated.
Consider the following C# class structure:
class Example
{
public survey[] surveys{ get; set; }//Data renames to surveys
}
class survey //Singular
{
public string title { get; set; }
public int id { get; set; }
}
Why can't you do so?:
JObject data = JObject.Parse(json);
foreach (var survey in data["surveys"].Children())
{
Debug.WriteLine("title: " + survey["title"]);
}
You need to use JSON.Net and use the class JsonConvert and the method DeserializeObject<T>.
If you run this:
JsonConvert.DeserializeObject<JObject>();
Then you will get back a list of de-serialized JObject objects.
Use, NuGet to download the package. I think it is called JSON.net.
Here is the weblink
WebClient client = new WebClient();
var json = client.DownloadString("http://www.test.com/api/surveys/?api_key=123");
Debug.WriteLine(json); //write all data from json
//add
var example = JsonConvert.DeserializeObject<Survey>(json);
Debug.WriteLine(example.length); // this could be count() instead.
class Survey
{
public string title { get; set; }
public int id { get; set; }
}
This should work!
Use json2csharp to generate c# classes from json.
You will also need to use Json.NET.
public class Survey
{
public string title { get; set; }
public int id { get; set; }
}
public class RootObject
{
public List<Survey> surveys { get; set; }
}
Then you can do:
var client = new WebClient();
string json = client.DownloadString(some_url);
RootObject root = JsonConvert.DeserializeObject<RootObject>(json);
foreach (Survey s in root.surveys)
{
// Do something with your survey
}
Don't forget to use Newtonsoft.Json namespace once you add a reference to it within your project.
using Newtonsoft.Json;
Edit: I have tested it using:
string json = "{'surveys': [{'title': 'first','id': 100,},{'title': 'second','id': 101,},{'title': 'third','id': 102,},]}";
instead of using the WebClient, and it works.

Categories