I am returning a json string to a WebMethod in WebForms and I want to take the json string and parse it into custom Order objects.
I have a class:
public class Order
{
public string Item { get; set; }
public string Color { get; set; }
public string Qty { get; set; }
public string Size { get; set; }
}
And a WebMethod:
[WebMethod]
public static string SendOrder(string json)
{
List<Order> orders = new List<Order>();
return json;
}
I am passing this string:
{
json: [
{
"Item":"Nike Polo #286772 - Women's Dri-FIT Micro Pique Short Sleeved Polo",
"Size":"XL",
"Color":"Light Blue",
"Quantity":"3"
},
{
"Item":"Port Authority Women's Jacket #L790 - Black",
"Size":"Medium",
"Color":"Black",
"Quantity":"3"
}
]
}
I want to loop through this string and creating new Orders.
What is the best way to do this?
That JSON is a little oddly formatted as it maps to the following classes (using http://json2csharp.com):
public class Json
{
public string Item { get; set; }
public string Size { get; set; }
public string Color { get; set; }
public string Quantity { get; set; }
}
public class RootObject
{
public List<Json> json { get; set; }
}
I'm not sure why you have a top-level variable named json, but whatever.
At this point just use JSON.NET to deserialize into the structure.
JsonConvert.DeserializeObject<RootObject>(yourJsonString);
If you want to rename the object from Json to Order you'll need to use an attribute for that. I don't recall the name off the top of my head but it should be easy to find in the JSON.NET documentation.
I recently completed a Windows Phone app that retrieved info from a Web API-based server as Json strings. I ended up using the JsonConvert class to convert my lists of objects from Json strings to my custom objects. Here's an example of one of my client-side methods that receives and converts the Json strings:
public async void GetGames()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("base url");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("specific url extention (like api/Order)");
if (response.IsSuccessStatusCode)
{
string s = await response.Content.ReadAsStringAsync();
var deserializedResponse = JsonConvert.DeserializeObject<List<Order>>(s);
//rest of code
}
}
}
Also, make sure that your web method is actually doing something. The example web method you posted creates creates a new list then just returns the parameter you passed in. Using Web API, you could return a list of all Order objects in your database via a method similar to the following:
public IQueryable<Order> GetOrders()
{
return db.Orders; //db is an instance of your DbContext class
}
I hope this is helpful. Let me know if you have any questions.
Related
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/
I have one specific issue, which I'm not able to handle.
I'm using HTTP Get API request and I'm getting JSON string, which I'm deserializing, this works perfectly. But then, I need to reuse just two pairs of this JSON file, but it needs to be pasted as JSON body for POST request. Let me show you the example:
Output of GET API Request:
{
"message":{
"value":[
{
"Reference":null,
"Key":"abc",
"IssueNumber":123
},
{
"Reference":null,
"Key":"def",
"IssueNumber":345
}
]
}
}
So now Im able to deserialize this JSON string (i.e.: jsonString("value)(0)("Key") and I will get "abc").
But now, I have no idea, how to serialize this deserialized object to use ReviewStatus and Key. This POST request JSON body looks like that:
{
"newStatus":"New"
"queueItems": [
{
"Key":"abc"
"IssueNumber":123
},
{
"Key":"def"
"IssueNumber":456
}
]
}
For loop works for me, but in that case, I will do API call for each item instead of doing just one POST API call. What would be the best solution in your opinion? I was trying to use Newtonsoft.Json.JsonConvert (SerializeObject Method), but it didn't work for me as I expected. I'm pretty sure, that there needs to be something much easier, but I need your help.
Thanks for any advice.
Frantisek
You can try to write two split species models, one for Receive JSON Modle, another for Response JSON Model.
Receive Modle
public class Value
{
public object Reference { get; set; }
public string Key { get; set; }
public int IssueNumber { get; set; }
}
public class Message
{
public List<Value> value { get; set; }
}
public class ReciveModel
{
public Message message { get; set; }
}
Response Model
public class QueueItem
{
public string Key { get; set; }
public int IssueNumber { get; set; }
}
public class ResponseModel
{
public string newStatus { get; set; }
public List<QueueItem> queueItems { get; set; }
}
Receive your JSON data and Deserialize to ReciveModel object, then let the data into another instance ResponseModel
final, you use JsonConvert.SerializeObject to serialize then instance to be JSON data.
var obj = JsonConvert.DeserializeObject<ReciveModel>(JsonData);
var res = new ResponseModel() {
newStatus = "New",
queueItems = obj.message.value.Select(x => new QueueItem() {
IssueNumber = x.IssueNumber,
Key = x.Key
}).ToList()
};
var jsonResult = JsonConvert.SerializeObject(res);
Result
{"newStatus":"New","queueItems":[{"Key":"abc","IssueNumber":123},{"Key":"def","IssueNumber":345}]}
c# online
Note
There are two way can create model easily.
You can use Web Essentials in Visual Studio, use Edit > Paste special > paste JSON as class, you can easier to know the relation between Json and model.
If you can't use Web Essentials you can instead of use http://json2csharp.com/ online JSON to Model class.
You can try to use those models to carry your JSON Format.
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"));
I am writing a program to access Mediafire's web API and it's all going well, the only issue remaining is the response text in JSON format that I have difficulty parsing.
With API calls like creating a folder, I get a simple response which can be deserialized into a Dictionary<string,Dictionary<string,string>> and searched for values:
{"response":
{
"action":"folder\/create.php",
"name":"blargh",
"folder_key":"mmttuu769djo0",
"result":"Success",
"current_api_version":"2.14"
}
}
I would use it like this:
Dictionary<string,string> json = DeserializeJSON(text)["response"];
//DeserializeJSON is a method to shorten:
//JsonConvert.DeserializeObject<Dictionary<string,Dictionary<string,string>>(text)
I can then query for json["result"] and whatnot. With other API calls I get complex structures that I'm not sure how to handle. It's basically a bunch of key:value pairs, but some of the values are key:value pairs as well, which can't be put into a dictionary like I'm currently doing. I'm fairly new to C# so I'm not sure what to do here, is there some other data type like a Dictionary which doesn't have static types?
Here's the response:
{"response":
{
"action":"upload\/upload.php",
"doupload":
{
"result":"0",
"key":"89lh7760x4l"
},
"server":"live",
"result":"Success",
"current_api_version":"2.14"
}
}
My question would be: What is a good way to get this kind of data into a list that I can query for values?
What about creating a new class(s) to deal with the json? You can generate classes by using json2csharp using the example json.
public class Doupload
{
public string result { get; set; }
public string key { get; set; }
}
public class Response
{
public string action { get; set; }
public Doupload doupload { get; set; }
public string server { get; set; }
public string result { get; set; }
public string current_api_version { get; set; }
}
public class RootObject
{
public Response response { get; set; }
}
Then you can deserialise the json using:
JavaScriptSerializer serializer = new JavaScriptSerializer();
var something = serializer.Deserialize<RootObject>(jsonString);
I ended up finding out about the dynamic type - Deserializing the text into a Dictionary<string,dynamic> allows it to have multiple types where some can be dictionaries as well. I can query it as I would expect but I just need to be sure what values are returned with each API call, and I need to cast it to a string.
string upload_key = (string)json["response"]["doupload"]["key"] //89lh7760x4l
I have a JSON data as follows
{"id": "367501354973","from": {
"name": "Bret Taylor",
"id": "220439" }
which is returned by an object(result) of IDictionary[String, Object]
In my C# code:
I have made a class for storing the JSON value which is as follows
public class SContent
{
public string id { get; set; }
public string from_name { get; set; }
public string from_id { get; set; }
}
My main C# function which stores the parses the JSON data and stores the value inside the class properties is as follows:
List<object> data = (List<object>)result["data"];
foreach (IDictionary<string, object> content in data)
{
SContent s = new SContent();
s.id = (string)content["id"];
s.from_name = (string)content["from.name"];
s.from_id = (string)content["from.id"];
}
When i execute this code, i get an exception saying System cannot find the Key "from.name" and "from.id"
When i comment the two lines (s.from_name = (string)content["from.name"];s.from_id = (string)content["from.id"];) my code runs fine.
I think i am not able to refer the nested JSON data properly.
Can anyone just validate it and please tell me how to refer nested data in JSON in C#?
Thanks
I'm not sure how you are parsing the JSON string. Are you using a class in the Framework to do the deserialization?
You could use the JavaScriptSerializer Class defined in the System.Web.Script.Serialization Namespace (you may need to add a reference to System.Web.dll)
Using that class, you would write your code like this:
public class SContent
{
public string id { get; set; }
public SFrom from { get; set; }
}
public class SFrom
{
public string name { get; set; }
public string id { get; set; }
}
Then deserialization looks like this:
var json = new JavaScriptSerializer();
var result = json.Deserialize<SContent>(/*...json text or stream...*/);
See JavaScriptSerializer on MSDN. You might also want to check out this similar question.