Using Dynamic and enforcing WCF contract upon Deserialization - c#

I have two model classes IntroModel and PhonePageModel. These are both WCF contracts.
I'm calling an API that gives back JSON and lets say I have stored it in string format.
String myApiData = myAPI.getTodaysInfo();
Using a function enum parameter, I would like to deserialize into the correct type of model
IntroPageModel introPageModel = null;
PhonePageModel phonePageModel = null;
if (enumVal == myEnums.IntroPage)
{
introPageModel = JsonConvert.DeserializeObject<IntroPageModel>(myApiData);
}
else if (enumVal == myEnums.PhonePageModel)
{
phonePageModel = JsonConvert.DeserializeObject<PhonePageModel>(myApiData);
}
This leaves the problem later in my code though of checking which model isn't null to know which model to work with afterwards. Instead, could I use dynamic but still ensure the information from myApiData is validated properly based upon the correct WCF Page model?
dynamic myPageModel = null;
if (enumVal == myEnums.IntroPage)
{
myPageModel = JsonConvert.DeserializeObject<IntroPageModel>(myApiData);
}
else if (enumVal == myEnums.PhonePageModel)
{
myPageModel = JsonConvert.DeserializeObject<PhonePageModel>(myApiData);
}

Asuming that you your get todayinfo as result array than object it will be something like this:
[
[
{
"IntroModelid": 1,
"IntroModelname": "intro123",
"guid": "151512321312",
"introModelfunc": [
{
"funcid": 1,
"funcname": "func123"
}
]
}
],
[
{
"PhonePageModelid": 1,
"PhonePageModelname": "phone123",
"other": "other",
"phonenumers": [
{
"numersid": 1,
"numbers": 6789,
"status": "OK"
},
{
"numersid": 2,
"numbers": 12345,
"funcionamiento": "NO"
}
]
}
]
]
when you get your collection as this:
var myapidata = JsonConvert.DeserializeObject(myApiDataString);
you will have two ChildrenTokens = Count = 2
you can iterate this as you wish. Or you can pass to your class list
var myapidata = (JArray)JsonConvert.DeserializeObject(json);
var IntroPageModel = myapidata [0];
var PhonePageModel = myapidata [1];
Hope you find useful

Related

Formatting my json in my C# app in a specific way

I am working on a C# app to work with a 3rd party vendor. They've requested that our JSON be formatted as such (note the "owner" array value)
var good =
{
"id": "0DE570C8-E578-48A9-B22A-F95BC6211B4F",
"make": "Subaru",
"index": "Forester",
"year": "2013",
"owner":
[
{
"First": "Bob",
"Last": "Smith"
}
]
}
In my code, I am unable to get the formatting correct. I am able to produce valid C#, but it doesn't add "owner" as an array and any attempt to make it an array (e.g. adding "[]" after the "new" produces an error ("The name 'x' does not exist in the current context"). Here is my attempted C# code:
var car = new
{
id = "0DE570C8-E578-48A9-B22A-F95BC6211B4F",
make = "Subaru",
model = "Forester",
year = "2013",
Owner = new
{
First = "Bob",
Last = "Smith"
}
};
I tried making a "Car" class and tried using an anonymous type.
Your JSON field for owner is an array and in your code you assign it as an object so you need to assign owner to an array like below:
var car = new
{
id = "0DE570C8-E578-48A9-B22A-F95BC6211B4F",
make = "Subaru",
model = "Forester",
year = "2013",
Owner = new[]
{
new { First = "Bob", Last = "Smith" }
}
};

Add a list in an existing JSON value

So I have below call to a method where my argument is a json string of this type
var jsonWithSearchData = await querySearchData(jsonOut);
jsonOut ->
[
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": "",
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
]
The querySearchData() returns me two list something like this :["P123","P124","P987"] and ["Ba123","KO817","Daaa112"]
I want to add this list in my r:searchData key above. The key inside my searchData i.e. r:Porelation and ClassA and ClassB remains static. So I would like my searchData in my input Json to finally become something like this.
"r:searchData": {
"r:Porelation":{
"ClassA": ["P123","P124","P987"],
"ClassB": ["Ba123","KO817","Daaa112"]
}
},
How can I do this? What I tried:
JArray jfinObject = JArray.Parse(jobjects);
jfinObject["r:searchData"]["r:relations"]["ClassA"] = JArray.Parse(ListofCode.ToString());
And I get below error:
System.Private.CoreLib: Exception while executing function: Function1.
Newtonsoft.Json: Accessed JArray values with invalid key value:
"r:searchData". Int32 array index expected.
There are a few ways you can add a node/object/array to existing json.
One option is to use Linq-to-Json to build up the correct model.
Assuming you have the json string described in your question, the below code will add your desired json to the r:searchData node:
var arr = JArray.Parse(json); // the json string
var payloadNode = arr[0]["data"]["payload"];
// use linq-to-json to create the correct object
var objectToAdd = new JObject(
new JProperty("r:Porelation",
new JObject(
new JProperty("r:ClassA", array1),
new JProperty("r:ClassB", array2))));
payloadNode["r:searchData"] = objectToAdd;
where array1 and array2 above could come from a linq query (or just standard arrays).
// Output:
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": {
"r:Porelation": {
"r:ClassA": [
"P123",
"P456"
],
"r:ClassB": [
"Ba123",
"Ba456"
]
}
},
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
Online demo
Another option is to create the json from an object, which could be achieved using JToken.FromObject(). However, this will only work if you have property names which are also valid for C# properties. So, this won't work for your desired property names as they contain invalid characters for C# properties, but it might help someone else:
// create JToken with required data using anonymous type
var porelation = JToken.FromObject(new
{
ClassA = new[] { "P123", "P456" }, // replace with your arrays here
ClassB = new[] { "Ba123", "Ba456" } // and here
});
// create JObject and add to original array
var newObjectToAdd = new JObject(new JProperty("r:Porelation", porelation));
payloadNode["r:searchData"] = newObjectToAdd;

C# dynamic object, modify properties based on string paths

The use case is pretty simple in concept. I receive a json payload that has two properties on the root level:
instructions
base
Instructions are set of instructions that I am supposed to apply on the base json object.
For eg - according to the below payload,
I am supposed to traverse to the widgets within defaultWidgets of the base property.
Then replace it completely with whatever is the value of patchedValue.
Input Payload:
{
"instructions": [
{
"patchedPath": "defaultWidget.widgets",
"patchedValue": false,
}
],
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": [
{
"managerId": "defaultWidget",
"widgetId": "invCreateWid7",
"type": "standard",
"manifestPath": "nexxe.standard-section#0.0.0-next.11",
"defaultInputManifestPath": "nexxe.input#0.0.1-alpha.49",
"title": "scannedInvoice",
"children": [
{
"name": "tom"
}
],
"hash": "ktocle2lrgps9",
"directives": ""
}
]
}
}
}
The result should be :
{
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": false
}
}
}
Code:
var stringPayload = "{ \"instructions\": [ { \"patchedPath\": \"defaultWidget.widgets\", \"patchedValue\": false, } ], \"base\": { \"defaultWidget\": { \"hash\": \"ktocle2l0u527\", \"layout\": \"6|6\", \"managerId\": \"defaultWidget\", \"widgets\": [ { \"managerId\": \"defaultWidget\", \"widgetId\": \"invCreateWid7\", \"type\": \"standard\", \"manifestPath\": \"nexxe.standard-section#0.0.0-next.11\", \"defaultInputManifestPath\": \"nexxe.input#0.0.1-alpha.49\", \"title\": \"scannedInvoice\", \"children\": [ { \"name\": \"tom\" } ], \"hash\": \"ktocle2lrgps9\", \"directives\": \"\" } ] } }}";
var parsedPayload = JsonConvert.DeserializeObject(stringPayload);
var baseJ = parsedPayload.GetType().GetProperty("instructions").GetValue(parsedPayload, null);
string jsonString = JsonConvert.SerializeObject(parsedPayload);
I am stuck on the very initial steps , I am getting:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
System.Type.GetProperty(...) returned null.
This is what QuickWatch says:
What's returned by DeserializeObject in this case is JObject so to start with you can cast to it:
var parsedPayload = (JObject) JsonConvert.DeserializeObject(stringPayload);
Then grab instructions and target to change:
var instructions = (JArray) parsedPayload["instructions"]; // cast to JArray
var result = parsedPayload["base"];
Then we can go over instructions and apply them:
foreach (var instruction in instructions) {
// grab target path and value
var targetPath = (string) ((JValue)instruction["patchedPath"]).Value;
var targetValue = (JValue)instruction["patchedValue"];
// temp variable to traverse the path
var target = result;
foreach (var part in targetPath.Split('.')) {
target = target[part];
}
// replace the value
target.Replace(targetValue);
}
Now result contains what was in base with instructions applied.
With Json.NET you can do that like this:
var json = File.ReadAllText("sample.json");
var semiParsedJson = JObject.Parse(json);
var instructions = (JArray)semiParsedJson["instructions"];
var #base = semiParsedJson["base"];
foreach (var instruction in instructions)
{
var path = (string)instruction["patchedPath"];
var newValue = (string)instruction["patchedValue"];
var toBeReplaced = #base.SelectToken(path);
toBeReplaced.Replace(newValue);
}
JObject.Parse parses the json string
With the index operator [] we retrieve the two top level nodes. - One of them is an array (that's why there is an explicit JArray cast)
The other one is a JToken
We iterate through the array and retrieve the path and the newvalue
We use the SelectToken to get the desired node and then apply the replacement via the Replace method.
Please bear in mind that this solution is not bulletproof. You might need to change the indexer operator to TryGetValue to be able to check existence before you perform any operation on the JToken.
You also need to check that the patchedPath is valid at all.

Removing a field from jSon String

I am storing jSon string as hexa-decimal or some characters string, its all working fine whan I retrieving as json string in my code, but there is one field I want to remove from the jSob object after I retrieved.
var t = StoredProcedures.SP_GlobalSearch.Execute(new SP_GlobalSearch_Params
{
Search = request.search,
SourceKey = "",
Skip = start,
Take = length,
ShowDeleted = false
}).Select(x => new SP_GlobalSearch
{
JsonObject = x.Data != null ? new JavaScriptSerializer().DeserializeObject(x.Data.Replace("", "")) : null,
Date = x.Date,
JsonObjectId = x.JsonObjectId,
SourceKey = x.SourceKey,
SourceId = x.SourceId,
TotalCount = x.TotalCount
});
var response = t?.ToList();
var jsondata = new DataTableResponse<SP_GlobalSearch>
{
totalCount = (int)response.Where(x => x.TotalCount != null).FirstOrDefault().TotalCount,
data = response.Where(x => x.TotalCount == null)
};
var jsonResult = Json(jsondata);
jsonResult.MaxJsonLength = Int32.MaxValue;
return jsonResult;
I am reading the text as jSon with the below statement,
JavaScriptSerializer().DeserializeObject(x.Data.Replace("", ""))
I want to remove the violations field from it, any help please. Thanks in advance
Here is my json:
{
"InspectionResultId":846,
"InspectionResultNumber":"T00846",
"InspectionRequestId":507,
"InspectionRequestNumber":"R00507",
"CaseId":689,
"InspectionResultStatusId":605,
"EnforcementSectionId":104,
"ViolationTypeId":603,
"DateOfInspection":"\/Date(1589439600000)\/",
"InspectionComment":"send to office staff, open investigation",
"InspectedCompanyDataId":964,
"ContactTypeId":701,
"EnteredById":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"InspectionResultTimestamp":"\/Date(1588280817470)\/",
"DateCreated":"\/Date(1588280817487)\/",
"DateUpdated":"\/Date(1588281867967)\/",
"CreatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UpdatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"Case":{
"RelatedContactId":0,
"CaseId":689,
"CaseNumber":"I00689",
"IsInvestigation":true,
"CaseStatusId":801,
"InspectionItemSourceId":211,
"EnforcementSectionId":104,
"ReminderDate":"\/Date(1590044400000)\/",
"PreCaseSummary":"send to office staff, open investigation",
"AssignedToInspectorId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"CaseTimestamp":"\/Date(1588281867403)\/",
"CaseCompanyId":964,
"DateCreated":"\/Date(1588281867437)\/",
"DateUpdated":"\/Date(1588281867840)\/",
"CreatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UpdatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"IsDeleted":false,
"InterpreterNeeded":false,
"VoluntaryDisclosure":false,
"PenaltyAdjustment":0,
"Company":{
"ContactId":964,
"ContactTypeId":1000,
"FirstName":"04.30.2020 new co",
"Notes":"new request",
"Active":true,
"Created":"\/Date(1588279909680)\/",
"Updated":"\/Date(1588279909680)\/",
"DateCreated":"\/Date(1588279909680)\/",
"DateUpdated":"\/Date(1588279909680)\/",
"IsEJArea":false,
"CreatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UpdatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"Classification":{
},
"Class":"Company",
"IsSpecial":false,
"Address":{
"Street1":"5678 Street",
"City":"Sacramento",
"StateCode":"CA",
"Zip":"95812",
"Country":"0"
}
}
},
"InspectionResultStatus":{
"InspectionResultStatusId":605,
"InspectionResultStatusName":"Clean",
"InspectionResultStatusSortOrder":5
},
"EnforcementSection":{
"EnforcementSectionId":104,
"EnforcementSectionName":"STBES",
"EnforcementSectionSortOrder":0,
"BranchId":2
},
"InspectedCompanyData":{
"ContactId":964,
"ContactTypeId":1000,
"FirstName":"04.30.2020 new co",
"Notes":"new request",
"Active":true,
"Created":"\/Date(1588279909680)\/",
"Updated":"\/Date(1588279909680)\/",
"DateCreated":"\/Date(1588279909680)\/",
"DateUpdated":"\/Date(1588279909680)\/",
"IsEJArea":false,
"CreatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UpdatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"Classification":{
},
"Class":"Company",
"IsSpecial":false
},
"InspectionItems":[
{
"InspectionItemId":1054,
"InspectionItemNumber":"T00000",
"InspectionRequestId":507,
"InspectionResultId":846,
"CaseId":689,
"InspectionItemSourceId":229,
"IsCreatedInCase":false,
"ShowYearMakeModel":"",
"ShowYearMakeModelVIN":"",
"GrossWeight":0.00,
"RegHoldSet":false,
"InspectionItemTimestamp":"\/Date(1588280802553)\/",
"DateCreated":"\/Date(1588280802567)\/",
"DateUpdated":"\/Date(1588281868153)\/",
"CreatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UpdatedByUserId":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"Violations":[
]
}
],
"CompletedBy":[
{
"IsActive":true,
"FirstName":"Daphne",
"LastName":"Greene",
"ObjectGUID":"S-1-5-21-1538631513-416410304-3002070310-33442",
"NameLoginFormat":"dgreene",
"NameFirstLast":"Daphne Greene",
"NameLastFirst":"Greene Daphne",
"Email":"daphne.greene#arb.ca.gov",
"EmailConfirmed":false,
"SecurityStamp":"e061e77e-c93e-4b9e-8497-4852b5cb4ca2",
"PhoneNumberConfirmed":false,
"TwoFactorEnabled":false,
"LockoutEnabled":false,
"AccessFailedCount":0,
"Id":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UserName":"dgreene"
}
],
"EnteredBy":{
"IsActive":true,
"FirstName":"Daphne",
"LastName":"Greene",
"ObjectGUID":"S-1-5-21-1538631513-416410304-3002070310-33442",
"NameLoginFormat":"dgreene",
"NameFirstLast":"Daphne Greene",
"NameLastFirst":"Greene Daphne",
"Email":"daphne.greene#arb.ca.gov",
"EmailConfirmed":false,
"SecurityStamp":"e061e77e-c93e-4b9e-8497-4852b5cb4ca2",
"PhoneNumberConfirmed":false,
"TwoFactorEnabled":false,
"LockoutEnabled":false,
"AccessFailedCount":0,
"Id":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UserName":"dgreene"
},
"MyGridContacts":[
],
"CreatedByUser":{
"IsActive":true,
"FirstName":"Daphne",
"LastName":"Greene",
"ObjectGUID":"S-1-5-21-1538631513-416410304-3002070310-33442",
"NameLoginFormat":"dgreene",
"NameFirstLast":"Daphne Greene",
"NameLastFirst":"Greene Daphne",
"Email":"daphne.greene#arb.ca.gov",
"EmailConfirmed":false,
"SecurityStamp":"e061e77e-c93e-4b9e-8497-4852b5cb4ca2",
"PhoneNumberConfirmed":false,
"TwoFactorEnabled":false,
"LockoutEnabled":false,
"AccessFailedCount":0,
"Id":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UserName":"dgreene"
},
"UpdatedByUser":{
"IsActive":true,
"FirstName":"Daphne",
"LastName":"Greene",
"ObjectGUID":"S-1-5-21-1538631513-416410304-3002070310-33442",
"NameLoginFormat":"dgreene",
"NameFirstLast":"Daphne Greene",
"NameLastFirst":"Greene Daphne",
"Email":"daphne.greene#arb.ca.gov",
"EmailConfirmed":false,
"SecurityStamp":"e061e77e-c93e-4b9e-8497-4852b5cb4ca2",
"PhoneNumberConfirmed":false,
"TwoFactorEnabled":false,
"LockoutEnabled":false,
"AccessFailedCount":0,
"Id":"7f54fa3e-b5cd-4b2e-9490-92f64c022246",
"UserName":"dgreene"
}
}
This above object is a dynamic object returned as string I want to remove Violation related fields and its values from it.
I want to remove the Violations, ViolationTypeId etc fields related to Violation from the jSon object above, can you please help me in this regards thank you.
You can simply convert it to object, remove the field and back to string.
for example in javascript
assuming your json is in variable myjson
tmp = Object(myjson.Data)
delete tmp.Violations
myjson.Data = JSON.stringify(tmp)
in C#, assuming Data is your string json
JObject tmp = JObject.Parse(Data);
tmp.Property("Violations").Remove();
Data = JavaScriptSerializer().Serialize(jsonResult.Data);

How to access JOBJECT element and change its value

In my controller I have this method :
public Tuple<DataTable, DataTable> GraphData(JObject jsonData)
The object has this data :
"Wgraph": {
"GraphType": "Line",
"XAxisList": [
{
"Dimension": "[DimCustomer].[AddressLine1].[AddressLine1]",
"HIERARCHY": "[DimCustomer].[AddressLine1]"
}
],
"YAxisList": [
{
"MeasureExpression": "undefined",
"ChartType": "",
"IsSecondaryAxis": "False"
},
{
"MeasureExpression": "undefined",
"ChartType": "",
"IsSecondaryAxis": "False"
}
},
"DashboardName": "NewTest"
}
What I am trying to do it access the second value of "IsSecondaryAxis":"False" and change its value to TRUE
How can I retrieve this data ?
Thank you
You can access the second element of the array using:
var arr = jsonData["Wgraph"]["YAxisList"] as JArray;
arr[1]["IsSecondaryAxis"] = true;
As the first response of Lee Gunn, but using a dynamic object:
var arr = ((dynamic) jsonData).Wgraph.YAxisList;
arr[1]["IsSecondaryAxis"] = true;
The result is the same. Regards.

Categories