JSON message handler in C# - c#

I am trying to make a message handler for received JSON strings over MQTT. I have this working for one type of message.
Here is my code:
static void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
// handle message received
Console.WriteLine("Received = " + Encoding.UTF8.GetString(e.Message) + " on topic " + e.Topic);
string source = Encoding.UTF8.GetString(e.Message);
dynamic data = JObject.Parse(source);
Console.WriteLine(data.content.value);
// this data.content.value is working for message 1 but crashes for message 2
}
How can I avoid using a lot of try catches in my message handler in case I have 2 (or more) different MQTT messages entering?
These are my 2 types of messages for now:
/// message 1:
{
"header": {
"headeritem": "exampleheader",
"type": "headertype",
"info": "headerinfo"
},
"content": {
"name": "contentname",
"value": true
}
}
/// message 2:
{
"header": {
"headeritem": "exampleheader",
"type": "headertype",
"info": "headerinfo"
},
"content": {
"item1": "exampleitem1",
"item2": "exampleitem2",
"item3": [
{
"item3type1": "exampletype1.1",
"item3type2": "exampletype2.1",
"item3type3": "exampletype3.1",
"item3type4": ["0xFFAA"]
},
{
"item3type1": "exampletype1.2",
"item3type2": "exampletype2.2",
"item3type3": "exampletype3.2",
"item3type4": ["0xFFBB"]
},
{
"item3type1": "exampletype1.3",
"item3type2": "exampletype2.3",
"item3type3": "exampletype3.3",
"item3type4": ["0xFFCC"]
}
]
}
}

When you do not know what JSON type is comming in, you can use reflection on the dynamic data type to check if the property exists.
Like explained here:
Test if a property is available on a dynamic variable
However, when the different JSON formats are limited to only a few, maybe you are better off creating hard typed classes to parse the JSON in.
Like explained here:
How to Convert JSON object to Custom C# object?
This way you do not have to worry about whether a property exists.

Related

Generate JSON from two different JSON objects without coding custom logic

I have a requirement where an event will emit a JSON following a defined schema = JSON-EventA schema. I have a config(config.json) that follows another JSON-EventB schema. Using data from JSON-EventA and Config from config.json, I have to generate a JSON event data which should follow the JSON-EventB schema. Is this possible to write a function GenerateEventData which takes the eventA data and config to generate EventB data ? Without coding the POCO and writing custom logic to convert from one json to another ? I want to be able to update the JSON-EventA schema, config.json without touching the function GenerateEventData, it should be able to generate data in the new JSON-EventB schema as directed by config.json
Illustrating an example that I want -
// I can get an event data and ensure it follows JSON-EventA schema
string eventAData = GetEvent(A);
/*
eventAData = {"Title": "MyTitle", "Address": {"PING": "123"}}
Follows the below schema
EventASchema = {
"type": "object",
"properties": {
"Title": {
"type": "string"
},
"Address": {
"type": "object",
"properties": {
"PIN": {
"type": "string"
}
}
}
};*/
string config = GetConfig();
// config = {"NewTitle": "Generated ${Title}", "PIN": "000${Address.PIN}", "Country": "US"}
//This is what I want to achieve.
string eventB = GenerateEventData(A, config);
/*
eventB = {"NewTitle": "Generated MyTitle", "PIN": "000123", "Country": "US"}
*/

Parsing JSON Using Newtonsoft.Json Without Knowing the Structure

I'm working on a project that involves automating API calls using a Swagger Definition. I download the swagger.json file. The structure of the JSON Object I need to parse is not consistent. When parsing paths, there are a list of objects, then within that they have the methods that can be used for that specific path. I can retrieve just the path using various string methods but my question was, is there a good way to parse json if the JSON is structured in such a way that it does not have a firm key? Here is an example of what I mean:
{"/user": {
"post": {
"tags": [
"user"
],
"summary": "Create user",
"description": "This can only be done by the logged in user.",
"operationId": "createUser",
"consumes": [
"application/json"
],
"produces": [
"application/json",
"application/xml"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Created user object",
"required": true,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
}
If I wanted to just parse that path and retrieve the method object how could I go about that considering sometimes the object will be "post" or sometimes it will be "get", "put", etc depending on what is allowable for the path.
JObject jsonResp = swaggerDownload();
JObject paths = (JObject)jsonResp["paths"];
foreach (var i in paths)
{
string pathToString = i.ToString();
var shaveSomethings = pathToString.Substring(1, something.Length - 2);
var pathAndJson = shaveSomethings.Split(new[] { ',' }, 2);
string correctJsonStructure = "{\"" + pathAndJson[0] + "\":" + pathAndJson[1] + "}";
JObject bd = JObject.Parse(correctJsonStructure);
//dynamic pathsTest = JsonConvert.DeserializeObject<dynamic>(correctJsonStructure);
//JObject result = JsonConvert.DeserializeObject<JObject>(correctJsonStructure);
//Console.WriteLine(bd["/user"]);
}
The swagger.json file should have full definition of each entity that endpoints return. You can follow How to create Rest API client to get a working client.
I've dealt with an API where responses didn't always match the definition. I saved all responses to a store/log first and then would try to de-serialize JSON. In case of an exception I would go back to store/log and see what was different and update my code to accommodate for the change. After few iterations there were no new changes and the ordeal was over.
Hope that helps.

Can you send a dynamic template to a list, using only list id?

According to the SendGrid docs, it seems like I can send a template to a list by inputting the template ID and list ID into the singlesend call. However when I call this method with those JSON fields, I get an error.
JSON:
{"sender_id":779461,"filter":{"list_ids":["572d0ae8-c665-4265-8e90-28fda56d9409"],"send_to_all":"false"},"template_id":"d-2b8c55e6e0a6463ab096d2e146d77c2c"}
Error: {
"errors": [
{
"field": "",
"message": "json could not be unmarshalled"
}
]
}
I've been trying to get the correct JSON format for a while now, with no luck due to this non-descriptive error. I am also using the C# library for .NET and I cannot find any methods to set a list id to the message. The SendGrid support portal is broken so I cannot reach out to them.
try your json like this send_to_all is not of type string but boolean:
{
"sender_id": 779461,
"filter": {
"list_ids": [
"572d0ae8-c665-4265-8e90-28fda56d9409"
],
"send_to_all": false
},
"template_id": "REAL UUID"
}

Asp.net Mvc receives a complex object as a list of key/value pair array

I have two asp.net mvc apps that am trying to get to communicate with each other by sending a complex serialized object from one of the app to the other.
But when the data reaches the other end, the object comes in as a list of array of key-value pair. Below are the details of the what am trying to send/recieve.
Here is the code that am using to send the json object
using (var hc = new HttpClient())
{
hc.DefaultRequestHeaders.Accept.Clear();
hc.DefaultRequestHeaders.Accept.Add(Media);
var dict = new Dictionary<string, DejaVuObject> {{"Entity", obj}};
var strinified = JsonConvert.SerializeObject(dict);
var stringContent = new StringContent(strinified, Encoding.UTF8, "application/json");
var response = await hc.PostAsync(url, stringContent);
return response;
}
The receiving method signature
[HttpPost]
public ActionResult RecieveEntity(Dictionary<string, object> post)
Here is what am sending
{
"Main Service ID": "1",
"Node ID": "",
"Parameters": [
{
"Name": "firstname",
"Validation": {
"Entity": 0,
"EntityListFilter": "",
"IsNotEditable": false,
"IsPrimaryIdentifier": false,
"IsRequired": true,
"IsUnique": false,
"Parameter Format": 0,
"ParameterMode": ""
}
}
],
"CustomEvents": [
{
"Description": "event description",
"Message": "new message",
"MilestoneCondition": "milestone information.",
"Name": "new message",
"TheFields": []
}
],
"Processings String": "Action failed.[TN01-31:Action failed]"
}
Here is what am receiving
{
"Processings String": "Action failed.[TC01-71:Action failed while processing the request.]::Action succeeded.[TC01-54:Processing this command was successful.]",
"Parameters": "[Name, Firstname][Validation, ][Key, 2e431711-2ba9-40ef-985e-dbfa8c13a932][isrequired, True][fieldname, ][Name, Lastname][Validation, ][Key, be4de2d6-d39e-44fa-8f31-b4b0964f82da]",
"CustomEvents": "[Description, Processing this command was successful][Message, Action suceeded][MilestoneCondition, When command processing suceeds.][Name, Action suceeded][TheFields, System.Collections.Generic.List`1[System.Dynamic.DejaVuObject]]",
"Main Service ID": "1"
}
If you look properly in what comes into the other system, you will find that the of most of the inner object is an array of key/value pair instead of ordinary array of objects that was sent. What am I doing wrong, and how do i go about correcting it?
Its the fact that you're using a dictionary type to receive the content. At the point the data packet is sent from the app1 its as per your definition. So updating app1 isn't going to help you.
As #Krishna has suggested update the signature to use dynamic, or you can extend your current app2 method to deal with the new interface.
Do you have an example of the data packet from one of the existing integrated apps?

Valid JSON string throws Unexpected character encountered error

I'm trying to connect an angular2 client to a C# ASP.net core server. When I'm sending a JSON string using websockets from the client to the server, I get an error:
Unexpected character encountered while parsing value: {. Path 'Argument', line 1, position 39.
The JSON string is as follows (The error seems to originate from the opening bracket after "Argument:"):
{
"MethodName": "CreateUser",
"Argument": {
"User": {
"Attributes": [{
"Name": "age",
"Value": "30",
"Type": 0
}],
"Email": "test#mail.com",
"Name": "Test Name"
},
"Password": "1234"
}
}
The code that throws the error is here:
public string Receive(string input)
{
try
{
Debug.WriteLine(input);
InstructionServer jsonObject = JsonConvert.DeserializeObject<InstructionServer>(input); // This fails
string methodName = jsonObject.MethodName;
string data = jsonObject.Argument;
return methods[methodName](1, data, "", "");
}
catch (Exception e)
{
return "error: " + e.Message;
}
}
I can't seem to figure out what the error is, because when I throw the JSON into an online JSON Formatter, it reports it as valid JSON. Any help would be appreciated.
EDIT: Just to clarify on the valid JSON. I tried printing the json string out before sending it on the client and after receiving it on the server, and it is the same json string as written above.
Argument appears to be expecting a string, but found an object. You'll have to check the format that InstructionServer is expecting and ensure that it will be able to deserialize correctly.
The Receive method expect the string value, this means you have to convert your object to JSON format to be like this:
"{\"MethodName\":\"CreateUser\",\"Argument\":{\"User\":{\"Attributes\":[{\"Name\":\"age\",\"Value\":\"30\",\"Type\":0}],\"Email\":\"test#mail.com\",\"Name\":\"Test Name\"},\"Password\":\"1234\"}}"

Categories

Resources