My Web API (code that generates JSON) is generating the following JSON string. It seems, if I am not wrong, that it has been encoded twice:
"\"[{\\\"SportID\\\":1,\\\"SportName\\\":\"Tennis\\\"},{\"SportID\\\":2,\\\"SportName\\\":\\\"Footbal\\\"},{\"SportID\\\":3,\"SportName\":\\\"Swimming\\\"}]\""
Web API code:
public string JSONTest()
{
List<Sport> sports = new List<Sport>();
sports.Add(new Sport() { SportID = 1, SportName = "Tennis" });
sports.Add(new Sport() { SportID = 2, SportName = "Footbal" });
sports.Add(new Sport() { SportID = 3, SportName = "Swimming" });
try
{
return JsonConvert.SerializeObject(sports);
}
catch (Exception ex) { }
}
Sport class:
public class Sport { public int SportID { get; set; } public string SportName { get; set; } }
Screenshot of getting JSON:
The following line gives me an error, I think because of twice encoding:
var JavaScriptSerializerResult = (new JavaScriptSerializer()).Deserialize< List<Sport>>(jsonResponse);
I get the same error if try with this:
var jsonConvertResult = JsonConvert.DeserializeObject<List<Sport>>(jsonResponse);
How can I fix my Web API to not encode twice, or if that is not the problem, how can I decode this JSON?
I think you should try JsonConvert.DeserializeObject to deserialize the JSON:
public class Sport
{
// Dummy "Sport" class as it was not mentioned by OP.
public int SportID { get; set; }
public string SportName { get; set; }
}
I get serialized JSON as:
Deserialized it:
string json = JSONTest();
var obj = JsonConvert.DeserializeObject<List<Sport>>(json);
Output:
UPDATE:
As per OP's shared JSON (which is being received from server), encoding can be removed by using:
private string RemoveEncoding(string encodedJson)
{
var sb = new StringBuilder(encodedJson);
sb.Replace("\\", string.Empty);
sb.Replace("\"[", "[");
sb.Replace("]\"", "]");
return sb.ToString();
}
Deserialize it by:
string js = "\"[{\\\"SportID\\\":1,\\\"SportName\\\":\"Tennis\\\"},{\"SportID\\\":2,\\\"SportName\\\":\\\"Footbal\\\"},{\"SportID\\\":3,\"SportName\":\\\"Swimming\\\"}]\"";
string res = RemoveEncoding(js);
var obj = JsonConvert.DeserializeObject<List<Sport>>(res);
Shorter sample for json.net library.
Here, entity is my serializable C# object. I use JsonConvert along with some formatting and specify to ignore reference looping to prevent circular referencing.
using Newtonsoft.Json;
var json = JsonConvert.SerializeObject (entity, Formatting.Indented,
new JsonSerializerSettings {ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
});
Use Linq Query Concept:
public string JSONTest()
{ List<Sport> sports = new List<Sport>();
sports.Add(new Sport() { SportID = 1, SportName = "Tennis" });
sports.Add(new Sport() { SportID = 2, SportName = "Footbal" });
sports.Add(new Sport() { SportID = 3, SportName = "Swimming" });
var result_sports = (from row in sports
group row by new { row.SportID , row.SportName} into hdr
select new Sport()
{
SportID = hdr.Key.SportID ,
SportName = hdr.Key.SportName ,
}).ToList();
string jsondata = new JavaScriptSerializer().Serialize(result_sports);
}
Summary: Your return object is being serialized twice. Remove your hand-rolled serialization code and return objects from your web services - not JSON strings.
Your JSON is indeed being serialized 'twice'. Look closely at this screenshot and we see escaped quote marks:
Your list properly serialized should produce a JSON string something like this:
[{"SportID":1,"SportName":"Tennis"},{"SportID":2,"SportName":"Footbal"},{"SportID":3,"SportName":"Swimming"}]
But we have something more like this:
"[{\"SportID\":1,\"SportName\":\"Tennis\"},{\"SportID\":2,\"SportName\":\"Footbal\"},{\"SportID\":3,\"SportName\":\"Swimming\"}]"
I can replicate this (code below) and it means that your JSON string has itself been fed through a serializer.
This is almost certainly due to you manually serializing your List<Sport>. You don't need to do that. Web API serializes for you - hence the second run through a serializer.
Change the return type of your Web API function if necessary, and then instead of writing:
return JsonConvert.SerializeObject(sports);
just do
return sports;
Web API will take care of the serialization and you will no longer have the bothersome quotes and escape characters.
Code dump I tested with:
void Main()
{
string json = JSONTest();
Console.WriteLine(json);
var obj = JsonConvert.DeserializeObject<List<Sport>>(json);
string jsonX2 = JsonConvert.SerializeObject(json);
Console.WriteLine(jsonX2);
obj = JsonConvert.DeserializeObject<List<Sport>>(jsonX2); // exception
}
public string JSONTest()
{
List<Sport> sports = new List<Sport>();
sports.Add(new Sport() { SportID = 1, SportName = "Tennis" });
sports.Add(new Sport() { SportID = 2, SportName = "Footbal" });
sports.Add(new Sport() { SportID = 3, SportName = "Swimming" });
return JsonConvert.SerializeObject(sports);
}
public class Sport
{
public int SportID { get; set; }
public string SportName { get; set; }
}
Related
I have JSON in a response structured like this
{
"statusCode": 200,
"result": {
"generalInfo": {
"firstName": "",
"lastName": ""
},
"isError": false
},
"sentDate": "2022-02-06T10:04:06.6853775Z",
}
var response = await _httpClient.PostAsJsonAsync(address, model);
Stream responseBody = await response.Content.ReadAsStreamAsync();
The response from the endpoint is actually a bit more complex and I want to extract only specific fields so I used dynamic
dynamic data = await JsonSerializer.DeserializeAsync<dynamic>(responseBody)
var dataString = data.ToString();
// dataString is
{"result":{"generalInfo":{"firstName":"John","lastName":"Doe"},"isError":false}
If I try to access dynamic properties like this
var firstName = data.result.generalInfo.firstName;
var lastName = data.result.generalInfo.lastName;
var isErr = data.IsError;
I'm getting exception
'System.Text.Json.JsonElement' does not contain a definition for
'result'
The problem is not DeserializeAsync, but that System.Text.Json uses JsonElements, so the dynamic value is actually a JsonElement. You'll need to parse the data from the JsonElement.
However, if you're using .Net 6 you can use JsonNode:
// deserialize into JsonNode
JsonNode data = await JsonSerializer.DeserializeAsync<JsonNode>(responseBody);
// OR parse the json string
JsonNode data = JsonNode.Parse(dataString);
int statusCode = (int)data["statusCode"];
var firstName = (string)data["result"]["generalInfo"]["firstName"];
var lastName = (string)data["result"]["generalInfo"]["lastName"];
var isErr = (bool)data["result"]["isError"];
Demo in .Net6
Support for dynamic was added to .Net 6 preview v4-6 but was removed before final release in favour of the JsonNode approach above. See github What's new in .NET 6 Preview 7 for further details.
Otherwise, you could parse it manually:
bool isError = false;
string firstName = "";
string lastName = "";
if (data is JsonElement elt && elt.TryGetProperty("result", out elt))
{
isError = elt.TryGetProperty("isError", out JsonElement boolElt) ? boolElt.GetBoolean() : false;
if (elt.TryGetProperty("generalInfo", out var genInfo))
{
firstName = genInfo.TryGetProperty("firstName", out var firstElt) ? firstElt.GetString() : "";
lastName = genInfo.TryGetProperty("lastName", out var lastElt) ? lastElt.GetString() : "";
}
}
However, my preferred approach is always to deserialize into defined classes if you can as it makes life much easier:
public class GeneralInfo
{
public string firstName { get; set; }
public string lastName { get; set; }
}
public class Result
{
public GeneralInfo generalInfo { get; set; }
public bool isError { get; set; }
}
public class Root
{
public Result result { get; set; }
}
var data = await JsonSerializer.DeserializeAsync<Root>(responseBody);
var firstName = data.result.generalInfo.firstName;
I am trying to deserialize JSON file and want to assign to object ScanResult. var text showing all the values but scanresult showing null some null values. https://gyazo.com/ff2ce386f845394c458a88d43a1f30d8
please suggest if I am missing something.
//MY jSon File SCAN Test 1-1543045410222.json 's code
{
"at": 1543045410222,
"i": 1000,
"s": {
"Sensor1": ["OFF"],
"Sensor2": ["OFF"],
"DataReady1": ["OFF"],
"DataReady2": ["OFF"],
"CV1": [5.0],
"CV2": [6.0]
}
}
//ViewModel Code is as below:
public void ResendScanResult()
{
var ScanActivities = scanActivityManager.GetAll();
foreach (var item in ScanActivities)
{
var scanName = item.ScanName;
var dir = _dataFilePath + scanName + "\\";
var jsonFileName = string.Format("{0}{1}-{2}.json", dir, scanName, item.ScanDateEpoch);
string fileName = Path.GetFileName(jsonFileName);
// ScanResult scanResult = new ScanResult();
var text = File.ReadAllText(jsonFileName);
//var scanResults = JsonConvert.DeserializeObject<ScanResult>(text);
Common.Model.ScanResult scanResult = JsonConvert.DeserializeObject<Common.Model.ScanResult>(text);
var Mvm = MonitorViewModel.Instance;
// TargetProvider target = Mvm.GetTargetProvider(scanResult);
// Mvm.PublishToServer(target, scanResult);
}
}
and my scanRescult class code is as below :
namespace ABX.Common.Model
{
public class ScanResult
{
public ScanResult()
{
At = DateTimeOffset.Now.ToUnixTimeMilliseconds();
Interval = 1;
}
public string Name { get; set; }
public long At { get; set; }
public long Interval { get; set; }
public JObject Values { get; set; }
public string FileName { get; set; }
public JObject ToJson()
{
JObject json = new JObject
{
{ "at", At },
{ "i", Interval },
{ "s", Values }
};
return json;
}
Either rename your class properties to match your JSON, rename your JSON to match your class properties, or implement a custom JsonConverter, where you can implement arbitrary mapping.
I am trying to create a JSON string which contains one container and one array.
I can do this by using a stringbuilder but I am trying to find a better way to get the JSON string; I want:
{ "message":{ "text":"test sms"},"endpoints":["+9101234"]}
I tried this:
string json = new JavaScriptSerializer().Serialize(new
{
text = "test sms",
endpoints = "[dsdsd]"
});
And the output is:
{"text":"test sms","endpoints":"[dsdsd]"}
Any help or suggestions how to get the required format?
In the most recent version of .NET we have the System.Text.Json namespace, making third party libraries unecessary to deal with json.
using System.Text.Json;
And use the JsonSerializer class to serialize:
var data = GetData();
var json = JsonSerializer.Serialize(data);
and deserialize:
public class Person
{
public string Name { get; set; }
}
...
var person = JsonSerializer.Deserialize<Person>("{\"Name\": \"John\"}");
Other versions of .NET platform there are different ways like the JavaScriptSerializer where the simplest way to do this is using anonymous types, for sample:
string json = new JavaScriptSerializer().Serialize(new
{
message = new { text = "test sms" },
endpoints = new [] {"dsdsd", "abc", "123"}
});
Alternatively, you can define a class to hold these values and serialize an object of this class into a json string. For sample, define the classes:
public class SmsDto
{
public MessageDto message { get; set; }
public List<string> endpoints { get; set; }
}
public class MessageDto
{
public string text { get; set; }
}
And use it:
var sms = new SmsDto()
{
message = new MessageDto() { text = "test sms" } ,
endpoints = new List<string>() { "dsdsd", "abc", "123" }
}
string json = new JavaScriptSerializer().Serialize(sms);
I do a request to a api that I'm using and this is the response that I get back.
{ "id": 1139, "performanceStatus": "OK", "availabilityStatus": "OK" }
I would like to convert this response in a list where I then can use a for/foreach loop and later can use linq and SelectMany to create a whole new list.
I got this far, but I am stuck the code is not hitting the var "newJson"..
Can someone help me out?
var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
dynamic parsedJson = JObject.Parse(json);
foreach (var j in parsedJson)
{
j.Replace(JObject.FromObject(
new {
id = j.id,
performance = j.performanceStatus,
availability = j.availabilityStatus
}));
}
var newJson = parsedJson.ToString();
Later I would like to Deserialize it into a strongly typed class. Like so
boi = await Task.Run(() => JsonConvert.DeserializeObject<Boi>(newJson)).ConfigureAwait(false);
Here is the strongly typed class
public class Boi
{
public int Id { get; set; }
public string PerformanceStatus { get; set; }
public string AvailabilityStatus { get; set; }
}
public class NewBoi
{
public List<Boi> eeg { get; set; }
}
You could do this:
var jsn = "{ \"id\": 1139, \"performanceStatus\": \"OK\", \"availabilityStatus\": \"OK\" }";
var bois = new List<Boi> { JsonConvert.DeserializeObject<Boi>(jsn) };
var newBoi = new NewBoi() { eeg = bois };
Although I would question the need for the NewBoi class - you could just work with the List.
To deserialize to a well known type use
JsonConvert.Deserialize<T>(jsonString,new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
where T is your well known type.
How can I deserialize:
{
"data": [
{"ForecastID":8587961,"StatusForecast":"Done"},
{"ForecastID":8588095,"StatusForecast":"Done"},
{"ForecastID":8588136,"StatusForecast":"Done"},
{"ForecastID":8588142,"StatusForecast":"Pending"}
]
}
to
class RawData
{
public string data { get; set; }
}
So, I just want to have
[
{"ForecastID":8587961,"StatusForecast":"Done"},
{"ForecastID":8588095,"StatusForecast":"Done"},
{"ForecastID":8588136,"StatusForecast":"Done"},
{"ForecastID":8588142,"StatusForecast":"Pending"}
]
as value of property data of RawData's class instance.
Using Json.Net
var obj = (JObject)JsonConvert.DeserializeObject(json);
var newJson = obj["data"].ToString();
or using built-in JavaScriptSerializer
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
var newjson = new JavaScriptSerializer().Serialize(dict["data"]);
It would have made far much more sense to deserialize this JSON structure to:
public class Forecast
{
public IEnumerable<ForecastData> Data { get; set; }
}
public class ForecastData
{
public int ForecastID { get; set; }
public string StatusForecast { get; set; }
}
which is pretty trivial with the JavaScriptSerializer class that's built into the framework:
string json = "your JSON data here";
IEnumerable<ForecastData> data = new JavaScriptSerializer()
.Deserialize<Forecast>(json)
.Data;
or if you don't want to define models you could do that:
dynamic result = new JavaScriptSerializer().DeserializeObject(json);
foreach (var item in result["data"])
{
Console.WriteLine("{0}: {1}", item["ForecastID"], item["StatusForecast"]);
}