System.Text.Json.JsonSerializer.Serialize adds \u0022 - c#

How can I set JsonSerializer to not add "\u0022" to string for EventData property? Because I get:
{"Id":5,"CreateDate":"2021-04-21T05:26:30.9817284Z","EventData":"{\u0022Id\u0022:1,\u0022Email\u0022:\u0022test#test.test\u0022}"}
I will never deserialize EventData, it must be readable. And I want:
{"Id":5,"CreateDate":"2021-04-21T05:26:30.9817284Z","EventData":"{Id:1,Email:test#test.test}"}
My code:
public class EmailSent
{
public int Id { get; set; }
public string Email { get; set; }
}
public class UserCreated
{
public int Id { get; set; }
public DateTime CreateDate { get; set; }
public string EventData { get; set; }
}
var emailSent = new EmailSent
{
Id = 1,
Email = "test#test.test"
};
var userCreated = new UserCreated
{
Id = 5,
CreateDate = DateTime.UtcNow,
EventData = JsonSerializer.Serialize(emailSent) // I will never deserialize it
};
string result = JsonSerializer.Serialize(userCreated);

You can use, for example, UnsafeRelaxedJsonEscaping:
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
string json = JsonSerializer.Serialize(userCreated, serializeOptions);
This will produce the following output:
{
"Id": 5,
"CreateDate": "2021-04-21T07:49:23.4378969Z",
"EventData": "{\"Id\":1,\"Email\":\"test#test.test\"}"
}
Reference: How to customize character encoding with System.Text.Json. Please read the caution there:
Caution
Compared to the default encoder, the UnsafeRelaxedJsonEscaping encoder is more permissive about allowing characters to pass through unescaped:
(...)

This happens because JsonSerializer.Serialize() is invoked more than once.

You can specify 'JSONSerializerOptions' Encoder equal to JavaScriptTenCoder. Create(new TextEncoderSettings(UnicodeRanges.All))
like this
public static string ToString(this object str)
{
try
{
string sResult = JsonSerializer.Serialize(str, new JsonSerializerOptions{WriteIndented = true, Encoder = JavaScriptEncoder.Create(new TextEncoderSettings(System.Text.Unicode.UnicodeRanges.All))});
return sResult;
}
}

I have almost the exact same problem, only my UserCreated is being returned by ASP.NET controller function, I don't directly control serialization.
The simplest solution is to change the type of EventData to JsonNode.
To set EventData from whatever complex object you want, you can use this awkward construct
EventData = JsonNode.Parse(JsonSerializer.Serialize(complexData))
Complete minimal example:
[Test]
public void Test1()
{
Dictionary<string, string> complexData =
new Dictionary<string, string>() { { "A", "B" } };
NestedJason toSerialize = new NestedJason()
{
FormName = "String",
FormData = JsonNode.Parse(JsonSerializer.Serialize(complexData))
};
Console.WriteLine(JsonSerializer.Serialize(toSerialize));
// prints {"FormName":"String","FormData":{"A":"B"}}
}
}
public class NestedJason
{
public string FormName { get; set; }
public JsonNode FormData { get; set; }
}

A cleaner option is to make FormData type object. (I'm assuming you don't want to make it type EmailSent because you want to store random data about many different types of events.) If you round trip the EventData as object, it will go in as EmailSent and come back out as JsonElement. Manual steps would be required to get it back to an EmailSent.
public class Tests
{
[Test]
public void Test1()
{
Dictionary<string, string> complexData =
new Dictionary<string, string>() { { "A", "B" } };
NestedJason toSerialize = new NestedJason()
{
FormName = "Sting",
FormData = complexData
};
Console.WriteLine(JsonSerializer.Serialize(toSerialize));
NestedJason result = JsonSerializer.Deserialize(
JsonSerializer.Serialize(toSerialize),
typeof(NestedJason)) as NestedJason;
Console.WriteLine(result.FormData.GetType().Name);
}
}
public class NestedJason
{
public string FormName { get; set; }
public Object FormData { get; set; }
}
(I personally will be using the previous JsonNode option, that is more editable, but the object option skips that round trip serialization kludge.)

Related

Serialize Json in c# with special character in variable name

I need to serialize the following json
{
"searchText": "masktl_TABLE_GetMissingTables",
"$skip": 0,
"$top": 1,
"includeFacets": true
}
I've tried this
string payload = JsonConvert.SerializeObject(new
{
searchText = "masktl_TABLE_GetMissingTables",
$skip = 0,
$top = 1,
includeFacets = true
});
But we can not put $ in the name of a variable. Can anyone please suggest me any other way to serialize the json?
Create a Dictionary<string, object> instead:
var dictionary = new Dictionary<string, object>
{
["searchText"] = "masktl_TABLE_GetMissingTables",
["$skip"] = 0,
["$top"] = 1,
["includeFacets"] = true
};
string payload = JsonConvert.SerializeObject(dictionary);
Alternatively, if you need to do this from more than just the one place, create a class with the relevant properties and use the JsonProperty attribute to specify the name within the JSON.
For example:
public class SearchRequest
{
[JsonProperty("searchText")]
public string SearchText { get; set; }
[JsonProperty("$skip")]
public int Skip { get; set; }
[JsonProperty("$top")]
public int Top { get; set; }
[JsonProperty("includeFacets")]
public bool IncludeFacets { get; set; }
}
var request = new SearchRequest
{
SearchText = "masktl_TABLE_GetMissingTables",
Skip = 0,
Top = 1,
IncludeFacets = true
};
string payload = JsonConvert.SerializeObject(request);
Instead of Anonymous object, have you tried using dictionary,
string payload = JsonConvert.SerializeObject(new Dictionary<string, object>()
{
{ "searchText", "masktl_TABLE_GetMissingTables" },
{ "$skip", 0 },
{ "$top", 1 },
{ "includeFacets", true }
});
Try Online
If you have any defined model class for given json format then you can JsonPropertyAttribute to change the name of property at the time of serialization.
Declare:
public class Pagination
{
[JsonProperty("searchText")]
public string SearchText{ get; set; }
[JsonProperty("$skip")]
public int Skip { get; set; }
[JsonProperty("$top")]
public int Top { get; set; }
[JsonProperty("includeFacets")]
public bool IncludeFacets { get; set; }
}
Usage:
var paginationObj = new Pagination()
{
SearchText = "masktl_TABLE_GetMissingTables",
Skip = 0,
Top = 1,
IncludeFacets = true
};
string payload = JsonConvert.SerializeObject(paginationObj);
Try online

Load JSON object into array?

I'm having trouble loading this json object into an array.
Here is a snippet (fragment) of my JSON response from the API:
{
"count":192,
"value":[
{
"id":"03dd9f56-108f-4e8f-b92e-93df05717464",
"name":"IIBTest",
"url":"https://devops.com/tfs/DefaultCollection/_apis/projects/03dd9f56-108f-4e8f-b92e-93df05717464",
"state":"wellFormed",
"revision":14434848,
"visibility":"private",
"lastUpdateTime":"2016-08-19T12:21:37.187Z"
},
{
"id":"b7e15034-fc8f-4f7e-866a-cb06f44b12ed",
"name":"MS Project POC",
"description":"POC for MS Project with TFS",
"url":"https://devops.com/tfs/DefaultCollection/_apis/projects/b7e15034-fc8f-4f7e-866a-cb06f44b12ed",
"state":"wellFormed",
"revision":14434955,
"visibility":"private",
"lastUpdateTime":"2017-10-03T19:31:56.56Z"
},
{
"id":"59e06621-c5f5-4fd1-9c55-1def541b99d9",
"name":"WorkflowReporting",
"url":"https://devops.com/tfs/DefaultCollection/_apis/projects/59e06621-c5f5-4fd1-9c55-1def541b99d9",
"state":"wellFormed",
"revision":14434591,
"visibility":"private",
"lastUpdateTime":"2015-09-11T06:59:12.21Z"
},
{
"id":"78a802f0-5eee-4bcb-bde9-a764e46f56db",
"name":"iSolutions",
"description":"",
"url":"https://devops.com/tfs/DefaultCollection/_apis/projects/78a802f0-5eee-4bcb-bde9-a764e46f56db",
"state":"wellFormed",
"revision":14435476,
"visibility":"private",
"lastUpdateTime":"2021-08-05T17:17:26.193Z"
},
{
"id":"1f20506a-63a5-486a-a857-fec64d7486a6",
"name":"Training",
"description":"MLITS Training and Learning",
"url":"https://devops.com/tfs/DefaultCollection/_apis/projects/1f20506a-63a5-486a-a857-fec64d7486a6",
"state":"wellFormed",
"revision":14435350,
"visibility":"private",
"lastUpdateTime":"2021-04-08T22:48:02.923Z"
},
...
}
And here is my code:
public class Rootobject
{
public int count { get; set; }
public Value[] value { get; set; }
}
public class Value
{
public string id { get; set; }
public string name { get; set; }
public string url { get; set; }
public string state { get; set; }
public int revision { get; set; }
public string visibility { get; set; }
public DateTime lastUpdateTime { get; set; }
public string description { get; set; }
}
static void Main(string[] args)
{
var client = new RestClient("https://devops.americannational.com/tfs/defaultcollection/_apis/projects?$top=300&api-version=5.0")
{
Authenticator = new RestSharp.Authenticators.NtlmAuthenticator()
};
client.Timeout = -1;
var request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
var jsonString = response.Content;
var jo = JObject.Parse(jsonString);
//...
}
I am wanting to load the names of the projects into the Array so that I can later iterate through them. Any help is appreciated, I have tried a few things but not having much luck.
you can use var jo = JsonConvert.DeserializeObject<Rootobject>(jsonString);
and then iterate through jo.value
try this
var jsonDeserialized= JsonConvert.DeserializeObject<Rootobject>(json);
as example how to use it this query returns array of project names
var projectNames= jsonDeserialized.value.Select(v => v.name ).ToArray();
output
["IIBTest","MS Project POC","WorkflowReporting","iSolutions","Training"]
this returns a list of projects
var projects= jsonDeserialized.value.ToList();

How to assign value to variable from a google API Json Response c#

I am trying to assign the value of a key from an async JSON response to a variable, the JSON key in question is the "threatType" Key. I am querying google's safebrowsing v4 API and I get a good response, the problem is when I try to assign a key to a variable nothing is assigned. Here's my code:
public static async Task<string> CheckUrl( string Api_Key, string MyUrl)
{
safeBrowsing_panel i = new safeBrowsing_panel();
var service = new SafebrowsingService(new BaseClientService.Initializer
{
ApplicationName = "Link-checker",
ApiKey = Api_Key
});
var request = service.ThreatMatches.Find(new FindThreatMatchesRequest()
{
Client = new ClientInfo
{
ClientId = "Link-checker",
ClientVersion = "1.5.2"
},
ThreatInfo = new ThreatInfo()
{
ThreatTypes = new List<string> { "SOCIAL_ENGINEERING", "MALWARE" },
PlatformTypes = new List<string> { "ANY_PLATFORM" },
ThreatEntryTypes = new List<string> { "URL" },
ThreatEntries = new List<ThreatEntry>
{
new ThreatEntry
{
Url = MyUrl
}
}
}
});
var response = await request.ExecuteAsync();
string json = JsonConvert.SerializeObject(await request.ExecuteAsync());
string jsonFormatted = JToken.Parse(json).ToString(Formatting.Indented);
Console.WriteLine(jsonFormatted);
return jsonFormatted;
}
I created classes to parse the json:
public class ThreatRes
{
public string threatType;
}
public class RootObjSB
{
public List<ThreatRes> matches;
}
And I call it with:
string SB_Result = await CheckUrl("MyAPIKey", "Bad_URL");
RootObjSB obj = JsonConvert.DeserializeObject<RootObjSB>(SB_Result);
The JSON response from google:
{
"matches": [
{
"cacheDuration": "300s",
"platformType": "ANY_PLATFORM",
"threat": {
"digest": null,
"hash": null,
"url": "http://badurl.com/",
"ETag": null
},
"threatEntryMetadata": null,
"threatEntryType": "URL",
"threatType": "SOCIAL_ENGINEERING",
"ETag": null
}
],
"ETag": null
}
I need help please.
So I tried using JavaScriptSerializer and it seemed to work just fine, I also reconstructed my classes to parse all the properties on the JSON response.
Reconstructed Classes:
public class Threat
{
public object digest { get; set; }
public object hash { get; set; }
public string url { get; set; }
public object ETag { get; set; }
}
public class Match
{
public string cacheDuration { get; set; }
public string platformType { get; set; }
public Threat threat { get; set; }
public object threatEntryMetadata { get; set; }
public string threatEntryType { get; set; }
public string threatType { get; set; }
public object ETag { get; set; }
}
public class RootObjSB
{
public List<Match> matches { get; set; }
public object ETag { get; set; }
}
and i deserialize it like this:
string SB_Result = await CheckUrl("MyAPIKey", "Bad_URL");
var obj = new JavaScriptSerializer().Deserialize<RootObjSB>(SB_Result);
string threat = obj.matches[0].threatType;
Console.WriteLine(threat);
I really don't know why the first option I tried didn't parse the data correctly but this was how I overcame that problem. Hope it helps anyone going through the same thing

Converting JSON array

I am attempting to use the Newtonsoft JSON library to parse a JSON string dynamically using C#. In the JSON is a named array. I would like to remove the square brackets from this array and then write out the modified JSON.
The JSON now looks like the following. I would like to remove the square bracket from the ProductDescription array.
{
"Product": "123",
"to_Description": [
{
"ProductDescription": "Product 1"
}
]
}
Desired result
{
"Product": "123",
"to_Description":
{
"ProductDescription": "Product 1"
}
}
I believe I can use the code below to parse the JSON. I just need some help with making the modification.
JObject o1 = JObject.Parse(File.ReadAllText(#"output.json"));
The to_Description property starts off as List<Dictionary<string,string>> and you want to take the first element from the List.
So, given 2 classes
public class Source
{
public string Product {get;set;}
public List<Dictionary<string,string>> To_Description{get;set;}
}
public class Destination
{
public string Product {get;set;}
public Dictionary<string,string> To_Description{get;set;}
}
You could do it like this:
var src = JsonConvert.DeserializeObject<Source>(jsonString);
var dest = new Destination
{
Product = src.Product,
To_Description = src.To_Description[0]
};
var newJson = JsonConvert.SerializeObject(dest);
Note: You might want to check there really is just 1 item in the list!
Live example: https://dotnetfiddle.net/vxqumd
You do not need to create classes for this task. You can modify your object like this:
// Load the JSON from a file into a JObject
JObject o1 = JObject.Parse(File.ReadAllText(#"output.json"));
// Get the desired property whose value is to be replaced
var prop = o1.Property("to_Description");
// Replace the property value with the first child JObject of the existing value
prop.Value = prop.Value.Children<JObject>().FirstOrDefault();
// write the changed JSON back to the original file
File.WriteAllText(#"output.json", o1.ToString());
Fiddle: https://dotnetfiddle.net/M83zv3
I have used json2csharp to convert the actual and desired output to classes and manipulated the input json.. this will help in the maintenance in future
First defined the model
public class ToDescription
{
public string ProductDescription { get; set; }
}
public class ActualObject
{
public string Product { get; set; }
public List<ToDescription> to_Description { get; set; }
}
public class ChangedObject
{
public string Product { get; set; }
public ToDescription to_Description { get; set; }
}
Inject the logic
static void Main(string[] args)
{
string json = "{\"Product\": \"123\", \"to_Description\": [ { \"ProductDescription\": \"Product 1\" } ]} ";
ActualObject actualObject = JsonConvert.DeserializeObject<ActualObject>(json);
ChangedObject changedObject = new ChangedObject();
changedObject.Product = actualObject.Product;
changedObject.to_Description = actualObject.to_Description[0];
string formattedjson = JsonConvert.SerializeObject(changedObject);
Console.WriteLine(formattedjson);
}
Why not:
public class EntityDescription
{
public string ProductDescription { get; set; }
}
public class Entity
{
public string Product { get; set; }
}
public class Source : Entity
{
[JsonProperty("to_Description")]
public EntityDescription[] Description { get; set; }
}
public class Target : Entity
{
[JsonProperty("to_Description")]
public EntityDescription Description { get; set; }
}
var raw = File.ReadAllText(#"output.json");
var source = JsonConvert.DeserializeObject<Source>(raw);
var target = new Target { Product = source.Product, Description = source.Description.FirstOrDefault() };
var rawResult = JsonConvert.SerializeObject(target);
Update For dynamic JSON
var jObject = JObject.Parse(File.ReadAllText(#"output.json"));
var newjObject = new JObject();
foreach(var jToken in jObject) {
if(jToken.Value is JArray) {
List<JToken> l = jToken.Value.ToObject<List<JToken>>();
if(l != null && l.Count > 0) {
newjObject.Add(jToken.Key, l.First());
}
} else {
newjObject.Add(jToken.Key, jToken.Value);
}
}
var newTxt = newjObject.ToString();

Create a json formatted object

I have this JSON array created in C#/aspx:
[
{
nome: "test",
apelido: "test"
}
]
And I want to create JSON like this:
{
success: 1,
error: 0,
gestor: "test",
cliente: [
{
nome: "test",
apelido: "test"
}
]
}
this is the code that i have:
var gestor = new JArray();
foreach (System.Data.DataRow item in com.Execute("select * from utilizadores").Rows)
{
gestor.Add(new JObject(new JProperty("nome", item["first_name"].ToString()),
new JProperty("apelido", item["last_name"].ToString())));
}
context.Response.Write(gestor);
I would just create a class for this (actually 2):
public class MyClass
{
public int success { get; set; }
public int error { get; set; }
public string gestor { get; set; }
public List<Cliente> cliente { get; set; }
}
public class Cliente
{
public string nome { get; set; }
public string apelido { get; set; }
}
And now you can loop to populate a list of these objects:
var myObj = new MyClass();
myObj.cliente = new List<Cliente>();
foreach (System.Data.DataRow item in com.Execute("select * from utilizadores").Rows)
{
myObj.cliente.Add(new Cliente()
{
nome = item["first_name"].ToString(),
apelido = item["last_name"].ToString()
};
}
// assuming that is successful
myObj.success = 1;
// not sure how you wanted this to be populated:
myObj.gestor = "test";
And now to serialize it you can just do:
context.Response.Write(JsonConvert.SerializeObject(myObj));
Charles' suggestion of anonymous classes is also perfectly fine if you have no other use for this class and it's not too complicated.
The most succinct way to do this is just with an anonymous class, if you are throwing this to some client side code and not really messing around with this exact object again elsewhere in server side code this is the easiest way to handle it.
var outputString = JsonConvert.SerializeObject(new {
success=1,
error=0,
gestor="test",
cliente = (from System.Data.DataRow i in com.Execute("select * from utilizadores").Rows
select new {
nome=item["first_name"],
apelido= item["last_name"]
}).ToArray()
});

Categories