Passing variables into a string variable that contains json - c#

I am trying to replace some parts of my query with a variable that holds a certain value.
For instance, inside of my variable query I am wanting to replace
\"level\": \"Information\"
and \"match\": { \"level\": \"Error\"
with variable fieldName and variable fieldValue respectively
The fieldName holds a value of "_source.level"
and fieldValue holds a value of "information" and "error".
(Not sure if I have to make another variable to hold the
second value of "error" since I am wanting both information and
error.)
The issue I am running into is normally I know you would add a $ before the string and add a {} where you want to call the variable. However, when I add a $ at the beginning of my string it does not like it and says
Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
So I am facing issues trying to figure out how I can pass those variables into my query variable.
string jsonFromFile;
using (var reader = new StreamReader(path))
{
jsonFromFile = reader.ReadToEnd();
}
var json = JsonConvert.DeserializeObject<VirtualSupport>(jsonFromFile);
foreach (var item in json.Systems.Applications)
{
foreach (var x in item.Application)
{
foreach (var y in x.BusinessProcessSteps)
{
foreach (var z in y.BusinessProcessStep.LogDataSources)
{
var fieldName = z.LogDataSource.LogFieldsMapping.LevelField.FieldName;
var fieldValue = z.LogDataSource.LogFieldsMapping.LevelField.FieldValue;
}
}
}
}
var query = "{\"size\": 1000,\"query\": {\"bool\": {\"should\":[ {\"match\": { \"level\": \"Information\" } }, {\"match\": { \"level\": \"Error\" } } ], " +
"\"filter\": [ { \"range\": { \"#timestamp\": { \"gte\": \"2021-07-26T07:58:45.304-05:00\", \"lt\": \"2021-07-26T08:58:45.305-05:00\" } } } ]," +
"\"minimum_should_match\": 1 } } }";
Snippet of the json file that I am reading from and assigning fieldname and fieldvalue to.
"LogFieldsMapping": {
"IDField": { "FieldName": "_id" },
"LevelField": {
"FieldName": "_source.level",
"FieldValue": [
{ "value": "Information" },
{ "value": "Error" }
]
}
}

Rather then using the $ (string interpolation), you could consider converting the query-string into a class:
{
"size": 1000,
"query": {
"bool": {
"should": [
{
"match": {
"level": "Information"
}
},
{
"match": {
"level": "Error"
}
}
],
"filter": [
{
"range": {
"#timestamp": {
"gte": "2021-07-26T07:58:45.304-05:00",
"lt": "2021-07-26T08:58:45.305-05:00"
}
}
}
],
"minimum_should_match": 1
}
}
}
Which could be converted to something like this:
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Match
{
public string level { get; set; }
}
public class Should
{
public Match match { get; set; }
}
public class Timestamp
{
public DateTime gte { get; set; }
public DateTime lt { get; set; }
}
public class Range
{
[JsonProperty("#timestamp")]
public Timestamp Timestamp { get; set; }
}
public class Filter
{
public Range range { get; set; }
}
public class Bool
{
public List<Should> should { get; set; }
public List<Filter> filter { get; set; }
public int minimum_should_match { get; set; }
}
public class Query
{
public Bool #bool { get; set; }
}
public class Root
{
public int size { get; set; }
public Query query { get; set; }
}
You can instanciate a new object from Root, and then add as many Matches to Should as you need, something similar like this:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
Root queryObject = new();
queryObject.query.#bool.should.Add(
new Should() {
match = new() {
level = "information"
}
});
queryObject.query.#bool.should.Add(
new Should() {
match = new() {
level = "error"
}
}
);
Console.WriteLine(JsonConvert.SerializeObject(queryObject));
// Outputs: {"size":1000,"query":{"bool":{"should":[{"match":{"level":"information"}},{"match":{"level":"error"}}],"filter":null,"minimum_should_match":0}}}
}
}
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Match
{
public string level { get; set; }
}
public class Should
{
public Match match { get; set; }
}
public class Timestamp
{
public DateTime gte { get; set; }
public DateTime lt { get; set; }
}
public class Range
{
[JsonProperty("#timestamp")]
public Timestamp Timestamp { get; set; }
}
public class Filter
{
public Range range { get; set; }
}
public class Bool
{
public List<Should> should { get; set; }
public List<Filter> filter { get; set; }
public int minimum_should_match { get; set; }
}
public class Query
{
public Bool #bool { get; set; }
}
public class Root
{
public Root()
{
size = 1000;
query = new();
query.#bool = new();
query.#bool.should = new();
// skipping the rest ...
}
public int size { get; set; }
public Query query { get; set; }
}
https://dotnetfiddle.net/YhFM1I

Related

Deserialize a json object with multiple nested objects /lists using JsonConvert

I a beginner in C# application development and have the following json data which I want to de-serialize:
{
"Parameters": [
{
"Info": {
"Id": 0,
"No": "0001"
},
"IntOptions": [
{
"Value": 0,
"ValInfo": "FIFO"
},
{
"Value": 1,
"ValInfo": "FIFO2"
}
],
"BubbleList": [
{
"Position": 0,
"SubBubbleList": [
{
"Value": 0,
"Message": "ListObj1"
},
{
"Value": 1,
"Message": "ListObj2"
}
]
}
]
}
]
}
I have the class structure defined as follows:
public class ParamList
{
private List<Param> _param = new List<Param>();
[JsonProperty("Parameters")]
public IReadOnlyCollection<Param> Param { get => _param.AsReadOnly(); }
}
public class Param
{
private List<IntOptions> _intOptions;
private List<BubbleList> _bubbleList;
[JsonProperty("Info")]
public Info? Info { get; }
[JsonProperty("IntOptions")]
public IReadOnlyCollection<IntOptions> IntOptionsVar { get => _intOptions.AsReadOnly(); }
[JsonProperty("BubbleList")]
public IReadOnlyCollection<BubbleList> BubbleListVar { get => _bubbleList.AsReadOnly(); }
}
public class Info
{
public Info(int id, string number)
{
Id = id;
Number = number;
}
[JsonProperty("Id")]
public int Id { get; private set; }
[JsonProperty("No")]
public string Number { get; private set; }
}
public class IntOptions
{
public IntOptions(int value, string valInfo)
{
Value = value;
ValInfo = valInfo;
}
[JsonProperty("Value")]
public int Value { get; private set; }
[JsonProperty("ValInfo")]
public string ValInfo { get; private set; }
}
public class BubbleList
{
private List<SubBubbleList>? _subBubbleList;
public BubbleList(int position)
{
Position = position;
}
[JsonProperty("Position")]
public int Position { get; private set; }
[JsonProperty("SubBubbleList")]
public IReadOnlyCollection<SubBubbleList> SubBubbleListVar { get => _subBubbleList.AsReadOnly(); }
}
public class SubBubbleList
{
public SubBubbleList(int value, string message)
{
Value = value;
Message = message;
}
[JsonProperty("Value")]
public int Value { get; private set; }
[JsonProperty("Message")]
public string Message { get; private set; }
}
I came up with the following de-serializing code which results in an empty list of Param:
try
{
ParamList paramList = JsonConvert.DeserializeObject<ParamList>(readJsonContent);
Console.WriteLine(paramList);
}
This gives me an empty list of Param.
I read a lot of articles explaining about de-serializing a json object, however, could not find one which would solve my use case. I need to understand what am I doing wrong here. I need to have a List<Param> which would then have Info, List<IntOptions>, & List<BubbleList> -> List<SubBubbleList>.
Is this achievable by just de-serializing the json data, or will I have to iterate through individual objects?
you have only getters in your classes. you need setters to assign values from json to c# objects
List<Parameter> Parameters = JsonConvert.DeserializeObject<ParamList>(json).Parameters;
classes
public class ParamList
{
public List<Parameter> Parameters { get; set; }
}
public class Parameter
{
public Info Info { get; set; }
public List<IntOption> IntOptions { get; set; }
public List<BubbleList> BubbleList { get; set; }
}
public class BubbleList
{
public int Position { get; set; }
public List<SubBubbleList> SubBubbleList { get; set; }
}
public class Info
{
public int Id { get; set; }
public string No { get; set; }
}
public class IntOption
{
public int Value { get; set; }
public string ValInfo { get; set; }
}
public class SubBubbleList
{
public int Value { get; set; }
public string Message { get; set; }
}
but if for some reasons you still need readonly you can change ALL your read only classes by moving json property name using this template
public class ParamList
{
[JsonProperty("Parameters")]
private List<Param> _param = new List<Param>();
public IReadOnlyCollection<Param> Param
{
get => _param.AsReadOnly();
}
}

Deserialize JSON in xamarin

How can i deserialize a local json file to an object?
I'm trying to deserialize a local json file in xamarin but it just doesn't work i read many guides and watched some tutorials but none of them helped and most of them give the same code i'm using right now
My code:
public test()
{
InitializeComponent();
List<Rootobject> ob = new List<Rootobject>();
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(test)).Assembly;
Stream stream = assembly.GetManifestResourceStream($"TunisiaPrayer.states.json");
string text = "";
using (var reader = new StreamReader(stream))
{
text = reader.ReadToEnd();
}
ob = JsonConvert.DeserializeObject<List<Rootobject>>(text);
//printing the json file to make sure it read it fully
//i get no error here
DisplayJson.Text = text;
//try catch to test if it was deserialized or not
try
{
//printing a property of ob in a label element to see if it works
DisplayData.Text = ob[2].Property1.data.gouvernorat.intituleAn;
}
catch (Exception ex)
{
DisplayData.Text = ex.Message;
}
}
RootObject Class:
namespace TunisiaPrayer.Models
{
public class Rootobject
{
public Class1 Property1 { get; set; }
}
public class Class1
{
public Data data { get; set; }
}
public class Data
{
public Gouvernorat gouvernorat { get; set; }
public Delegation[] delegation { get; set; }
}
public class Gouvernorat
{
public int id { get; set; }
public string intituleAr { get; set; }
public string intituleAn { get; set; }
}
public class Delegation
{
public int id { get; set; }
public string intituleAr { get; set; }
public string intituleAn { get; set; }
}
}
sample of states.json:
[{
"data": {
"gouvernorat": {
"id": 358,
"intituleAr": "اريانة",
"intituleAn": "Ariana"
},
"delegation": [{
"id": 631,
"intituleAr": "اريانة",
"intituleAn": "Ariana"
},
{
"id": 534,
"intituleAr": "التظامن",
"intituleAn": "Attadhamon"
},
{
"id": 532,
"intituleAr": "سكرة",
"intituleAn": "Soukra"
}
]
}
},
{
"data": {
"gouvernorat": {
"id": 362,
"intituleAr": "القصرين",
"intituleAn": "Kasserine"
},
"delegation": [{
"id": 579,
"intituleAr": "العيون",
"intituleAn": "El Ayoun"
},
{
"id": 576,
"intituleAr": "سبيبة",
"intituleAn": "Sbiba"
},
{
"id": 575,
"intituleAr": "سبيطلة",
"intituleAn": "Sbitla"
},
{
"id": 573,
"intituleAr": "تالة",
"intituleAn": "Tala"
}
]
}
}]
error: Object reference not set to an instance of an object
note that when i print ob.Count it gives me the correct length of the list but i can't access any data in it
you have to use Root[] , not just root, try this
var obj =JsonConvert.DeserializeObject< List<Root>>(text);
test
var displayData = obj[1].data.gouvernorat.intituleAn; // = Kasserine
classes
public class Root
{
public Data data { get; set; }
}
public class Data
{
public Gouvernorat gouvernorat { get; set; }
public List<Delegation> delegation { get; set; }
}
public class Gouvernorat
{
public int id { get; set; }
public string intituleAr { get; set; }
public string intituleAn { get; set; }
}
public class Delegation
{
public int id { get; set; }
public string intituleAr { get; set; }
public string intituleAn { get; set; }
}

How to return IEnumerable<T> as null

I am having the below ActivitiesDB.cs which is a DBEntity class.
public class ActivitiesDB
{
public IEnumerable<Activity> Activities { get; set; }
}
public class Activity
{
public Guid ActivityId { get ;set; }
public DateTime ActivityDateTime { get; set; }
public DateTime UpdatedDateTime { get; set; }
public IEnumerable<MetaData> MetaData { get; set; }
}
public class MetaData
{
public string Name { get; set; }
public string Value { get; set; }
}
sample data in DB(I am using CosmosDb in backend):
"Activities": [
{
"ActivityId": "4f436d11-7a61-4e7f-b0fb-0f0d5bb6be76",
"ActivityDateTime": "2021-04-30T09:35:35.32Z",
"UpdatedDateTime": "2021-05-03T07:45:21.5115588Z",
"Metadata": [
{
"Name": "name",
"Value": "value"
}
]
},
{
"ActivityId": "659e62c5-4408-42b4-8719-b8c577221d22",
"ActivityDateTime": "2021-04-30T09:35:35.32Z",
"UpdatedDateTime": "2021-05-03T07:45:21.5115588Z",
"Metadata": null
}
]
To display the data, I am having class DisplayActivtiesResponse.cs below:
public class DisplayActivtiesResponse
{
public IEnumerable<DisplayActivity> DisplayActivties{ get; set; }
}
public class DisplayActivity
{
public Guid ActivityId { get ;set; }
public DateTime ActivityDateTime { get; set; }
public DateTime UpdatedDateTime { get; set; }
public IEnumerable<MetaData> MetaData { get; set; }
}
public class MetaData
{
public string Name { get; set; }
public string Value { get; set; }
}
Below is the code to fetch the data from DB:
public async Task<DisplayActivtiesResponse> DisplayActivityAsync(Guid activityId)
{
var feedIterator = this.cosmosReviewRequestContainer.GetItemLinqQueryable<ActivitiesDB>()
.Where(q => q.Activities.Where(x => x.ActivityId == activityId)
.ToFeedIterator();
var requestModel = new ActivitiesDB();
while (feedIterator.HasMoreResults)
{
var items = await feedIterator.ReadNextAsync().ConfigureAwait(false);
requestModel = items.FirstOrDefault();
}
return new DisplayActivtiesResponse
{
DisplayActivties = mapper.Map<IEnumerable<DisplayActivity>>(requestModel);
};
}
MappingProfile.cs:
public class MappingProfile : Profile
{
public MappingProfile()
{
this.CreateMap<Activity, DisplayActivity>().ReverseMap();
}
}
Now, When I am fetching the data from db, I observed that if the metadata is null, I am getting empty array [] instead of null. I still dont know what i am missing from my end. Kindly help me on this.
Set AllowNullCollections to true when initializing:
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.AllowNullCollections = true;
});
or directly in the mapper configuration:
new MapperConfiguration(cfg =>
{
cfg.AllowNullCollections = true;
}

Change existing JSON message format into new with fields in C#?

We have to do some changes in existing JSON response and it requires to modify existing c# code too. Till now I've tried but don't get the exact idea about the formatting as it is new for me.
Can any one please check and suggest the changes in below code?
Existing JSON message:
"hotel_room_types": {
"QUEEN": {
"code": "QUEEN",
"bed_type": {
"standard": [
5
],
"custom": []
},
"extra_bed_type": {
"standard": [
5
],
"custom": []
},
"accessibility": "compliant_with_local_laws_for_disabled",
"room_smoking_policy": "non_smoking"
}
}
In above JSON message we have to replace the "bed_type" and "extra_bed_type" with "bed_configurations" and "extra_bed_configurations" in below newly provided format by client:
"hotel_room_types": {
"QUEEN": {
"code": "QUEEN",
"bed_configurations": [
[{
"type": "standard",
"code": 3,
"count": 1
}],
[{
"type": "standard",
"code": 1,
"count": 2
}]
],
"extra_bed_configurations": [
[{
"type": "standard",
"code": 900302,
"count": 1
},
{
"type": "custom",
"name": "Rollaway with wheel locks and adjustable height",
"count": 1
}]
],
"accessibility": "compliant_with_local_laws_for_disabled",
"room_smoking_policy": "non_smoking"
}
}
Existing C# code to generate the JSON response message format:
public class HotelRoomType
{
public string code { get; set; }
public string name { get; set; }
public string description { get; set; }
public List<Photo> photos { get; set; }
public Amenities room_amenities { get; set; }
public string room_size { get; set; }
public string room_size_units { get; set; }
public BedType bed_type { get; set; }
public BedType extra_bed_type { get; set; }
public RoomViewType room_view_type { get; set; }
public string accessibility { get; set; }
public MaxOccupancy max_occupancy { get; set; }
public string room_smoking_policy { get; set; }
}
Below is the code to fill the data in required fields of JSON message its inside a method which contains lines of code so I get it separately:
HotelRoomType hotelrmtype = new HotelRoomType();
hotelrmtype.bed_type = Common.GetStandardBedTypeMappingID(rm.BedType);
if (rm.NumOfBed > 1)
hotelrmtype.extra_bed_type = hotelrmtype.bed_type; //same as bed type
hotelrmtypeDict.Add(rm.Code, hotelrmtype); //Binding Data into Dictionary.
GetStandardBedTypeMappingID() contains :
public static CRS.TripConnect.BedType GetStandardBedTypeMappingID(short code)
{
CRS.TripConnect.BedType tripConnectBedType = new CRS.TripConnect.BedType();
List<int> standardBedTypes = new List<int>();
List<object> customBedTypes = new List<object>();
tripConnectBedType.standard = standardBedTypes;
tripConnectBedType.custom = customBedTypes; //These is blank.
short id = 0;
switch (code)
{
case 10:
id = 3;
break;
case 20: // 20 Queen Q 5
id = 5;
break;
case 30: // 30 Double D 1
id = 1;
break;
case 40: // 40 Twin T 8
id = 8;
break;
}
standardBedTypes.Add(id);
return tripConnectBedType;
}
Update: With the help of #Sam Answer below I have modified the code:
public class HotelRoomType
{
//Added following properties
public List<List<Bed_Configurations>> bed_configurations { get; set; }
public List<List<Extra_Bed_Configurations>> extra_bed_configurations { get; set; }
}
Created two new classes as:
public class Bed_Configurations
{
public string type { get; set; }
public int code { get; set; }
public int count { get; set; }
}
public class Extra_Bed_Configurations
{
public string type { get; set; }
public int code { get; set; }
public int count { get; set; }
public string name { get; set; }
}
Now the question is: How to fill these two list?
I'm trying to achieve this like below but it is giving me conversion error.
Bed_Configurations bdConfig = new Bed_Configurations();
bdConfig.type = "Standard";
bdConfig.code = Common.GetStandardBedTypeMappingIDnew(rm.BedType);
bdConfig.count = rm.NumOfBed;
hotelrmtype.bed_configurations.Add(bdConfig);
Error Message:
Please Advise the changes in the above code so as to get the required JSON message. Appreciate your help!
public class RootClass
{
public HotelRoomType hotel_room_types { get; set; }
}
public class HotelRoomType
{
public BedModelAndDetails QUEEN { get;set; }
}
public class BedModelAndDetails
{
public string accessibility { get; set; }
public string room_smoking_policy { get; set; }
public string code { get; set; }
//public BedType bed_type { get; set; }
public object bed_type { get; set; }
//public BedType extra_bed_type { get; set; }
public object extra_bed_type { get; set; }
public List<List<BedConfiguration>> bed_configurations { get; set; }
public List<List<BedConfiguration>> extra_bed_configurations { get; set; }
}
public class BedType
{
public List<int> standard { get; set; }
public List<int> custom { get; set; }
}
public class BedConfiguration
{
public string type { get; set; }
public int code { get; set; }
public int count { get; set; }
}
[TestMethod]
public void ReplaceJson()
{
var inputJson1 = "{\"hotel_room_types\": {\"QUEEN\": {\"code\": \"QUEEN\", \"bed_type\": {\"standard\": [5],\"custom\": [] }, \"extra_bed_type\": { \"standard\": [5], \"custom\": [] },\"accessibility\": \"compliant_with_local_laws_for_disabled\", \"room_smoking_policy\": \"non_smoking\" } " +"}}";
var input1 = JsonConvert.DeserializeObject<RootClass>(inputJson1, new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
var inputJson2 = "{\"hotel_room_types\": {\"QUEEN\": {\"code\": \"QUEEN\",\"bed_configurations\": [[{\"type\": \"standard\",\"code\": 3,\"count\": 1}],[{\"type\": \"standard\",\"code\": 1,\"count\": 2}]],\"extra_bed_configurations\": [[{\"type\": \"standard\",\"code\": 900302,\"count\": 1},{\"type\": \"custom\",\"name\": \"Rollaway with wheel locks and adjustable height\",\"count\": 1}]],\"accessibility\": \"compliant_with_local_laws_for_disabled\",\"room_smoking_policy\": \"non_smoking\"} }}";
var input2 = JsonConvert.DeserializeObject<RootClass>(inputJson2);
//var finalInput = new RootClass();
//finalInput.hotel_room_types = inputJson1
//input1.hotel_room_types.QUEEN.bed_configurations = input2.hotel_room_types.QUEEN.bed_configurations;
//input1.hotel_room_types.QUEEN.extra_bed_configurations = input2.hotel_room_types.QUEEN.extra_bed_configurations;
input1.hotel_room_types.QUEEN.bed_type = input2.hotel_room_types.QUEEN.bed_configurations;
input1.hotel_room_types.QUEEN.extra_bed_type = input2.hotel_room_types.QUEEN.extra_bed_configurations;
}
Does this help?

JObject ToObject not Mapping

I have a part of some JSon that I am trying to map to a C# object. The rest of the JSon maps correctly to the object but only this part does not map anything and the objects values are null.
Here is the code that I am calling
var data = JObject.Parse(model.Data);
var dataModel = data.ToObject<MyModel>();
In MyModel I have this code
public class P
{
public string R { get; set; }
public IList<SavedSearch> SavedSearches { get; set; }
public class SavedSearch
{
public string A { get; set; }
public string B { get; set; }
public string CD { get; set; }
}
}
The corresponding JSon snippet is
"p": [
{
"r": "something",
"savedSearches": [
{
"saved-search": {
"#a": "blah",
"#b": "blahblah",
"#c-d": "blahblahblah"
}
}
]
}
]
R is correctly populated with the correct value, but A, B and CD are not. How must I change my C# model to fix this?
Your need to add an extra level of indirection for "saved-search", and also inform the serializer how to map the JSON property names to c# property names, since the JSON property names contain invalid characters (e.g. #) for c# properties. Thus:
[DataContract]
public class P
{
[DataMember(Name="r")]
public string R { get; set; }
[DataMember(Name="savedSearches")]
public IList<SavedSearch> SavedSearches { get; set; }
[DataContract]
public class SavedSearch
{
[DataMember(Name="saved-search")]
public SavedSearchItem SavedSearchItem { get; set; }
}
[DataContract]
public class SavedSearchItem
{
[DataMember(Name="#a")]
public string A { get; set; }
[DataMember(Name = "#b")]
public string B { get; set; }
[DataMember(Name = "#c-d")]
public string CD { get; set; }
}
}
And
public class MyModel
{
public List<P> p { get; set; }
}
When used as follows:
string json = #"
{""p"": [
{
""r"": ""something"",
""savedSearches"": [
{
""saved-search"": {
""#a"": ""blah"",
""#b"": ""blahblah"",
""#c-d"": ""blahblahblah""
}
}
]
}
]
}
";
var data = JObject.Parse(json);
var dataModel = data.ToObject<MyModel>();
Debug.WriteLine(JsonConvert.SerializeObject(dataModel, Formatting.Indented));
Produce
{
"p": [
{
"r": "something",
"savedSearches": [
{
"saved-search": {
"#a": "blah",
"#b": "blahblah",
"#c-d": "blahblahblah"
}
}
]
}
]
}
Incidentally, since you will be remapping the property names anyway, I'd suggest using more descriptive names in c# than R, A, B and CD.

Categories

Resources