Getting null values when deserializing a list using RestSharp - c#

I am new to C# and to RestSharp.
I am writing a small program to retrieve a list of records via REST. I have been able to retrieve one record. Now I need to get a list of records, and here I have a problem.
The response I get using SoapUI looks like this:
{
"#count": 2,
"#start": 1,
"#totalcount": 2,
"Messages": [],
"ResourceName": "email",
"ReturnCode": 0,
"content": [
{"email": {"evsysseq": "0000000000000262"}},
{"email": {"evsysseq": "0000000000000263"}}
]
}
My code looks like this:
class EmailID
{
public string Evsysseq { get; set; }
}
var client = new RestClient("xxxxx");
client.Authenticator = new HttpBasicAuthenticator("xxx", "xxx");
string queryParm = HttpUtility.UrlEncode("evsysseq>\"0000000000000261\"");
var request = new RestRequest("xxxx?query="+ queryParm, Method.GET);
request.RootElement = "content";
var queryResult = client.Execute<List<EmailID>>(request).Data;
Running it does not result in errors, and I can see on the queryResult object that it does contain two records. But, Evsysseq is null on both, and that is my problem. I am not sure what to tweak to get it right.

You are getting null values because the JSON you are deserializing does not match the class structure you are deserializing into. You are telling RestSharp to deserialize the content array into a List<EmailID>, but the JSON really represents a list of objects that contain EmailID objects. And so you need another class:
class EmailObj
{
public EmailID Email { get; set; }
}
Then deserialize like this and you should get the data:
var queryResult = client.Execute<List<EmailObj>>(request).Data;
If you want to, you can then use LINQ to get the List<EmailID> that you originally wanted like this:
var emailIds = queryResult.Select(eo => eo.Email).ToList();
HTH

Related

C# reading an Array from IQueryCollection

Working in a C# Asp.netcore project, I'm trying to read an array from an IQueryCollection in a GET request. The IQueryCollection is in Request.Query.
I need to read the query without a model. When the front end json hits the back end, its no longer JSON which is fine, I just need to read whatever the front end passed. In this example its a int array but it could be anything.
Models don't scale very well for queries. To return a model on a get, they work brilliantly but for a query that can be as complex or simple as it needs to be I can't commit to models. Would be really usefull if I could extract the query to an anonamous object.
Json passed from the front end:
var params = {
items: [1, 4, 5],
startDate: new Date(),
endDate: new Date()
}
C# Request.QueryString
{?items%5B%5D=1&items%5B%5D=4&items%5B%5D=5&startDate=Fri%20Oct%2015%202021%2022%3A30%3A57%20GMT%2B1000%20(Australian%20Eastern%20Standard%20Time)&endDate=Fri%20Oct%2015%202021%2022%3A30%3A57%20GMT%2B1000%20(Australian%20Eastern%20Standard%20Time)}
I've tried:
// Gives me a null
var value = HttpUtility.ParseQueryString(Request.QueryString.Value).Get("items");
// Gives me an empty object {}
var value = Request.Query["items"];
Hope this is enough information.
The query string format is undefined for arrays. Some web frameworks use ?foo[]=1&foo[]=2, others use ?foo=1&foo=2, again others ?foo[0]=1&foo[1]=2.
You'll have to use the same parsing serverside as you serialize it clientside. This works for your [] syntax:
var queryString = "?items%5B%5D=1&items%5B%5D=4&items%5B%5D=5&date=2021-10-15";
var parsed = HttpUtility.ParseQueryString(queryString);
foreach (var key in parsed.AllKeys)
{
if (key.EndsWith("[]"))
{
var values = string.Join(", ", parsed.GetValues(key));
Console.WriteLine($"{key}: array: {values}.");
}
else
{
Console.WriteLine($"{key}: scalar: {parsed[key]}.");
}
}
Output:
items[]: array: 1, 4, 5.
date: scalar: 2021-10-15.
But instead of parsing the query string yourself, let the framework do that. You say you don't find models scalable; I find that hand-crafting code doesn't scale well. A model like this would just work, granted you fix your date serializer on the JS side:
public class RequestModel
{
public int[] Items { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}

C# convert postman POST to c# gets bad request (probbaly bad type)

I was able to complete the following POST via postman:
I tried to recreate that situation in c#:
var products = new
{
name = "test",
price = 100,
quantity = 1
};
var postModel = new
{
merchant_uid = merchant_uid,
products = products,
return_url = return_url,
notify_url = notify_url,
total_price = total_price,
};
var response = await client.PostAsJsonAsync(url, postModel);
But isnt that identical, to what I am doing in postman?
I am being returned that: The product Name field is required.
But i am giving it that in my code.
Where is my mistake?
Thank you!
The answer is in creating a type and making a list of that type. Add the objects, and thats it.
I think you need to create array of dictionaries to pass your products, for example:
var products = new [] {
new Dictionary < string, string > {
{
"name",
"test"
},
{
"price",
"100"
},
{
"quantity",
"1"
}
}
};
that is similar what you have in the postman

Is it possible to add fields with invalid characters to a .net AnonymousType?

I'm trying to send a JSON message to facebook that they call a game.achievement but I wanted to create the object using an AnonymousType before Posting. The problem is one of the fields is "game:points" (with the colon). As you can see I've used the # prefix for the object field but it doesn't work for the game:points field. It gets underlined in red and won't compile.
var paramsJson = new
{
privacy = new { value = "ALL_FRIENDS" },
#object = new
{
app_id = "my app id",
type = "game.achievement",
title = "Test",
#"game:points" = 100,
description = "Test",
image = "img.png"
}
};
I've tried many varieties of #, double quotes etc. Is it possible or do I need to just use a StringBuilder for this?
Why don't you just use a dictionary?
var postData = new Dictionary<string, object>
{
{"game:points", 100}
}
Presumably you're going to have to serialize your object to Post it regardless of how it's constructed. Serializing this to JSON would result in the same structure. Alternatively, just do as other's have suggested and create a class for your payload. You can then use Newtonsoft to indicate alternative names for serialization.
public class GameAchievement
{
[JsonProperty("game:points")]
public int Points {get; set;}
}

Deserializing JSON response without creating a class

From the result of an API call I have a large amount of JSON to process.
I currently have this
Object convertObj = JsonConvert.DeserializeObject(responseFromServer);
I am aware that I could do something like
Movie m = JsonConvert.DeserializeObject<Movie>(responseFromServer);
And then use it like
m.FieldName
m.AnotherField
//etc
Ideally I would like to do something like
var itemName = convertObj["Name"];
to get the first Name value for the first item in the list.
Is this possible, or do I have to create a class to deserialize to?
The reason I do not want to create the class is I am not the owner of the API and the field structure may change.
Edit.
Okay so I created the class as it seems the best approach, but is there a way to deserialize the JSON into a list?
var sessionScans = new List<SessionScan>();
sessionScans = JsonConvert.DeserializeObject<SessionScan>(responseFromServer);
Complains that it cannot convert SessionScan to generic list.
No need to use dynamic, you can simply use JToken which is already does what you expect:
var json = #"
{
""someObj"": 5
}
";
var result = JsonConvert.DeserializeObject<JToken>(json);
var t = result["someObj"]; //contains 5
With .NET 6, this can be done as below,
using System.Text.Json;
using System.Text.Json.Nodes;
string jsonString = #"some json string here";
JsonNode forecastNode = JsonNode.Parse(jsonString)!;
int temperatureInt = (int)forecastNode!["Temperature"]!;
Console.WriteLine($"Value={temperatureInt}");
//for nested elements, you can access as below
int someVal = someNode!["someParent"]["childId"]!.ToString();
Refer this MS docs page for more samples - create object using initializers, make changes to DOM, deserialize subsection of a JSON payload.
You can try with JObject.Parse :
dynamic convertObj = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
string name = convertObj.Name;
string address = convertObj.Address.City;
The below example can deserialize JSON to a list of anonymous objects using NewtonSoft.Json's DeserializeAnonymousType method.
var json = System.IO.File.ReadAllText(#"C:\TestJSONFiles\yourJSONFile.json");
var fooDefinition = new { FieldName = "", AnotherField = 0 }; // type with fields of string, int
var fooListDefinition = new []{ fooDefinition }.ToList();
var foos = JsonConvert.DeserializeAnonymousType(json, fooListDefinition);
You can use Json.NET's LINQ to JSON API
JObject o = JObject.Parse(jsonString);
string prop = (string)o["prop"];
Use Newtonsoft.Json
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
var json = "[{'a':'aaa','b':'bbb','c':'ccc'},{'a':'aa','b':'bb','c':'cc'}]";
var ja = (JArray)JsonConvert.DeserializeObject(json);
var jo = (JObject) ja[0];
Console.WriteLine(jo["a"]);
I had this problem working with unknown APIs then I decide to come over this problem using this approach, I'm writing down here my test case:
[TestMethod]
public void JsonDocumentDeserialize()
{
string jsonResult = #"{
""status"": ""INTERNAL_SERVER_ERROR"",
""timestamp"": ""09-09-2019 11:00:24"",
""message"": ""documentUri is required.""
}";
var jDoc = JsonDocument.Parse(jsonResult);
if (jDoc.RootElement.TryGetProperty("message", out JsonElement message))
{
Assert.IsTrue(message.GetString() == "documentUri is required.");
}
}
it worked for me because first I was looking to find a way to use dynamic type as it's mentioned in Azure Function HTTPTrigger. But I found this approach most useful and robust.
Microsoft Reference

Json deserializer

im currently making my first steep with json and well im complety confused.
I found many examples how to deserialize json files but nothing helps me.
{
"102": {
"id": 102,
"name": "cvmember3",
"profileIconId": 28,
"revisionDate": 1373593599000,
"summonerLevel": 1
},
"101": {
"id": 101,
"name": "IS1ec76a704e9b52",
"profileIconId": -1,
"revisionDate": 1355466175000,
"summonerLevel": 1
}
}
This is the json i object i got, the problem is im to stupid to deseralize it.
What i tried till now:
String name= (string) new JavaScriptSerializer().Deserialize<Dictionary<String, object>>(json)["name"];
Im missing the index, and dont know how to add it
anyone, can say me the correct line to deserialize, i has acces to the libary json.net
Alternatively you could define a class for the data you're going to get back and then parse your JSON into a dictionary something like this:
public class DataClass
{
public int id;
public string name;
public int profileIconId;
public long revisionDate;
public int summonerLevel;
}
Then
Dictionary<int, DataClass> myDictionary = JsonConvert.DeserializeObject<Dictionary<int, DataClass>>(json);
string foundName = myDictionary[102].name;
If you only want one item from the string (i only need to get one arttribut), you can use NewtonSoft to fish out the item you need:
using Newtonsoft.Json.Linq;
// read from where ever
string jstr = File.ReadAllText("C:\\Temp\\101.json");
JObject js = JObject.Parse(jstr);
var data102 = js["102"]["name"]; // == "cvmember3"
var data101 = js["101"]["name"]; // == "IS1ec76a704e9b52"
Console.WriteLine("Name for 101 is '{0}'", data101.ToString());
Console.WriteLine("Name for 102 is '{0}'", data102.ToString());
Output:
Name for 101 is 'IS1ec76a704e9b52'
Name for 102 is 'cvmember3'
This is a quick way to get at just one item value but it assumes you know what it looks like and where it is stored.

Categories