Fluent Assertions between two collection class - c#

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"
}
}
});

Related

Foreach in List and return new empty list in condition

I have create two class as below :
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; } = string.Empty;
public string ISBNCode { get; set; } = string.Empty;
public DateTime PublishDate { get; set; } = DateTime.MinValue;
}
Initial Data as below:
{
"Id": 0,
"Total": 2,
"Books": [
{
"BookId": 1,
"BookName": "Book A",
"Publisher": "Peter",
"ISBNCode": "ISBN0001",
"PublishDate": "2022-03-03T10:19:23.9038822+00:00"
},
{
"BookId": 2,
"BookName": "Book C",
"Publisher": "Kate",
"ISBNCode": "ISBN0003",
"PublishDate": "2022-02-26T10:19:23.9039301+00:00"
}
]
}
I want to make the result if PublishDate > 2022-03-01 and then only keep BookId and PublishDate remain property need to empty, the expected output will be
{
"Id": 0,
"Total": 2,
"Books": [
{
"BookId": 1,
"BookName": "",
"Publisher": "",
"ISBNCode": "",
"PublishDate": "2022-03-03T10:19:23.9038822+00:00"
},
{
"BookId": 2,
"BookName": "Book C",
"Publisher": "Kate",
"ISBNCode": "ISBN0003",
"PublishDate": "2022-02-26T10:19:23.9039301+00:00"
}
]
}
For book class will have many properties and sublist in future, so I would like make a new book, just like this
searchResult.Books.Where(dt => dt.PublishDate > '2022-3-1').ToList().ForEach(
b => new Book {
BookId = b.BookId,
PublishDate = b.PublishDate
});
But I have no idea inside, can anyone advise about this ?
Thank you
I think it's a little strange to clear properties, maybe I don't get it completely, but..
You could create a filter, which will be used with Select:
private static Book ClearPropertiesAfterDate(Book book, DateTime date)
{
if(book.PublishDate > date)
return new Book { BookId = b.BookId, PublishDate = b.PublishDate }
else
return book;
}
// use select to transform each item.
// The ClearPropertiesAfterDate returns a new book (with only the id
// and publishDate when it was released after a certain date
// otherwise it returns the original book.
var booksFiltered = searchResult.Books.Select(dt =>
ClearPropertiesAfterDate(dt, '2022-3-1')).ToList();
'2022-3-1' should be a DateTime? Just should how you could transform items, didn't tested it in visualstudio or fiddle thingy

handle empty Json Array from object

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()
};

json format output from JavaScriptSerializer

var singleItems = new List<Products>();
singleItems.Add(new Products() { product_id = 1, title = "Bryon Hetrick", price = 50 });
singleItems.Add(new Products() { product_id = 2, title = "Nicole Wilcox", price = 20 });
var serializer = new JavaScriptSerializer();
var serializedResult = serializer.Serialize(serializer);
From above example code i am getting Json output like bellow.
[{"product_id":1,"title":"Bryon Hetrick","price":50},
{"product_id":2,"title":"Nicole Wilcox","price":20}]
But my Json need one more value called- "config" also i need whole data formatted exactly like bellow. How to edit my c# code to achieve that value?
{ "products":[{"product_id":"B071H6TBM5","title":"New Iphone 5S","price":"23.45"},{"product_id":"B071DM968J","title":"Iphone 4 old","price":"23.45"}],"config":{"token":"","Site":"Us","Mode":"ListMyItem"}}
You could make a Config class with the properties you require and then a composite class with Prodcuts and Config, i.e. ProductConfig:
public class Products
{
public string product_id { get; set; }
public string title { get; set; }
public string price { get; set; }
}
public class Config
{
public string token { get; set; }
public string site { get; set; }
public string mode { get; set; }
}
public class ProductConfig
{
public List<Products> Products { get; set; }
public Config Config { get; set; }
}
You can then create/populate the ProductConfig class with the new properties.
public string SerializeProductConfig()
{
ProductConfig pc = new ProductConfig();
pc.Config = new Config { token = "DDTest", site = "US", mode = "Test Mode" };
pc.Products = new List<Products>();
pc.Products.Add(new Products() { product_id = "1", title = "Bryon Hetrick", price = "50" });
pc.Products.Add(new Products() { product_id = "2", title = "Nicole Wilcox", price = "20" });
var serializer = new JavaScriptSerializer();
return serializer.Serialize(pc);
}
and serialize the ProductConfig object using the JavaScript serializer or NewtonSoft which will give you the following JSON
{ // ProductConfig
"Products": [
{
"product_id": "1",
"title": "Bryon Hetrick",
"price": "50"
},
{
"product_id": "2",
"title": "Nicole Wilcox",
"price": "20"
}
],
"config": {
"token": "DDTest",
"site": "US",
"mode": "Test Mode"
}
}

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.

LINQ grouping in object

I have two classes
public class MyObjects{
public bool Active {get; set;}
public List<OtherObject> OtherObjects {get; set;}
}
public class OtherObject {
public int Id {get; set;}
public bool Enabled {get; set;}
public string Address {get; set;}
public string Name {get; set;}
}
My current result is
MyObject { Active = true; },
OtherObjects: [OtherObject: { Id: 1, Name: 'First'},
OtherObject{Id: 2, Name: 'First'},
OtherObject{Id: 3, Name: 'Second'}];
I want to group them by Name so I would still have Active property and those OtherObjects inside would be grouped by OtherObject Name property. Is it possible to do so only using LINQ?
EDIT:
Final result should be json, that I will use in angular, so it should be something like this:
{
""Active"": true,
""OtherObjects"": [
{
""ObjectName"": ""Second"",
""ObjectOtherProperties"": [
{
""Id"": 1,
""Enabled"": false
},
{
""Id"": 2,
""Enabled"": true
}
],
""ObjectName"": ""Second"",
""ObjectOtherProperties"": [
{
""Id"": 1,
""Enabled"": false
}
],
]
}
}
Any suggestions how to achieve this? Maybe I must make other classes and somehow map them by grouping?
This is how I would do it, keeping it simple:
// 1. Add OtherObjectsDictionary
// 2. Block OtherObjects in the json serialization
public class MyObjects
{
public bool Active { get; set; }
[Newtonsoft.Json.JsonIgnore]
public List<OtherObject> OtherObjects { get; set; }
public Dictionary<string, List<OtherObject>> OtherObjectsDictionary { get; set; }
}
// 3. Block Name in the json serialization
public class OtherObject
{
public int Id { get; set; }
public bool Enabled { get; set; }
public string Address { get; set; }
[Newtonsoft.Json.JsonIgnore]
public string Name { get; set; }
}
// 4. Linq queries to achieve the grouped result
// 5. Serialize to Json
static void Main(string[] args)
{
var myObjects = new MyObjects() { Active = true, OtherObjects = new List<OtherObject>() };
myObjects.OtherObjects.Add(new OtherObject { Id = 1, Name = "First" });
myObjects.OtherObjects.Add(new OtherObject { Id = 2, Name = "First" });
myObjects.OtherObjects.Add(new OtherObject { Id = 3, Name = "Second" });
myObjects.OtherObjectsDictionary = new Dictionary<string, List<OtherObject>>();
var distinctNames = myObjects.OtherObjects.Select(otherObject => otherObject.Name).Distinct();
foreach(var distinctName in distinctNames)
{
var groupedObjectsList = myObjects.OtherObjects.Where(otherObject => otherObject.Name == distinctName).ToList();
myObjects.OtherObjectsDictionary.Add(distinctName, groupedObjectsList);
}
var outputJson = Newtonsoft.Json.JsonConvert.SerializeObject(myObjects);
}
This is the json result:
{
"Active": true,
"OtherObjectsDictionary": {
"First": [
{
"Id": 1,
"Enabled": false,
"Address": null
},
{
"Id": 2,
"Enabled": false,
"Address": null
}
],
"Second": [
{
"Id": 3,
"Enabled": false,
"Address": null
}
]
}
}
I hope it helps.
You may also use the System.Web.Extensions .dll as Add References for framework 4.0 projects (not 4.0 Client Profile).
Then add using inside your class.
I also applied a different approach, a more-or-less DB like normalization.
List of classes
public class MyObjects
{
public bool Active { get; set; }
public List<ObjectName> OtherObjects { get; set; }
}
public class ObjectName
{
public string Name { get; set; }
public List<OtherObject> OtherObjectProperties { get; set; }
}
public class OtherObject
{
public int Id { get; set; }
public bool Enabled { get; set; }
[ScriptIgnore]
public string Address { get; set; }
[ScriptIgnore]
public string Name { get; set; }
}
populate the records..
List<OtherObject> oList = new List<OtherObject>();
oList.Add(new OtherObject() { Id = 2, Name = "First" });
oList.Add(new OtherObject() { Id = 3, Name = "Second" });
// each name with objects
List<ObjectName> oNames = new List<ObjectName>();
oNames.AddRange(oList.Select(p => new ObjectName() {
Name = p.Name
, OtherObjectProperties = oList.Where(p1 => p1.Name == p.Name).ToList()
}).Distinct()
);
// parent object with with object names
MyObjects mo = new MyObjects() { Active = true, OtherObjects = oNames };
and finally, the javascript serializer..
JavaScriptSerializer jss = new JavaScriptSerializer();
string b = jss.Serialize(mo);
string b should give you the output like below..
{
"Active":true
,"OtherObjects":[
{
"Name":"First"
,"OtherObjectProperties":[
{
"Id":2
,"Enabled":false}
]},
{
"Name":"Second"
,"OtherObjectProperties":[
{
"Id":3
,"Enabled":false}
]
}]
}
Please advise if you're confused about any of the following.. :)

Categories