handle empty Json Array from object - c#

I have a json object that returns two empty arrays
"subQuestions": [] and "answers": []
I have created classes for the object, but I cannot get it to work,
this is what I have so far.
Object
"questions": [
{
"questionId": "1",
"question": "Ipsum",
"helpText": null,
"questionType": "MultipleChoice",
"answerChoices": [
{
"answerChoiceId": "b2b-2.01-answer1",
"value": "Lorem",
"subQuestions": []
}
],
"answers": []
}
Classes
public class AnswerChoice
{
public string answerChoiceId { get; set; }
public string value { get; set; }
public List<object> subQuestions { get; set; }
}
public class Question
{
public string questionId { get; set; }
public string question { get; set; }
public object helpText { get; set; }
public string questionType { get; set; }
public List<AnswerChoice> answerChoices { get; set; }
public List<object> answers { get; set; }
}
public class ObjectRoot
{
public string productId { get; set; }
public List<Question> questions { get; set; }
}
var jsonBody = new ObjectRoot()
{
productId = productId,
questions = new[]
{
new Question() {
questionId = "b2b-2.01",
question ="Vad är syftet med ert engagemang hos oss?",
helpText = null,
questionType = "MultiChoise",
answerChoices = new []{
new AnswerChoice{
answerChoiceId = "",
value = "",
**HERE is what it gets tricky for me**
}
}
}
}
};
The tricky part for me is after value = "", and the subQuestion object needs to be added, have tried multiple ways but no luck.

In your classes all collections is List not array. So to make it work you need to call ToList extension method. And for empty collections just call List constructor
var jsonBody = new ObjectRoot()
{
productId = "productId",
questions = new[]
{
new Question() {
questionId = "b2b-2.01",
question ="Vad är syftet med ert engagemang hos oss?",
helpText = null,
questionType = "MultiChoise",
answerChoices = new []{
new AnswerChoice{
answerChoiceId = "",
value = "",
subQuestions = new List<object>() // empty collection
}
}.ToList(),
answers = new List<object>()
}
}.ToList()
};

Related

Fluent Assertions between two collection class

I have a class with collection class inside
public class SearchResult {
public int Id { get; set; }
public int Total { get; set; }
public IEnumerable<Book> Books { get; set; }
}
public class Book {
public int BookId { get; set; }
public string BookName { get; set; }
public string Publisher { get; set; }
public string ISBNCode { get; set; }
public IList<catagory> Catagories { get; set; }
}
I have a question , if I create the other object , with same structure of SearchResult and I want to copy SearchResult to SearchResultClone, which inside Books only copy BookId and BookName remain is empty.
Just like below
{
"Id": 0,
"Total": 3,
"Books": [
{
"BookId": 1,
"BookName": "Book A",
"Publisher": "",
"ISBNCode": "",
"Catagories": []
},
{
"BookId": 2,
"BookName": "Book B",
"Publisher": "",
"ISBNCode": "",
"Catagories": []
},
{
"BookId": 3,
"BookName": "Book C",
"Publisher": "",
"ISBNCode": "",
"Catagories": []
}
]
}
Event the original result have value of Publisher, ISBNCode ..etc
How to do it in LINQ ?
My second question is , if I want to make a fluent assertions as above object
var result = await sut.search(query);
result.Should().BeEquivalentTo ({the SearchResultClone })
How to write this fluent assertion ?
You need to create new instances of the classes based on the old instances:
var ans = result.Select(sr => new SearchResult {
Id = sr.Id,
Total = sr.Total,
Books = sr.Books.Select(b => new Book { BookId = b.BookId, BookName = b.BookName }).ToList()
}).ToList();
result.Should().BeEquivalentTo ({the SearchResultClone })
How to write this fluent assertion ?
If your expectation (the object you pass into BeEquivalentTo) is of the type SearchResult, then FA will try to compare the empty values of ISBN to the same property on the sut. You can solve that by doing something like:
sut.Should().BeEquivalentTo(new
{
Id = "some value",
Total = 123,
Books = new[]
{
new
{
BookId = 123,
BookName = "some book"
}
}
});

Deserialize JSON array with unknown keys inside JSON object to a generic property - C#

Finding the right title for this problem was kinda hard so I'll try to explain the problem a bit better below.
I am making a call to an API which returns the following JSON object:
{{
"id": "jsonrpc",
"jsonrpc": "2.0",
"result": {
"result": [
{
"AccountId": 285929,
"Flags": [
"Managed_Obsolete"
],
"PartnerId": 73560,
"Settings": [
{
"AN": "company_1"
},
{
"CD": "1435323320"
},
{
"ED": "2147483647"
},
{
"OS": "Windows Server 2012 R2 Standard Edition (9600), 64-bit"
},
{
"OT": "2"
},
{
"T3": "1085792125772"
},
{
"US": "958222150780"
},
{
"YS": "100"
}
]
},
{
"AccountId": 610474,
"Flags": null,
"PartnerId": 249262,
"Settings": [
{
"AN": "company_2"
},
{
"CD": "1522143635"
},
{
"ED": "2147483647"
},
{
"OS": "Windows 7 Professional Service Pack 1 (7601), 64-bit"
},
{
"OT": "2"
},
{
"T3": "598346102236"
},
{
"US": "758149148249"
},
{
"YS": "100"
}
]
},
],
"totalStatistics": null
},
}}
In above result I listed only the first 2 accounts (total of 80+ accounts normally).
Deserializing the object works fine, I am putting the JSON object fields inside my C# model (list).
The problem however is that I can't get the (inner) Settings array properly in my model. The settings array keys are unknown, I define these keys when I call the API:
JObject requestObject = new JObject();
requestObject.Add(new JProperty("id", "jsonrpc"));
requestObject.Add(new JProperty("jsonrpc", "2.0"));
requestObject.Add(new JProperty("method", "myMethod"));
requestObject.Add(new JProperty("visa", someID));
requestObject.Add(new JProperty("params",
new JObject(
new JProperty("query", new JObject(
new JProperty("PartnerId", partnerId),
new JProperty("StartRecordNumber", 0),
new JProperty("RecordsCount", 9999999),
new JProperty("Columns", new JArray("AR", "AN", "US", "T3", "OT", "OS", "YS"))
)),
new JProperty("timeslice", unixDate),
new JProperty("totalStatistics", "*")
))
);
In above call I define the keys for the Settings array, this could however also be just one key or more. For this reason I want to make my Settings property in my C# model generic (I don't want to list all the possible key names because this are over 100 keys).
What I had so far:
List<EnumerateAccountHistoryStatisticsResult> resultList = new List<EnumerateAccountHistoryStatisticsResult>();
var result = JsonConvert.DeserializeObject<JObject>(streamreader.ReadToEnd());
dynamic innerResult = result["result"]["result"];
foreach (var obj in innerResult)
{
resultList.Add(
new EnumerateAccountHistoryStatisticsResult
{
AccountId = obj.AccountId,
Flags = obj.Flags.ToObject<IEnumerable<string>>(),
PartnerId = obj.PartnerId,
Settings = obj.Settings.ToObject<List<ColumnSettingsResult>>(),
});
}
The EnumerateAccountHistoryStatisticsResult Model:
public class EnumerateAccountHistoryStatisticsResult
{
public int AccountId { get; set; }
public IEnumerable<string> Flags { get; set; }
public int PartnerId { get; set; }
public List<ColumnSettingsResult> Settings { get; set; }
}
The ColumnSettingsResult model:
public class ColumnSettingsResult
{
public string AR { get; set; }
public string AN { get; set; }
public string US { get; set; }
public string T3 { get; set; }
public string OT { get; set; }
public string OS { get; set; }
public string YS { get; set; }
// and list all other columns...
}
With above models I would need to list all the possible columns which are over 100 properties, besides that the result of the Settings list is not logical because I get all the property values but for each different key I get null values:
The ColumnSettingsResult model should more be something like:
public class ColumnSettingsResult
{
public string ColumnName { get; set; }
public string ColumnValue { get; set; }
}
I cant get the key and value inside these two properties though without defining the key name inside the model..
I already tried several things without result (links below as reference).
Anyone that can get me in the right direction?
C# deserialize Json unknown keys
Convert JObject into Dictionary<string, object>. Is it possible?
Convert Newtonsoft.Json.Linq.JArray to a list of specific object type
Try making Settings of type Dictionary<string,string> (or List<KeyValuePair<string,string>> if Dictionary doesn't give you what you want.
public class MyJsonObject
{
public string id { get; set; }
public string jsonrpc { get; set; }
public Result result { get; set; }
public class Result2
{
public int AccountId { get; set; }
public List<string> Flags { get; set; }
public int PartnerId { get; set; }
public Dictionary<string,string> Settings { get; set; } //or List<KeyValuePair<string,string>>
}
public class Result
{
public List<Result2> result { get; set; }
public object totalStatistics { get; set; }
}
}
Then JsonConvert.DerserializeObject<MyJsonObject>(jsonString);

Pass Object Array into Request Body

I have an object defined as follows.
public class ILT
{
public items items;
public options options;
}
public class items
{
public string course_code { get; set; }
public string session_code { get; set; }
public string date_name { get; set; }
public string date { get; set; }
public string time_start { get; set; }
public string time_end { get; set; }
public string location_name { get; set; }
public string location_address { get; set; }
public string location_country { get; set; }
public items() { }
public items(string course_code, string session_code, string date_name,
string date, string time_start, string time_end, string location_name,
string location_address, string location_country)
{
this.course_code = course_code;
this.session_code = session_code;
this.date_name = date_name;
this.date = date;
this.time_start = time_start;
this.time_end = time_end;
this.location_name = location_name;
this.location_address = location_address;
this.location_country = location_country;
}
}
I'm trying to pass the object into a RestfulAPI request body. The "items" attribute is supposed to be an array of objects.
The JSon should be formatted as follows:
{
"items": [
{
"course_id": 6,
"session_code": "my session code",
"session_name": "my session name",
"session_maximum_enrollments": 20,
"session_last_subscription_date": "2018-10-27",
"completion_type": "Evaluation",
"score_base": 100,
"date_name": "my date name",
"date": "2018-10-28",
"timezone": "America/New_York",
"time_start": "08:00:00",
"time_end": "12:00:00",
"location_name": "my location name",
"location_address": "10850 W. Park Place Suite 600, Milwaukee, WI 53225",
"location_country": "UNITED STATES OF AMERICA"
}
],
"options": {
"update_session_info": true
}
}
I'm having difficulty getting the items into an array. I'm trying to initialize the object into the request body as follows:
public bool CreateILT()
{
if (String.IsNullOrEmpty(Token))
Token = request.GetToken();
ILT classroom = new ILT
{
items = new items[0]
(
course_code = "APS_CLASSROOM",
session_code = "APS_CLASSROOM",
date_name = "August 27, 2018",
date = "2018-10-27",
time_start = "08:00:00",
time_end = "17:00:00",
location_name = "Crisis Prevention Institute",
location_address = "10850 W. Park Place Suite 600, Milwaukee, WI 53225",
location_country = "UNITED STATES OF AMERICA"
),
options = new options
{
update_session_info = true
}
};
dynamic response = request.Request_POST("/learn/v1/ilt/session/batch", Token, classroom);
if (response.data.success.ToString() == "True")
success = true;
return success;
}
Am I able to initialize an object array like this? I'm getting errors of various types when tweaking around. The above code errors out on each of the object's member's saying it does not exist in the current context.
Your class variable decleration is wrong. It stores object, not array/list of objects. And I could not see your options class. Do you have it right?
It should be declared as follows:
public class ILT
{
public List<items> items;
public options options;
}
And you should initialize it as follows:
ILT classroom = new ILT
{
items = new List<items> {
new item(
course_code = "APS_CLASSROOM",
session_code = "APS_CLASSROOM",
date_name = "August 27, 2018",
date = "2018-10-27",
time_start = "08:00:00",
time_end = "17:00:00",
location_name = "Crisis Prevention Institute",
location_address = "10850 W. Park Place Suite 600, Milwaukee, WI 53225",
location_country = "UNITED STATES OF AMERICA")
},
options = new options
{
update_session_info = true
}
};

How to receive JSON data in Dictionary using FromData in Web api?

Below is JSON example which client will send to my API named as 'GetQuestion'
{
"lstQuestions": [{
"QuestionCategory": 1,
"QuestionText": "what is m in mvc",
"OptionA": "model",
"OptionB": "view",
"OptionC": "controller",
"OptionD": "razor",
"CorrectOption": "A"
},
{
"QuestionCategory": 2,
"QuestionText": "How are you",
"OptionA": "fine",
"OptionB": "not fine",
"OptionC": "ok",
"OptionD": "not ok",
"CorrectOption": "A"
}],
"Status" : 1
}
Below is my controller API code:
public class QuestionDetails
{
public List<Questions> lstQuestions { get; set; }
public int Status { get; set; }
}
public class Questions
{
public string QuestionCategory { get; set; }
public string QuestionText { get; set; }
public string OptionA { get; set; }
public string OptionB { get; set; }
public string OptionC { get; set; }
public string OptionD { get; set; }
public string CorrectOption { get; set; }
}
[Route("GetQuestions")]
[HttpPost]
public HttpResponseMessage SendQuestionDetails([FromBody] QuestionDetails UserDetailInput)
{
HttpResponseMessage mesage = Request.CreateResponse(HttpStatusCode.OK, "Demo"); ;
if (ModelState.IsValid)
{
//in progress
}
return mesage;
}
What I want to do is how to create a class with Dictionary and pass as parameter, I don't want to use List because its heavy and Dictionary is much faster than List.
For example:
public class QuestionDetails
{
public Dictionary<string, Questions> lstQuestions { get; set; }
public int Status { get; set; }
}
public HttpResponseMessage SendQuestionDetails([FromBody] Dictionary<string, QuestionDetails> UserDetailInput)
{
HttpResponseMessage mesage = Request.CreateResponse(HttpStatusCode.OK, "Demo"); ;
if (ModelState.IsValid)
{
//in progress
}
return mesage;
}
Don't know what are you talking about with Dictionary is much faster than List but you just need to send the JSON as
{
"A": {
"lstQuestions": {
"A": {
"QuestionCategory": 1,
"QuestionText": "what is m in mvc",
"OptionA": "model",
"OptionB": "view",
"OptionC": "controller",
"OptionD": "razor",
"CorrectOption": "A"
},
"V": {
"QuestionCategory": 2,
"QuestionText": "How are you",
"OptionA": "fine",
"OptionB": "not fine",
"OptionC": "ok",
"OptionD": "not ok",
"CorrectOption": "A"
}
},
"Status": 1
}
}
Hope below code will clear your query.
public HttpResponseMessage SendQuestionDetails([FromBody] Dictionary<string, QuestionDetails> UserDetailInput)
{
List<Questions> list = new List<Questions> { };
list.Add(new Questions
{
CorrectOption = "CorrectOption1",
OptionA = "OptionA1",
OptionB = "OptionB1",
OptionC = "OptionC1",
OptionD = "OptionD1",
QuestionCategory = "QuestionCategory1",
QuestionText = "QuestionText1"
});
list.Add(new Questions
{
CorrectOption = "CorrectOption2",
OptionA = "OptionA2",
OptionB = "OptionB2",
OptionC = "OptionC2",
OptionD = "OptionD2",
QuestionCategory = "QuestionCategory2",
QuestionText = "QuestionText2"
});
Dictionary<QuestionDetails, int> dictionary = new Dictionary<QuestionDetails, int> { };
QuestionDetails detail = new QuestionDetails { lstQuestions = list, Status = 1 };
HttpResponseMessage mesage = Request.CreateResponse(HttpStatusCode.OK, detail);
return mesage;
return mesage;
}

Use Linq or C# to parse Json

I am getting familiar with C# and Linq and appreciate any help. It should be easy for someone who works with it. I have a Json object that returns contact information. I also have a list of ids. I need to compare the list to the Json object and wherever the value in the list matches the userclientcode in the Json object, I need to extract the following information (only for the matches):
clienttaxonomy (if not empty)
fullname (if not empty)
[0]contactdata ( -> email if not null or empty)
[1]contactdata (-> address if not null or empty)
[2]contactdata (-> phone number if not null or empty)
First List
var fileContactIds = new List<string> { "5678765", "2135123", "12341234", "341234123", "12341234123", "2341234123", "341234123", "123412341", "13342354",
"12342341", "123412322", "163341234", "2345234115", "8967896", "75626234 };
JSON object returned with:
return JsonConvert.DeserializeObject<RelatedContacts>(json)?.list;
This is the Json object:
[![Json object][1]][1]
This is the Json string (unescaped):
{
"type": "com.kurtosys.api.userprofile.domain.RelatedContactList",
"list": [{
"objectlistid": 5678765,
"objectlisttypeid": 4567876,
"objectlistname": "ALL.National",
"clienttaxonomyid": 765677,
"clienttaxonomy": "National Wholesaler",
"order": 1,
"contacts": [{
"personid": 7654345678,
"fullname": "Person Jallo",
"userid": 876567,
"userclientcode": "341234123",
"contactdetails": [{
"contactid": 8765567,
"contacttypeid": 4565,
"contactdata": "person.contact#site.com"
}, {
"contactid": 876545678,
"contacttypeid": 4565,
"contactdata": "Baltimore,MD,21209,United States"
}, {
"contactid": 87654567,
"contacttypeid": 4584,
"contactdata": "410-413-2640"
}]
}]
}, {
"objectlistid": 765678,
"objectlisttypeid": 40400461,
"objectlistname": "RM.Internal",
"clienttaxonomyid": 7567898,
"clienttaxonomy": "Internal Regional Wholesaler",
"order": 2,
"contacts": [{
"personid": 56789876,
"fullname": "Jackson Man",
"userid": 876567,
"userclientcode": "1012275",
"contactdetails": [{
"contactid": 309598309,
"contacttypeid": 76546,
"contactdata": "mister.jackson##site.com.com"
}, {
"contactid": 876567,
"contacttypeid": 4581,
"contactdata": "Baltimore,MD,21209,United States"
}, {
"contactid": 876567,
"contacttypeid": 2342,
"contactdata": "123-413-2604"
}]
}]
}, {
"objectlistid": 309571364,
"objectlisttypeid": 40400461,
"objectlistname": "RM.External",
"clienttaxonomyid": 309580710,
"clienttaxonomy": "External Regional Wholesaler",
"order": 3,
"contacts": [{
"personid": 302736188,
"fullname": "Phal Sumi",
"userid": 303826019,
"userclientcode": "163341234",
"contactdetails": [{
"contactid": 309598253,
"contacttypeid": 2342,
"contactdata": "misters.emailas#site.com"
}, {
"contactid": 309611930,
"contacttypeid": 2342,
"contactdata": "Baltimore,MD,21209,United States"
}, {
"contactid": 34234132,
"contacttypeid": 3422,
"contactdata": "342-803-1793"
}]
}]
}]
}
How do I
1] Select using Linq and Lambdas and put in a list fullname, email, address etc from the deserialized object ?
2]compare with first list and only transfer those items where the userclientcode == the number in list A.
I have tried:
var query5 = relatedContact.Where(s => s.objectlistid == Convert.ToInt64(contacts.Select(t => t.id)))
var selected = relatedContact.Where(p => p.contacts
.Any(a => fileContactIds.Contains(p.contacts))
.ToList();
var query2 = relatedContact.Where(s => s.objectlistid == Convert.ToInt64(contacts.Select(t => t.id)))
.Select(s => new
{
Description = s.clienttaxonomy,
Fullname = s.contacts[0].fullname,
Email = s.contacts[0].contactdetails[0].contactdata,
Address = s.contacts[0].contactdetails[1].contactdata,
PhoneNumber = s.contacts[0].contactdetails[2].contactdata
});
But don't really know what I'm doing it seems. Any suggestions on how to get the required sections ? I think part of the reason is that the contactdata is a list.
Thanks all
You can create a classes for the desearlization of JSON Object like this
public class Rootobject
{
public string type { get; set; }
public List[] list { get; set; }
}
public class List
{
public int objectlistid { get; set; }
public int objectlisttypeid { get; set; }
public string objectlistname { get; set; }
public int clienttaxonomyid { get; set; }
public string clienttaxonomy { get; set; }
public int order { get; set; }
public Contact[] contacts { get; set; }
}
public class Contact
{
public long personid { get; set; }
public string fullname { get; set; }
public int userid { get; set; }
public string userclientcode { get; set; }
public Contactdetail[] contactdetails { get; set; }
}
public class Contactdetail
{
public int contactid { get; set; }
public int contacttypeid { get; set; }
public string contactdata { get; set; }
}
And then to extract the selected information we can also create a another class like
public class ExtractedInfo
{
public string ocClientTaxonomy { get; set; }
public string ocFullName { get; set; }
public CTDetails ocContactDetails { get; set; }
}
public class CTDetails
{
public string ocCTAddress { get; set; }
public string ocCTEmail { get; set; }
public string ocCTPhoneNumber { get; set; }
}
Now we have to find all the data from JSON
var fileContactIds = new List<string> { "5678765", "2135123", "12341234", "341234123", "12341234123", "2341234123", "341234123", "123412341", "13342354", "12342341", "123412322", "163341234", "2345234115", "8967896", "75626234" };
//Read JSON from txt file. You can do it by your way
string myjson = File.ReadAllText("Some.txt");
string ctphno, ctadd, ctemail, cltax, ctfullname;
List<ExtractedInfo> ei = new List<ExtractedInfo>();
CTDetails ctdtl = new CTDetails();
ExtractedInfo eiex = new ExtractedInfo();
//Deserialize the JSON string to Object.
Rootobject AllData = JsonConvert.DeserializeObject<Rootobject>(myjson);
//Finding all data in List Class
foreach(List lst in AllData.list)
{
cltax = lst.clienttaxonomy; // you can directly put eiex.ocClientTaxonomy = lst.clienttaxonomy;
foreach(Contact ct in lst.contacts)
{
//To check if value in the list matches the objectlistid in the Json object
if(fileContactIds.Contains(lst.objectlistid.ToString()))
{
ctfullname = ct.fullname; // you can directly put eiex.ocFullName = ct.fullname;
foreach(Contactdetail ctd in ct.contactdetails)
{
//Here we are trying to find the Match for Email.
if(Regex.IsMatch(ctd.contactdata, #"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", RegexOptions.IgnoreCase))
{
ctemail = ctd.contactdata;
ctdtl.ocCTEmail = ctemail;
}
//Here We trying to find the match for Phone Number.
else if(Regex.IsMatch(ctd.contactdata, #"\(?\d{3}\)?-? *\d{3}-? *-?\d{4}", RegexOptions.IgnoreCase))
{
ctphno = ctd.contactdata;
ctdtl.ocCTPhoneNumber = ctphno;
}
//If NOthing matches than it might be address (Assumed)
else
{
ctadd = ctd.contactdata;
ctdtl.ocCTAddress = ctadd;
}
}
eiex.ocFullName = ctfullname;
}
}
eiex.ocClientTaxonomy = cltax;
eiex.ocContactDetails = ctdtl;
ei.Add(eiex);
}
Hope this helps and fit in your requirements.

Categories