How to read values from JsonNode in System.Text.Json - c#

I want to serialize a refresh token and send it to the client.
Then on return, I want to deserialize and read it.
Here's my code.
using System.Text.Json;
using System.Dynamic;
using System;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using System.Text.Json.Nodes;
dynamic token = new ExpandoObject();
token.UserName = "John";
token.Expires = DateTime.Now.AddMinutes(5);
token.CreateDate = DateTime.Now;
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
};
var refreshToken = JsonSerializer.Serialize(token, options);
Console.WriteLine(refreshToken);
var deserializedToken = JsonSerializer.Deserialize<JsonNode>(refreshToken, options);
var userName = "How can I extract username from JsonNode";
I tried to use JsonNode["UserName"].Value, but it does not work.

Since you are using dynamic all subsequent variables are resolved as dynamic too. Just declare one of the types (for example string for serialization result) and use indexer + GetValue:
string refreshToken = JsonSerializer.Serialize(token, options);
JsonNode? deserializedToken = JsonSerializer.Deserialize<JsonNode>(refreshToken, options);
var userName = deserializedToken["userName"].GetValue<string>();

Your type after deserializaton will be a JsonNode, If you try to use a dynamic, your type after deserialization will be a JsonElement, so you can not gain anything with dynamic too. You can just use Parse
JsonNode deserializedToken = JsonNode.Parse(refreshToken);
string userName = (string) deserializedToken["userName"];
and you can create a json string much more simple way and without using options too
var token = new
{
userName = "John",
expires = DateTime.Now.AddMinutes(5),
createDate = DateTime.Now
};
string refreshToken = System.Text.Json.JsonSerializer.Serialize(token);

Related

CosmosDb c# SDK is not working on contrary to the Rest Api

I am using CosmosDb Sdk with nuget Microsoft.Azure.DocumentDB.Core 2.1.0 with .NetStandard 2.0.
I am using this query to fetch documents
var client client = new DocumentClient(new Uri(config.CosmosDbEndPointUrl), config.CosmosDbPrimaryKey);
var partitionKey = "siteId"; // the partition key is defined as /siteId, I tried both, still not working
var queryOptions = new FeedOptions
{
MaxItemCount = 500,
EnableCrossPartitionQuery = true,
PartitionKey = new PartitionKey(partitionKey)
};
var auditQuery = client
.CreateDocumentQuery<AuditDTO>(
UriFactory.CreateDocumentCollectionUri(_databaseName, _collectionName), queryOptions)
.Where(f => f.Status == AuditStatus.Pending)
.AsDocumentQuery();
var results = new List<AuditDTO>();
while (auditQuery.HasMoreResults)
{
var audits = await auditQuery.ExecuteNextAsync<AuditDTO>();
results.AddRange(audits);
}
This query returns 0 document.
I based my query on this tutorial
I thought some parameters were incorrect so, I tried to use the Rest Api, code based on this example (see comment EXECUTE a query)
var client = new System.Net.Http.HttpClient();
string response = string.Empty;
string authHeader = string.Empty;
string verb = string.Empty;
string resourceType = string.Empty;
string resourceId = string.Empty;
string resourceLink = string.Empty;
client.DefaultRequestHeaders.Add("x-ms-date", utc_date);
client.DefaultRequestHeaders.Add("x-ms-version", "2017-02-22");
verb = "POST";
resourceType = "docs";
resourceLink = $"dbs/{databaseId}/colls/{collectionId}/docs";
resourceId = (idBased) ? $"dbs/{databaseId}/colls/{collectionId}" : collectionId.ToLowerInvariant();
authHeader = GenerateMasterKeyAuthorizationSignature(verb, resourceId, resourceType, masterKey, "master", "1.0");
client.DefaultRequestHeaders.Remove("authorization");
client.DefaultRequestHeaders.Add("authorization", authHeader);
client.DefaultRequestHeaders.Add("x-ms-documentdb-isquery", "True");
client.DefaultRequestHeaders.Add("x-ms-documentdb-query-enablecrosspartition", "true");
client.DefaultRequestHeaders.Add("x-ms-partition-key", "[\"siteId\"]");
var qry = new SqlQuerySpec { query = "SELECT * FROM root WHERE (root[\"status\"] = 0)" };
var r = await client.PostWithNoCharSetAsync(new Uri(baseUri, resourceLink), qry);
var s = await r.Content.ReadAsStringAsync();
Using the Rest Api returns 1 document as I am expecting.
I tried to deserialize the response to the class AuditDTO, it works, so, no problem with my model.
I don't understand why the Rest Api is working and not the .Net Sdk.
There is no authorization exception, no error message. I just get 0 document.
I am missing something?
var partitionKey = "siteId";
var queryOptions = new FeedOptions
{
MaxItemCount = 500,
EnableCrossPartitionQuery = true,
PartitionKey = new PartitionKey(partitionKey)
};
Your problem is on the partition key.
Partition key is expected to be the value of the partition key not the definition.
This means that the partitionKey value on FeedOptions should look like this 59c49da3-b398-4db7-aff4-d2129353e3a8 (assuming it's a guid) not this siteId.
The correct FeedOptions Object would look like this:
var partitionKey = "59c49da3-b398-4db7-aff4-d2129353e3a8";
var queryOptions = new FeedOptions
{
MaxItemCount = 500,
EnableCrossPartitionQuery = true,
PartitionKey = new PartitionKey(partitionKey)
};
The documentation is really misleading.
To enable CrossPartition queries to query all partitions, you just need to set EnableCrossPartitionQuery to true and that's it!
var queryOptions = new FeedOptions
{
MaxItemCount = 500,
EnableCrossPartitionQuery = true
};
As Nick Chapsas said, if you need to search a specific partition, set the PartitionKey property to the value of the partition you want to search against.
Here is a sample I found on Azure GitHub.

C# items as root nodes of JSON

I'm trying to pass a Json that I'd like to access from jquery as,
jdata.comType
my c# code is,
var frontChartList = new List<object>();
frontChartList.Add(new
{
comType = comType,
today = DateTime.Now.ToString("D"),
agentsAdded = "53",
agentsAvail = "47",
packageAvailDays = leftDays.ToString(),
});
JavaScriptSerializer jss = new JavaScriptSerializer();
String json = jss.Serialize(frontChartList);
return json;
I cannot access this as
jdata.comType
only as,
jdata[0].comType
how should I create the JSON to get a string accessible as jdata.comType?
since I will only be passing one object in this.
Because your frontChartList is a List<object>, change it to single object instead:
var frontChartList = new
{
comType = comType,
today = DateTime.Now.ToString("D"),
agentsAdded = "53",
agentsAvail = "47",
packageAvailDays = leftDays.ToString(),
});

Include quotes around json aws sns call

I need for AWS SNS the correct formatted JSON object but my format is wrong.
dynamic foo = new ExpandoObject();
foo.GCM = new ExpandoObject {};
foo.GCM.data = new ExpandoObject();
foo.GCM.data.message = "bogus";
string json = Newtonsoft.Json.JsonConvert.SerializeObject(foo,Newtonsoft.Json.Formatting.None);
The result:
{"GCM":{"data":{"message":"bogus"}}}
Required format: {"GCM":"{\"data\":{\"message\":\"bogus\"}}"}
dynamic foo = new ExpandoObject();
foo.data = new ExpandoObject();
foo.data.message = "bogus";
string json1 = JsonConvert.SerializeObject(foo, Newtonsoft.Json.Formatting.None);
var json = JsonConvert.SerializeObject(new { GCM=json1 } , Newtonsoft.Json.Formatting.None);
OUTPUT: {"GCM":"{\"data\":{\"message\":\"bogus\"}}"}
But I don't understand why this Required format needs double serialization. Are you sure about it?

Json.net deserialize DateTime from HTTPClient result

I am using HTTPCLient to call RestFul service. My problem when parsing DateTime.
Because in my class I have DateTime Property. Which in Json it is type long. Json key is: exp
{
"resultCodes": "OK",
"description": "OK",
"pans": {
"maskedPan": [
{
"id": "4b533683-bla-bla-3517",
"pan": "67*********98",
"exp": 1446321600000,
"isDefault": true
},
{
"id": "a3093f00-zurna-01e18a8d4d72",
"pan": "57*********96",
"exp": 1554058800000,
"isDefault": false
}
]
}
}
In documentation i read that
To minimize memory usage and the number of objects allocated Json.NET supports serializing and deserializing directly to a stream.
So =>
WAY 1 (Reading via GetStringAsync). In documentation has written that use StreamReader instead.
return Task.Factory.StartNew(() =>
{
var client = new HttpClient(_handler);
var url = String.Format(_baseUrl + #"list/{0}", sessionId);
BillsList result;
var rrrrr = client.GetStringAsync(url).Result;
result = JsonConvert.DeserializeObject<BillsList>(rrrrr,
new MyDateTimeConverter());
return result;
}, cancellationToken);
WAY 2(Good way. I read via StreamReader. Bu in line var rTS = sr.ReadToEnd(); it creates new string. It is not good. Because i have used GetStreamAsync to avoid of creating string variable.)
return Task.Factory.StartNew(() =>
{
var client = new HttpClient(_handler);
var url = String.Format(_baseUrl + #"list/{0}", sessionId);
BillsList result;
using (var s = client.GetStreamAsync(url).Result)
using (var sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
var rTS = sr.ReadToEnd();
result = JsonConvert.DeserializeObject<BillsList>(rTS,
new MyDateTimeConverter());
}
return result;
}, cancellationToken);
WAY 3(The best. But it gives exception if property is DateTime in my class. )
return Task.Factory.StartNew(() =>
{
var client = new HttpClient(_handler);
var url = String.Format(_baseUrl + #"list/{0}", sessionId);
BillsList result;
using (var s = client.GetStreamAsync(url).Result)
using (var sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
var serializer = new JsonSerializer();
result = serializer.Deserialize<BillsList>(reader);
}
return result;
}, cancellationToken);
So my question. I want to continue with 3-rd way. But have there any way to set some handler as MyDateTimeConverter for JsonSerializer to convert it automatically?
You can set up default JsonSerializerSettings when your app is initialized:
// This needs to be done only once, so put it in an appropriate static initializer.
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new MyDateTimeConverter() }
};
Then later you can use JsonSerializer.CreateDefault
JsonSerializer serializer = JsonSerializer.CreateDefault();
result = serializer.Deserialize<BillsList>(reader);
You can add your MyDateTimeConverter to the Converters collection on the JsonSerializer; that should allow you to use your third approach without getting errors.
var serializer = new JsonSerializer();
serializer.Converters.Add(new MyDateTimeConverter());
result = serializer.Deserialize<BillsList>(reader);

Return Single result from mongo doc

Hi I am trying to make a generic method to return a single value from the database
I am not sure where to put the return result, value is returned as a BSON document.I need 1 value from it....
public static string SearchMongoSingleValue(string key, string value, string ducument, string datatable)
{
var connectionString = "mongodb://localhost";
var client = new MongoClient(connectionString);
var server = client.GetServer();
var database = server.GetDatabase(datatable);
var collection = database.GetCollection(ducument);
var query = Query.EQ(key, value);
var oneDocument = collection.FindOne(query);
return oneDocument[value];
Thanks
I think you need oneDocument[key] and not oneDocument[value]. Just tested this code:
using MongoDB.Driver;
using MongoDB.Bson;
using MongoDB.Driver.Builders;
var client = new MongoClient("mongodb://localhost");
var coll = client.GetServer().GetDatabase("local").GetCollection("test1");
var doc = new BsonDocument();
doc.Add("Name","John");
doc.Add("Color","Red");
coll.Insert(doc);
var query = Query.EQ("Name", "John");
var doc2 = coll.FindOne(query);
var value = doc2["Color"];
It returns "Red" allright

Categories