Archive
C# | Parse Json using System.Text.Json (instead of Json.NET)
In this post lets see how to parse a complex Json content without using Json.NET library and by using the native System.Text.Json namespace.
What and why cant I use Json.NET library?
- Json.NET (also known as Newtonsoft.Json) is a popular third-party JSON library for .NET.
- Flexible Serialization, Better Performance, LINQ to JSON, JSON Path, and JSON Schema validation are some of the standout features of Json.NET library.
- I was unable to utilize the Json.NET library solely due to the fact that it is a third-party tool, and we are obligated not to use it.
Scenario:
Coming to our scenario we have following json content and we need to parse and read the inputs and outputs collection from the actions array.
{
"actions": [
{
"name": "Display select file dialog",
"status": "Failed",
"inputs": {
"allowMultiple": {
"localizedName": "Allow multiple selection",
"value": "False",
"variableName": ""
},
"title": {
"localizedName": "Dialog title",
"value": "Select the excel file to extract table from...",
"variableName": ""
}
},
"outputs": {
"selectedFile": {
"localizedName": "Selected file",
"value": "",
"variableName": "SelectedFile"
},
"buttonPressed": {
"localizedName": "Button pressed",
"value": "Cancel",
"variableName": "ButtonPressed"
}
}
},
{
"name": "If",
"status": "Succeeded",
"inputs": {
"expression": {
"localizedName": "Condition",
"value": "False",
"variableName": ""
}
},
"outputs": {}
}
],
"childFlowsLogStatus": "Default"
}
C# Code Snippet:
Following is the C# code snippet , which parses the json content and flattens the inputs and outputs collection json using native System.Text.Json namespace.
using System;
using System.Text;
using System.Text.Json;
namespace ParseJson
{
class Program
{
static void Main(string[] args)
{
try
{
var jsonContent = "{\"actions\":[{\"name\":\"Display select file dialog\",\"status\":\"Failed\",\"inputs\":{\"allowMultiple\":{\"localizedName\":\"Allow multiple selection\",\"value\":\"False\",\"variableName\":\"\"},\"title\":{\"localizedName\":\"Dialog title\",\"value\":\"Select the excel file to extract table from...\",\"variableName\":\"\"}},\"outputs\":{\"selectedFile\":{\"localizedName\":\"Selected file\",\"value\":\"\",\"variableName\":\"SelectedFile\"},\"buttonPressed\":{\"localizedName\":\"Button pressed\",\"value\":\"Cancel\",\"variableName\":\"ButtonPressed\"}}},{\"name\":\"If\",\"status\":\"Succeeded\",\"inputs\":{\"expression\":{\"localizedName\":\"Condition\",\"value\":\"False\",\"variableName\":\"\"}},\"outputs\":{}}],\"childFlowsLogStatus\":\"Default\"}";
string strInputXML = ParseInputandOutput(jsonContent, "inputs");
string strOutputXML = ParseInputandOutput(jsonContent, "outputs");
Console.WriteLine($"Input content : {strInputXML}");
Console.WriteLine($"Output content : {strOutputXML}");
}
catch (Exception ex)
{
Console.WriteLine($"Error {ex.Message}");
}
finally
{
Console.ReadLine();
}
}
private static string ParseInputandOutput(string flowContextDetails, string propertyName)
{
StringBuilder sbrRawText = new StringBuilder();
JsonDocument doc = JsonDocument.Parse(flowContextDetails);
JsonElement actions = doc.RootElement.GetProperty("actions");
foreach (JsonElement action in actions.EnumerateArray())
{
if (action.GetProperty("status").GetString() == "Failed")
{
JsonElement propertyNodes = action.GetProperty(propertyName);
sbrRawText.AppendLine(propertyNodes.ToString());
}
}
return sbrRawText.ToString();
}
}
}
Run the console app and you will get the flattened json of inputs and outputs collection.
Hope this blog post gives the idea of how to parse json using native System.Text.Json namespace.
Dataverse File Download error | Feature ‘target-typed object creation’ is not available in C# 7.3
I was trying to download the Dataverse File using the code snippet provided in official documentation.
Following is the snippet and I got the Feature ‘target-typed object creation’ is not available in C# 7.3 compilation error.
Reason:
- Target-typed new expressions has been introduced in C# 9.0 using which we do not require type specification for constructors when the type is known.
- Since I was not having C# 9.0 I was getting the compilation error.
Fix:
- Fix is simple, we need to replace
InitializeFileBlocksDownloadRequest initializeFileBlocksDownloadRequest = new()
{
Target = entityReference,
FileAttributeName = fileAttributeName
};sds
with
InitializeFileBlocksDownloadRequest initializeFileBlocksDownloadRequest = new InitializeFileBlocksDownloadRequest
{
Target = entityReference,
FileAttributeName = fileAttributeName
};
and replace
List<byte> fileBytes = new();
with
List<byte> fileBytes = new List<byte>();
Modified code snippet:
/// <summary>
/// Downloads a file
/// </summary>
/// <param name="service">The service</param>
/// <param name="entityReference">A reference to the record with the file column</param>
/// <param name="fileAttributeName">The name of the file column</param>
/// <returns></returns>
private static byte[] DownloadFile(
IOrganizationService service,
EntityReference entityReference,
string fileAttributeName)
{
InitializeFileBlocksDownloadRequest initializeFileBlocksDownloadRequest = new InitializeFileBlocksDownloadRequest()
{
Target = entityReference,
FileAttributeName = fileAttributeName
};
var initializeFileBlocksDownloadResponse =
(InitializeFileBlocksDownloadResponse)service.Execute(initializeFileBlocksDownloadRequest);
string fileContinuationToken = initializeFileBlocksDownloadResponse.FileContinuationToken;
long fileSizeInBytes = initializeFileBlocksDownloadResponse.FileSizeInBytes;
List<byte> fileBytes = new List<byte>();
long offset = 0;
long blockSizeDownload = 4 * 1024 * 1024; // 4 MB
// File size may be smaller than defined block size
if (fileSizeInBytes < blockSizeDownload)
{
blockSizeDownload = fileSizeInBytes;
}
while (fileSizeInBytes > 0)
{
// Prepare the request
DownloadBlockRequest downLoadBlockRequest = new()
{
BlockLength = blockSizeDownload,
FileContinuationToken = fileContinuationToken,
Offset = offset
};
// Send the request
var downloadBlockResponse =
(DownloadBlockResponse)service.Execute(downLoadBlockRequest);
// Add the block returned to the list
fileBytes.AddRange(downloadBlockResponse.Data);
// Subtract the amount downloaded,
// which may make fileSizeInBytes < 0 and indicate
// no further blocks to download
fileSizeInBytes -= (int)blockSizeDownload;
// Increment the offset to start at the beginning of the next block.
offset += blockSizeDownload;
}
return fileBytes.ToArray();
}
🙂
C# | Telesign | Send SMS | Couldn’t load type Telesign.MessagingClient
Telesign is a Communications Platform as a Service company. We can Send and receive text messages effortlessly with TeleSign’s global text message API.
Other day I’ve subscribed to Telesign trial and was trying to send SMS from my C# console application.
As a first step I’ve installed ‘Telesign’ NuGet package to my C# console project and pasted the code copied form Telesign portal.
I got following “Couldn not load type ‘Telesign.MessagingClient’ from assembly Telesign” exception when I ran the code.
Reason and Fix:
- My C# console project name was ‘TeleSign’ which conflicted with ‘Telesign’ NuGet package assembly.
- Rename the Project solved the issue.
Its trivial issue but took sometime to figure out the reason. Hope this helps.
🙂