How to POST list of dictionaries - c#

I would like to post following JSON via API using Restsharp library
{
"id" : "customerID",
"name" : "customerName",
"customKeys" : {
"dataA" : "{\"keyA\": \"valueA\", \"keyB\": \"valueB\"}",
"dataB" : "{\"keyA\": \"valueA\", \"keyB\": \"valueB\"}"
}
}
Actually i made following code which is creating Customer object and everything work correctly beside last fields customKeys....
public class Customer
{
public string id { get; set; }
public string name { get; set; }
public List<Dictionary<string, object>> customKeys { get; set; }
}
Customer customer = new Customer
{
id = id,
name = customerName,
customKeys = ????????????????
};
string json = JsonConvert.SerializeObject(customer);
RestRequest request = newRestRequest("someEndpoint",Method.POST);
request.AddJsonBody(customer);
var response = client.Execute(request);
I just wanted to be sure which data type i should use in following case.
Should i use Dictionary of Dictionaries or just ListOfDictionaries ? Or maybe there is a better and easier way to make that POST call ?

You would use a Dictionary of Dictionaries if your Dictionaries have a special meaning besides just positional placement.
Otherwise, you would be better with a List of Dictionaries.

You can try this:
public class CustomKeys
{
public string dataA { get; set; }
public string dataB { get; set; }
}
public class Customer
{
public string id { get; set; }
public string name { get; set; }
public List<CustomKeys> customKeys { get; set; }
}
Customer customer = new Customer
{
id = id,
name = customerName,
customKeys = new List<CustomKeys>()
{
dataA ="dataA",
dataB ="dataB "
};
};

Related

class property manipulation when parsing json data in c#

I am practicing with web api. My goal is to create a Get endpoint, which receive data from an external api, then return a different result. external api link: https://www.themealdb.com/api/json/v1/1/search.php?f=a, The external api data looks like:
{
"meals": [
{
"idMeal": "52768",
"strMeal": "Apple Frangipan Tart",
"strDrinkAlternate": null,
"strCategory": "Dessert",
.....
},
{
"idMeal": "52893",
"strMeal": "Apple & Blackberry Crumble",
....
}
]
}
I want my endpoint provide a different result like the following:
[
{
"idMeal": "52768",
"strMeal": "Apple Frangipan Tart",
"ingredients": ["Apple", "sugar"...]
},
{
"idMeal": "52893",
"strMeal": "Apple & Blackberry Crumble",
"ingredients": ["Apple", "sugar"...]
}
]
The following code is what I attempted so far, It's working, but the moment I changed property ingredient1 from public to private, that ingredient in list will become null, also, there are so many ingredients, some of them are null by default, I don't want to add them if they are null, how can I fix these two issues? Thanks a lot
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc;
using RestSharp;
namespace testAPI.Controllers;
public class Content
{
[JsonPropertyName("meals")]
public List<Meal> Meals { get; set; }
}
public class Meal
{
[JsonPropertyName("idMeal")]
public string MealId { get; set; }
[JsonPropertyName("strMeal")]
public string Name { get; set; }
[JsonPropertyName("strIngredient1")]
public string Ingredient1 { get; set; }
[JsonPropertyName("strIngredient2")]
public string Ingredient2 { get; set; }
[JsonPropertyName("strIngredient20")]
public string Ingredient20 { get; set; }
public List<string> Ingredients
{
get { return new List<string>(){Ingredient1, Ingredient2, Ingredient20};}
}
}
[ApiController]
[Route("api/[controller]")]
public class DishesController : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetAllRecipes()
{
var client = new RestClient($"https://www.themealdb.com/api/json/v1/1/search.php?s=");
var request = new RestRequest();
var response = await client.ExecuteAsync(request);
var mealList = JsonSerializer.Deserialize<Content>(response.Content);
return Ok(mealList.Meals);
}
}
To address the problems one at a time...
the moment I changed property ingredient1 from public to private, that ingredient in list will become null
Changing the access modifier affects both deserialization and serialization, so this cannot be used to only stop it from serializing the property. You should split the data models up into what you want to receive and what you want to expose/return.
there are so many ingredients, some of them are null by default, I don't want to add them if they are null
Addition to splitting up the data models you can handle this when mapping from one model to the other.
The following code should fix both issues:
namespace TheMealDb.Models
{
// These are the models you receive from TheMealDb
// JSON converted to classes with https://json2csharp.com/
public class Root
{
public List<Meal> meals { get; set; }
}
public class Meal
{
public string idMeal { get; set; }
public string strMeal { get; set; }
public string strIngredient1 { get; set; }
public string strIngredient2 { get; set; }
public string strIngredient3 { get; set; }
// Other properties removed for brevity...
}
}
namespace Internal.Models
{
// This is the model you want to return from your controller action
public class Meal
{
[JsonPropertyName("id")] // No need to use the same name as from themealdb
public string Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("ingredients")]
public List<string> Ingredients { get; set; }
}
}
Now, to fetch, map and return the data in your controller action:
[HttpGet]
public async Task<IActionResult> GetAllRecipes()
{
var client = new RestClient($"https://www.themealdb.com/api/json/v1/1/search.php?s=");
var request = new RestRequest();
var response = await client.ExecuteAsync(request);
// Deserialize to the "TheMealDb" models
var mealList = JsonSerializer.Deserialize<TheMealDb.Models.Root>(response.Content);
// Map to your own models
var myMealList = mealDbList.meals?.Select(MapToInternal);
return Ok(myMealList);
}
// Map "TheMealDb" model to your own model
private Internal.Models.Meal MapToInternal(TheMealDb.Models.Meal externalMeal)
{
return new Internal.Models.Meal
{
Id = externalMeal.idMeal,
Name = externalMeal.strMeal,
Ingredients = new []
{
externalMeal.strIngredient1,
externalMeal.strIngredient2,
externalMeal.strIngredient3,
// ...
}
// Remove empty/null ingredients
.Where(ingr => !string.IsNullOrEmpty(ingr))
.ToList()
};
}
See the code in action.

Creating and populating an object with complex types

I'm working on an API that will ultimately return a data extract in JSON format. This isn't my exact code. I've simplified the idea so I can convey my question more clearly.
There's a method that queries the database and returns the following columns:
CustomerID, CustomerName, Preference, PreferenceValue (where one customer will have dozens of preferences). The dataset is ordered by CustomerID.
My goal is to return a JSON object like this:
{
"Customer": {
"CustomerID": "123",
"CustomerName": "John Smith",
"CustomerPreferences": {
"Color": "Red",
"Texture": "Rough",
"Size": "Medium",
"Weight": "Heavy"
}
}
}
I'm new to C# and OO. So, to these ends, I've been researching and trying various approaches all day. I can do this with a single object no problem, but not with a nested class. My intuition tells me what I'm trying to do shouldn't be much harder... but it continues to elude me.
I tried this (it didn't work). I made this class (note: it is the same shape as the JSON I'm hoping to get):
public class Customer
{
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public class Preferences
{
public string Preference { get; set; }
public string PreferenceValue { get; set; }
}
}
Then I created the objects (although at this point, I'm already sure I'm on the wrong path, since I'm forced to initialize them separately):
List<Customer> lstCustomer = new List<Customer>();
List<Customer.Preference> lstPref = new List<Customer.Preference>();
Then I tried looping through my query results... (not sure why I'm still sharing this, since I know it doesn't work, and I'm likely embarrassing myself!!):
if (rdr.HasRows)
{
string CurrentCustomer = "";
while (rdr.Read())
{
/*
Since the data is sorted by CustID,
I only add the parent class when it changes.
*/
if (CurrentCustomer != rdr["CustID"].ToString())
{
lstCustomer.Add(new Customer
{
CustomerID = rdr["CustID"].ToString(),
CustomerName = rdr["CustomerName"].ToString()
});
CurrentCustomer = rdr["CustID"].ToString();
}
lstPref.Add(new Customer.Preference
{
PrefName = rdr["PreferanceName"].ToString(),
PrefValue = rdr["PreferenceValue"].ToString()
});
}
}
I have the feeling this is relatively easy. I've been searching and searching, and cannot find the solution. Once I have an object created and populated, returning it as JSON is a snap. But I can't figure out how to create this simple data structure!
You're not that far off. I'd go with something like this
public class Customer
{
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public Dictionary<string, string> Preferences { get; set; }
public Customer()
{
Preferences = new Dictionary<string, string>();
}
}
and
List<Customer> customers = new List<Customer>();
if (rdr.HasRows)
{
Customer CurrentCustomer = new Customer();
while (rdr.Read())
{
/*
Since the data is sorted by CustID,
I only add the parent class when it changes.
*/
if (CurrentCustomer.CustomerID != rdr["CustID"].ToString())
{
CurrentCustomer = new Customer()
{
CustomerID = rdr["CustID"].ToString(),
CustomerName = rdr["CustomerName"].ToString()
};
customers.Add(CurrentCustomer);
}
CurrentCustomer.Preferences.Add(rdr["PreferanceName"].ToString(),
rdr["PreferenceValue"].ToString());
}
}
but try not to butcher the formatting like I did ...
It seems to me your JSON structure and your class structure don't really match. Instead of a nested class, consider using a dictionary to match a preference name to its value.
public class Customer
{
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public Dictionary<string, string> Preferences { get; }
}
Then you can add preferences to your dictionary using the usual add method.
Move preferences outside of your Customer class, and define a property instead:
public class Customer
{
public string CustomerID { get; set; }
public string CustomerName { get; set; }
public List<Preference> Preferences { get; set;}
}
public class Preference
{
public string Preference { get; set; }
public string PreferenceValue { get; set; }
}

C# Copy List items to Object Arrays

I have a list created from a stored procedure using EF6.0
I have also created 3 classes
public class Resas
{
public string todo{ get; set; }
public string prop { get; set; }
public string Code { get; set; }
public string statusCode { get; set; }
public string checkin { get; set; }
public string checkout { get; set; }
public List<profiles> profiles { get; set; }
}
public class profiles
{
public string action { get; set; }
public string id { get; set; }
public string profileType { get; set; }
public string title { get; set; }
public string firstName { get; set; }
public string middleName { get; set; }
public string lastName { get; set; }
public List<emailAddresses> emailAdresses { get; set; }
}
public class emailAddresses
{
public string emailAddress { get; set; }
public string emailAddress2 { get; set; }
}
I am doing a for-loop in the list and I need to get certain columns and put it in the array (I will put two, to keep it simple)
myEntities db = new myEntities();
List<rev_Result> revList = new List<rev_Result>();
revList.Clear();
revList = db.rev().ToList();
for (int i = 0; i < revList.Count(); i++)
{
Resas resas = new Resas();
profiles[] profiles = new profiles[1];
resas.todo = revList[i].todo;
resas.profiles[0].lastName = revList[i].lastName;
}
I am not familiar with C# as you can see from the psedo-code above.
I cannot figure out how to feed the Resas with data and then its Profile with data and then move to the next Resas entry.
Any help appreciated.
That's fairly simple using Linq:
Resas resas = new Resas();
resas.profiles = revList
.Select(x => new profiles() { action = x.todo, lastName = x.lastName })
.ToList();
What's happening here is: You loop through every entry in revList and get your wanted data structure (that's what Select is doing). x refers to the current entry in the loop, while the stuff to the right side of the arrow is you 'output': a new instance of your profiles class with the members assigned accordingly. The result of all of this is then converted to a list (before ToList(), think of it as a recipe to create the list) and assigned to resas.profiles.
By the way, a word on conventions: Usually, in C#, you would give your classes a name that starts with a capital letter. Also, your profiles class seems to contain data of exactly one profile, so a better name might be Profile. This also makes your data structure more clear, since List<profiles> seems to be a list of lists of profiles - but that's not what it actually is, is it?
Furthermore, Members generally start with a capital letter as well, so instead of action, lastName, you'd have: Action and LastName.
You can try with Linq. This is the code that should solve your issue, but Resas class doesn't have action property:
List<Resas> ls = revList.Select(x => new Resas() {
action = x.todo,
profiles = new List<profiles>() {
new profiles { lastName = x.lastName }
}
).ToList();
If you need to use action property of inprofiles` class:
List<Resas> ls = revList.Select(x => new Resas() {
profiles = new List<profiles>() {
new profiles {
action = x.todo,
lastName = x.lastName
}
}
).ToList();

Want to change JSON Format

I have this class
public class Contact {
#regionContact Info
public Guid ContactID { get; set; }
public string Name { get; set; }
public string RegID { get; set; }
public string MobileNumber { get; set; }
public string Tel { get; set; }
#endregion
}
when I call getAllContact() method, I get this result
[{"ContactID":"7abe6291-43f2-e411-b150-000c2975315f","Name":"Visitor 1","RegID":"1","MobileNumber":"1122334455","Tel":"1122334455"},{"ContactID":"f76f310f-a3f3-e411-b150-000c2975315f","Name":"Visitor 2","RegID":"2","MobileNumber":null,"Tel":null},{"ContactID":"9b3e6018-a3f3-e411-b150-000c2975315f","Name":"Visitor 3","RegID":"3","MobileNumber":null,"Tel":null}]
but what I want is with this kind of format.
{"contacts":[{"ContactID":"7abe6291-43f2-e411-b150-000c2975315f","Name":"Visitor 1","RegID":"1","MobileNumber":"1122334455","Tel":"1122334455"},{"ContactID":"f76f310f-a3f3-e411-b150-000c2975315f","Name":"Visitor 2","RegID":"2","MobileNumber":null,"Tel":null},{"ContactID":"9b3e6018-a3f3-e411-b150-000c2975315f","Name":"Visitor 3","RegID":"3","MobileNumber":null,"Tel":null}]}
How can I change to get this json format? Could anybody help me please?
Your getAllContact() method should an object with one parameter in it called contacts which is of type List
public class ContactList {
public List<Contact> contacts { get; set; }
}
Then serialise the ContactList object.
Try to write like this way . sure u will get your result.Here i have added one item in list. you can add multiple items.
void getAllContact()
{
Dictionary<string, List<Contact>> contactsDic = new Dictionary<string, List<Contact>>();
List<Contact> list = new List<Contact>();
list.Add(new Contact
{
ContactID = Guid.Parse("7abe6291-43f2-e411-b150-000c2975315f"),
Name = "Visitor 1",
RegID = "1",
MobileNumber = "1122334455",
Tel = "1122334455"
}
);
contactsDic.Add("contacts", list);
string ss = JsonConvert.SerializeObject(contactsDic);
}
If your model is Contact class so Simplify do this:
return Ok(new {contacts = yourmodel});

Restsharp - Deserialize xml to list where element tag contains unique id

I am consuming a Rest-based service (CRM system called Solve360) and for example I am grabbing a list of contacts here is a snippet what I receive from the server:
<response>
<id99623996>
<id>99623996</id>
<name>Aaron</name>
<typeid>1</typeid>
<parentid>98830114</parentid>
<parentcn>CC</parentcn>
<flagged/>
<created>2014-01-03T17:10:47+00:00</created>
<viewed>2014-01-14T20:35:26+00:00</viewed>
<updated>2014-01-03T17:11:13+00:00</updated>
</id99623996>
<id99624297>
<id>99624297</id>
<name>Abigail </name>
<typeid>1</typeid>
<parentid>98830114</parentid>
<parentcn>CC</parentcn>
<flagged/>
<created>2014-01-03T17:11:01+00:00</created>
<viewed>2014-01-03T17:11:01+00:00</viewed>
<updated>2014-01-03T17:11:13+00:00</updated>
</id99624297>
</response>
So here is my c# code using latest Restsharp:
public T ExecuteSerializedCommand<T>(string resourceLoc, string method, Dictionary<string, string> parameters) where T : new() {
var request = BuildRestRequest(resourceLoc, method, parameters);
request.RootElement = "Response";
var response = RestSharpObj.Execute<T>(request);
if (response.ErrorException != null) {
const string message = "Error retrieving response. Check inner details for more info.";
var rsMessage = new ApplicationException(message, response.ErrorException);
throw rsMessage;
}
return response.Data;
}
And Here is the calling code:
public List<Contact> GeContacts() {
return ExecuteSerializedCommand<List<Contact>>(ITEM_CONTACTS, RESTVERB_GET, new Dictionary<string, string>());
}
Oh and my class Contact:
public class Contact {
public int id { get; set; }
public string name { get; set; }
public int typeid { get; set; }
public int parentid { get; set; }
public string parentcn { get; set; }
public string flagged { get; set; }
public DateTime created { get; set; }
public DateTime viewed { get; set; }
public DateTime updated { get; set; }
}
So my final deserialized response is null.
Any suggestions are appreciated. I think the problem is in the xml tag that contains the id number. Not sure how to handle that with Restsharp.

Categories

Resources