Related
I'm trying to write my own small API. I found an article on how to implement an API with Mongodb on ASP.NET Core MVC: article. The problem is that when creating a GET request, the object is incorrectly serialized. As I understand it, the standard Json serializer cannot serialize objects of a custom data type.
Here is the file with the model that I am reading from the database. Everything comes from the database correctly, but when I try to send a response, a file with an empty List<Weekday> arrives.
[Serializable]
public class Group
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string? Id { get; set; }
public string groupName { get; set; }
public Schedule schedule { get; set; }
public Group()
{
groupName = "UNKNOWN";
schedule = new Schedule();
}
public Group(string groupName)
{
this.groupName = groupName;
schedule = new Schedule();
}
}
[Serializable]
public class Schedule
{
public List<Weekday> week = new List<Weekday>();
}
[Serializable]
public class Weekday
{
public List<DaysSchedule> daysSchedules { get; set; } = new List<DaysSchedule>();
public int dayNumber { get; set; } = 0;
}
public class DaysSchedule
{
public List<string> dates = new List<string>();
public List<Classes> classes = new List<Classes>();
}
public class Classes
{
[BsonElement("ordinal")]
public int ordinal { get; set; }
[BsonElement("name")]
public string name { get; set; }
[BsonElement("teacher")]
public string? teacher { get; set; }
[BsonElement("type")]
public string type { get; set; }
[BsonElement("location")]
public string location { get; set; }
public Classes()
{
ordinal = 0;
name = "UNKNOWN";
type = "UNDEFINED";
location = "UNDEFINED";
}
public Classes(int ordinal, string name, string teacher, string type, string location)
{
this.ordinal = ordinal;
this.name = name;
this.teacher = teacher;
this.type = type;
this.location = location;
}
}
Here is an example of a Json file that I expect. I did not insert the entire file, as it is very large. But the main point is that the Week list contains days of the week, each of which has certain schedule options.
{
"Id": "63ea85829903ec2ab03720d3",
"groupName": "М3О-225Бк-21",
"schedule": {
"week": [
{
"daysSchedules": [
{
"dates": [
"13.02.2023",
"13.02.2023"
],
"classes": [
{
"ordinal": 0,
"name": "Math",
"teacher": "Lyahner",
"type": "PZ",
"location": "64"
},
{
"ordinal": 1,
"name": "Programming",
"teacher": "Lyahner",
"type": "LK",
"location": "84"
},
{
"ordinal": 2,
"name": "OOP",
"teacher": "Lyahner",
"type": "LK",
"location": "29"
},
{
"ordinal": 3,
"name": "OOP",
"teacher": "Vestyak",
"type": "LK",
"location": "33"
}
]
},
{
"dates": [
"13.02.2023",
"13.02.2023"
],
"classes": [
{
"ordinal": 0,
"name": "Phisics",
"teacher": "Lyahner",
"type": "LK",
"location": "97"
},
{
"ordinal": 1,
"name": "Programming",
"teacher": "Lyahner",
"type": "LK",
"location": "78"
},
{
"ordinal": 2,
"name": "Programming",
"teacher": "Sukhno",
"type": "PZ",
"location": "91"
},
{
"ordinal": 3,
"name": "Programming",
"teacher": "Sukhno",
"type": "PZ",
"location": "32"
}
]
},
{
"dates": [
"13.02.2023",
"13.02.2023"
],
"classes": [
{
"ordinal": 0,
"name": "OOP",
"teacher": "Vestyak",
"type": "LK",
"location": "93"
},
{
"ordinal": 1,
"name": "Math",
"teacher": "Lyahner",
"type": "PZ",
"location": "72"
},
{
"ordinal": 2,
"name": "Math",
"teacher": "Vestyak",
"type": "LK",
"location": "70"
},
{
"ordinal": 3,
"name": "Phisics",
"teacher": "Vestyak",
"type": "LK",
"location": "42"
}
]
}
],
"dayNumber": 0
.......................................
Here's what Json I get:
{
"id": "63ea85829903ec2ab03720d3",
"groupName": "М3О-225Бк-21",
"schedule": {}
}
Here is the code of my Controller. Here I don't quite understand how the Http Get and Http Post attributes work. I understand that they configure routing and transfer control to a method for processing and sending a response. But where does the serialization of the Group object take place and how is it passed to the method? I tried to implement serialization explicitly by taking a string variable in the Get method and serializing the object using Newtonsoft.Json, it worked, but I don't think this option is correct and suits me. I would like to know what the problem is? And can I set custom serialization for the Group object so that I can pass and return it from methods with routing attributes?
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;
using ThreeplyWebApi.Services;
using ThreeplyWebApi.Models;
using System.Text.Json;
namespace ThreeplyWebApi.Controllers
{
[ApiController]
[Route("controller")]
public class GroupsController : ControllerBase
{
readonly private GroupsService _groupsService;
public GroupsController(GroupsService schedulesService)
{
_groupsService = schedulesService;
}
[HttpGet]
public async Task<List<Group>> Get() => await _groupsService.GetAsync();
[HttpGet("{groupName}")]
public async Task<ActionResult<Group>> Get(string groupName)
{
var group = await _groupsService.GetAsync(groupName);
if (group == null)
{
return NotFound();
}
return Ok(group);
}
[HttpPost]
public async Task<IActionResult> Post([FromBody]Group newGroup)
{
await _groupsService.CreateAsync(newGroup);
return CreatedAtAction(nameof(Get), new { groupName = newGroup.groupName }, newGroup);
}
}
}
I also provide the code of my service for accessing the database, the methods of which are called by the controller to access the database.
namespace ThreeplyWebApi.Services
{
public class GroupsService
{
private readonly IMongoCollection<Group> _groupsCollection;
public GroupsService(IOptions<GroupsDatabaseSettings> groupDatabaseSettings)
{
var MongoClient = new MongoClient(groupDatabaseSettings.Value.ConnectionString);
var MongoDatabase = MongoClient.GetDatabase(groupDatabaseSettings.Value.DatabaseName);
_groupsCollection = MongoDatabase.GetCollection<Group>(groupDatabaseSettings.Value.GroupsCollectionName);
}
public async Task<List<Group>> GetAsync()
{
return await _groupsCollection.Find<Group>(_ => true).ToListAsync();
}
public async Task<Group> GetAsync(string groupName)
{
return await _groupsCollection.Find(x => x.groupName == groupName).FirstOrDefaultAsync();
}
public async Task CreateAsync(Group group) {
await _groupsCollection.InsertOneAsync(group);
}
public async Task UpdateAsync(string groupName, Group updatedGroup) =>
await _groupsCollection.ReplaceOneAsync(x => x.groupName == groupName, updatedGroup);
public async Task RemoveAsync(string groupName) =>
await _groupsCollection.DeleteOneAsync(x => x.groupName == groupName);
}
}
I am really new to c# language programming and
I have a JSON string:
{
"Type": "Name",
"parameters": [
{
"A": {
"type": "string",
"defaultValue": "key"
},
"B": {
"type": "string",
"defaultValue": "key"
},
"C": {
"type": "string",
"defaultValue": "key"
},
"D": {
"type": "string",
"defaultValue": "autogenerated"
},
"E": {
"type": "string",
"defaultValue": "autogenerated"
},
"F": {
"type": "dropdown",
"dropDownItems": [
"true",
"false"
],
"defaultValue": "false"
}
}
]
}
and I want to output the JSON array parameters but without "A", "B" and "C".
This JSON File is always changing but it always have this "A", "B" and "C".
Among with the answer of Thierry Prost
namespace Testedouble
{
class Program
{
static void Main(string[] args)
{
var jsonString = #"{
'Type': 'Name',
'parameters': [
{
'A': {
'type': 'string',
'defaultValue': 'key'
},
'B': {
'type': 'string',
'defaultValue': 'key'
},
'C': {
'type': 'string',
'defaultValue': 'key'
},
'D': {
'type': 'string',
'defaultValue': 'autogenerated'
},
'E': {
'type': 'string',
'defaultValue': 'autogenerated'
},
'F': {
'type': 'dropdown',
'dropDownItems': [
'true',
'false'
],
'defaultValue': 'false'
}
}
]
}";
var values = JsonConvert.DeserializeObject<Foo>(jsonString);
foreach (var key in new string[] { "A", "B", "C" })
{
foreach (var item in values.parameters)
{
item.Remove(key);
}
}
Console.WriteLine(JsonConvert.SerializeObject(values));
}
public class Foo
{
public string Type { get; set; }
public List<Dictionary<string, object>> Parameters { get; set; }
}
}
}
I made a small console application that shows the desired result. The flow is as follows:
We create the C# classes we need for the given JSON: DropdownInfo, ParameterInfo, ParameterBase, Base. I made them several so you can better extend them as you need.
We Deserialize the Object and then modify it the way we want.
var itemsToRemove = new string[] { "A", "B", "C" };
Here we add all the elements, which we don't want to be in the output. In our case, we remove A, B, C
- Serialize back the Object to JSON. We use Formatting.Indented, so the result looks better (beautifier, human readable)
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
namespace JsonExercise
{
public class JsonExercise
{
public static void Main(string[] args)
{
var sb = new StringBuilder();
var line = string.Empty;
while (!string.IsNullOrWhiteSpace((line = Console.ReadLine())))
{
sb.AppendLine(line);
}
var json = sb.ToString().Trim();
var inputObj = JsonConvert.DeserializeObject<Base>(json);
var resultObj = new
{
Type = inputObj.Type,
Parameters = new List<object>()
};
Console.WriteLine("--------------------------------");
//Here we can give all the Properties, which will be skipped!
var itemsToRemove = new string[] { "A", "B", "C" };
var propertiesToAdd = new Dictionary<string, object>();
foreach (var propertyInfo in typeof(ParameterBase).GetProperties())
{
if (!itemsToRemove.Contains(propertyInfo.Name))
{
var propertyValue = (inputObj.Parameters[0]).GetType().GetProperty(propertyInfo.Name).GetValue(inputObj.Parameters[0]);
propertiesToAdd.Add($"{propertyInfo.Name}", propertyValue);
}
}
var objToAdd = GetDynamicObject(propertiesToAdd);
resultObj.Parameters.Add(objToAdd);
Console.WriteLine("Serializing Object");
Console.WriteLine(JsonConvert.SerializeObject(resultObj, Formatting.Indented));
}
public static dynamic GetDynamicObject(Dictionary<string, object> properties)
{
return new MyDynObject(properties);
}
}
public sealed class MyDynObject : DynamicObject
{
private readonly Dictionary<string, object> _properties;
public MyDynObject(Dictionary<string, object> properties)
{
_properties = properties;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _properties.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_properties.ContainsKey(binder.Name))
{
result = _properties[binder.Name];
return true;
}
else
{
result = null;
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (_properties.ContainsKey(binder.Name))
{
_properties[binder.Name] = value;
return true;
}
else
{
return false;
}
}
}
public class Base
{
public string Type { get; set; }
public ParameterBase[] Parameters { get; set; }
}
public class ParameterBase
{
public ParameterInfo A { get; set; }
public ParameterInfo B { get; set; }
public ParameterInfo C { get; set; }
public ParameterInfo D { get; set; }
public ParameterInfo E { get; set; }
public DropdownInfo F { get; set; }
}
public class ParameterInfo
{
public string Type { get; set; }
public string DefaultValue { get; set; }
}
public class DropdownInfo
{
public string Type { get; set; }
public string DefaultValue { get; set; }
public string[] DropDownItems { get; set; }
}
}
The first part of the code with the StringBuilder class is just to read the input(The given JSON).
I will give sample input and output JSON data.
--INPUT--
{
"Type": "Name",
"parameters": [
{
"A": {
"type": "string",
"defaultValue": "key"
},
"B": {
"type": "string",
"defaultValue": "key"
},
"C": {
"type": "string",
"defaultValue": "key"
},
"D": {
"type": "string",
"defaultValue": "autogenerated"
},
"E": {
"type": "string",
"defaultValue": "autogenerated"
},
"F": {
"type": "dropdown",
"dropDownItems": [
"true",
"false"
],
"defaultValue": "false"
}
}
]
}
--OUTPUT--
{
"Type": "Name",
"Parameters": [
{
"D": {
"Type": "string",
"DefaultValue": "autogenerated"
},
"E": {
"Type": "string",
"DefaultValue": "autogenerated"
},
"F": {
"Type": "dropdown",
"DefaultValue": "false",
"DropDownItems": [
"true",
"false"
]
}
}
]
}
Edit: Changed the code after #João Paulo Amorim comment. I tested the code it works fine, use it freely.
Shout out to João Paulo Amorim and his answer. Looks smoother.
PS. My first answer on StackOverFlow \o/
With Newtonsoft.Json package:
using System;
using Newtonsoft.Json;
using System.IO;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
//File with json
string jsontext = File.ReadAllText("json.json");
dynamic json = JsonConvert.DeserializeObject(jsontext);
foreach(var parameter in json.parameters)
{
Console.WriteLine(parameter.D);
Console.WriteLine(parameter.E);
Console.WriteLine(parameter.F);
}
Console.ReadLine();
}
}
}
Using newtonsoft library
Working Fiddle added
public class Foo
{
public string Type { get; set; }
[JsonProperty("parameters")]
public List<Dictionary<string, object>> Parameters { get; set; }
[JsonProperty("defaultValue")]
public string DefaultValue { get; set; }
}
var values = JsonConvert.DeserializeObject<Foo>(jsonStr);
values.Parameters = values
.Parameters
.Select(
dic => dic
.Where(kvp => new string[] { "A", "B", "C" }.Contains(kvp.Key))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value))
.ToList();
Console.WriteLine(JsonConvert.SerializeObject(values));
1) Parse your json to JObject under namespace with using Newtonsoft.Json.Linq;
2) Retrieve 1st object inside parameters array by using JObject.SelectToken()
3) Remove A, B, C by using JObject.Remove()
string json = "Your json here";
JObject jObject = JObject.Parse(json);
JObject jObj = (JObject)jObject.SelectToken("parameters[0]");
jObj.Property("A").Remove();
jObj.Property("B").Remove();
jObj.Property("C").Remove();
string output = jObject.ToString();
Output: (From Debugger)
Online Demo
I am having trouble deserializing JSON received from HubSpot ContactList API.
I am using Restsharp and NewtonSoft, and I'm having real struggles understanding how to correctly define the required classes in order to deserialize the JSON string, which is below:
"contacts": [
{
"vid": 2251,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2251",
"properties": {
"firstname": {
"value": "Carl"
},
"lastmodifieddate": {
"value": "1554898386040"
},
"company": {
"value": "Cygnus Project"
},
"lastname": {
"value": "Swann"
}
},
"form-submissions": [],
"identity-profiles": [
{
"vid": 2251,
"saved-at-timestamp": 1553635648634,
"deleted-changed-timestamp": 0,
"identities": [
{
"type": "EMAIL",
"value": "cswann#cygnus.co.uk",
"timestamp": 1553635648591,
"is-primary": true
},
{
"type": "LEAD_GUID",
"value": "e2345",
"timestamp": 1553635648630
}
]
}
],
"merge-audits": []
},
{
"vid": 2301,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2301",
"properties": {
"firstname": {
"value": "Carlos"
},
"lastmodifieddate": {
"value": "1554886333954"
},
"company": {
"value": "Khaos Control"
},
"lastname": {
"value": "Swannington"
}
},
"identity-profiles": [
{
"vid": 2301,
"saved-at-timestamp": 1553635648733,
"deleted-changed-timestamp": 0,
"identities": [
{
"type": "EMAIL",
"value": "cswann#khaoscontrol.com",
"timestamp": 1553635648578,
"is-primary": true
},
{
"type": "LEAD_GUID",
"value": "c7f403ba",
"timestamp": 1553635648729
}
]
}
],
"merge-audits": []
}
],
"has-more": false,
"vid-offset": 2401
}
If I simply request the vid, I correctly get 2 vid's back. It's when I try to do the properties and that i get a fail.
Please help
Lets reduce the Json to the minimum to reproduce your error :
{
"vid": 2301,
"portal-id": 5532227,
"is-contact": true,
"profile-url": "https://app.hubspot.com/contacts/5532227/contact/2301",
"properties": {
"firstname": {
"value": "Carlos"
},
"lastmodifieddate": {
"value": "1554886333954"
},
"company": {
"value": "Khaos Control"
},
"lastname": {
"value": "Swannington"
}
}
}
And the appropriate class ContactListAPI_Result:
public partial class ContactListAPI_Result
{
[JsonProperty("vid")]
public long Vid { get; set; }
[JsonProperty("portal-id")]
public long PortalId { get; set; }
[JsonProperty("is-contact")]
public bool IsContact { get; set; }
[JsonProperty("profile-url")]
public Uri ProfileUrl { get; set; }
[JsonProperty("properties")]
public Dictionary<string, Dictionary<string, string>> Properties { get; set; }
}
public partial class ContactListAPI_Result
{
public static ContactListAPI_Result FromJson(string json)
=> JsonConvert.DeserializeObject<ContactListAPI_Result>(json);
//public static ContactListAPI_Result FromJson(string json)
// => JsonConvert.DeserializeObject<ContactListAPI_Result>(json, Converter.Settings);
}
public static void toto()
{
string input = #" {
""vid"": 2301,
""portal-id"": 5532227,
""is-contact"": true,
""profile-url"": ""https://app.hubspot.com/contacts/5532227/contact/2301"",
""properties"": {
""firstname"": {
""value"": ""Carlos""
},
""lastmodifieddate"": {
""value"": ""1554886333954""
},
""company"": {
""value"": ""Khaos Control""
},
""lastname"": {
""value"": ""Swannington""
}
}
}";
var foo = ContactListAPI_Result.FromJson(input);
}
But the Value of one property will be burrow in the sub dictionary, we can the project the object in a more usefull one :
public partial class ItemDTO
{
public long Vid { get; set; }
public long PortalId { get; set; }
public bool IsContact { get; set; }
public Uri ProfileUrl { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
Adding the projection to the Class:
public ItemDTO ToDTO()
{
return new ItemDTO
{
Vid = Vid,
PortalId = PortalId,
IsContact = IsContact,
ProfileUrl = ProfileUrl,
Properties =
Properties.ToDictionary(
p => p.Key,
p => p.Value["value"]
)
};
}
Usage :
var result = foo.ToDTO();
Live Demo
Creating and managing class structure for big and nested key/value pair json is tedious task
So one approach is to use JToken instead.
You can simply parse your JSON to JToken and by querying parsed object, you will easily read the data that you want without creating class structure for your json
From your post it seems you need to retrieve vid and properties from your json so try below code,
string json = "Your json here";
JToken jToken = JToken.Parse(json);
var result = jToken["contacts"].ToObject<JArray>()
.Select(x => new
{
vid = Convert.ToInt32(x["vid"]),
properties = x["properties"].ToObject<Dictionary<string, JToken>>()
.Select(y => new
{
Key = y.Key,
Value = y.Value["value"].ToString()
}).ToList()
}).ToList();
//-----------Print the result to console------------
foreach (var item in result)
{
Console.WriteLine(item.vid);
foreach (var prop in item.properties)
{
Console.WriteLine(prop.Key + " - " + prop.Value);
}
Console.WriteLine();
}
Output:
OK. I have sent a GET request to SharePoint and received a string back:
"{\"#odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items\",\"value\":[{\"#odata.etag\":\"\\\"a69b1840-239d-42ed-9b20-8789761fb06a,3\\\"\",\"createdDateTime\":\"2018-08-25T22:44:16Z\",\"eTag\":\"\\\"a69b1840-239d-42ed-9b20-8789761fb06a,3\\\"\",\"id\":\"9\",\"lastModifiedDateTime\":\"2018-08-25T22:44:16Z\",\"webUrl\":\"https://XXXXX.sharepoint.com/sites/GeneratorApp/Lists/GenApp/9_.000\",\"createdBy\":{\"user\":{\"email\":\"XXXXX#XXXXX.com\",\"id\":\"b0465821-e891-4f44-9e18-27e875f1b75d\",\"displayName\":\"XXXXX\"}},\"lastModifiedBy\":{\"user\":{\"email\":\"XXXXX#XXXXX.com\",\"id\":\"b0465821-e891-4f44-9e18-27e875f1b75d\",\"displayName\":\"XXXXX\"}},\"parentReference\":{},\"contentType\":{\"id\":\"0x0100E19591A4ECA81542AEA41A6AAFED6781\"},\"fields#odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items('9')/fields/$entity\",\"fields\":{\"#odata.etag\":\"\\\"a69b1840-239d-42ed-9b20-8789761fb06a,3\\\"\",\"SerialNumber\":\"20180824-1353-DC6-Generator-A\",\"id\":\"9\"}},{\"#odata.etag\":\"\\\"13f60f9e-1bf2-4803-93b9-c45234963d47,3\\\"\",\"createdDateTime\":\"2018-08-25T22:45:55Z\",\"eTag\":\"\\\"13f60f9e-1bf2-4803-93b9-c45234963d47,3\\\"\",\"id\":\"10\",\"lastModifiedDateTime\":\"2018-08-25T22:45:55Z\",\"webUrl\":\"https://XXXXX.sharepoint.com/sites/GeneratorApp/Lists/GenApp/10_.000\",\"createdBy\":{\"user\":{\"email\":\"XXXXX#XXXXX.com\",\"id\":\"b0465821-e891-4f44-9e18-27e875f1b75d\",\"displayName\":\"XXXXX\"}},\"lastModifiedBy\":{\"user\":{\"email\":\"XXXXX#XXXXX.com\",\"id\":\"b0465821-e891-4f44-9e18-27e875f1b75d\",\"displayName\":\"XXXXX\"}},\"parentReference\":{},\"contentType\":{\"id\":\"0x0100E19591A4ECA81542AEA41A6AAFED6781\"},\"fields#odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items('10')/fields/$entity\",\"fields\":{\"#odata.etag\":\"\\\"13f60f9e-1bf2-4803-93b9-c45234963d47,3\\\"\",\"SerialNumber\":\"20180824-1416-DC6-Generator-B\",\"id\":\"10\"}},{\"#odata.etag\":\"\\\"00024848-0d4e-4ee8-b018-f1653af2a577,3\\\"\",\"createdDateTime\":\"2018-08-25T22:47:30Z\",\"eTag\":\"\\\"00024848-0d4e-4ee8-b018-f1653af2a577,3\\\"\",\"id\":\"11\",\"lastModifiedDateTime\":\"2018-08-25T22:47:30Z\",\"webUrl\":\"https://XXXXX.sharepoint.com/sites/GeneratorApp/Lists/GenApp/11_.000\",\"createdBy\":{\"user\":{\"email\":\"XXXXX#XXXXX.com\",\"id\":\"b0465821-e891-4f44-9e18-27e875f1b75d\",\"displayName\":\"XXXXX\"}},\"lastModifiedBy\":{\"user\":{\"email\":\"XXXXX#XXXXX.com\",\"id\":\"b0465821-e891-4f44-9e18-27e875f1b75d\",\"displayName\":\"XXXXX\"}},\"parentReference\":{},\"contentType\":{\"id\":\"0x0100E19591A4ECA81542AEA41A6AAFED6781\"},\"fields#odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items('11')/fields/$entity\",\"fields\":{\"#odata.etag\":\"\\\"00024848-0d4e-4ee8-b018-f1653af2a577,3\\\"\",\"SerialNumber\":\"20180824-1438-DC6-Generator-R\",\"id\":\"11\"}},{\"#odata.etag\":\"\\\"7c8e80ed-6fea-408a-9594-2b7b13e3691b,3\\\"\",\"createdDateTime\":\"2018-08-25T23:02:43Z\",\"eTag\":\"\\\"7c8e80ed-6fea-408a-9594-2b7b13e3691b,3\\\"\",\"id\":\"12\",\"lastModifiedDateTime\":\"2018-08-25T23:02:43Z\",\"webUrl\":\"https://XXXXX.sharepoint.com/sites/GeneratorApp/Lists/GenApp/12_.000\",\"createdBy\":{\"user\":{\"email\":\"XXXXX#XXXXX.com\",\"id\":\"b0465821-e891-4f44-9e18-27e875f1b75d\",\"displayName\":\"XXXXX\"}},\"lastModifiedBy\":{\"user\":{\"email\":\"XXXXX#XXXXX.com\",\"id\":\"b0465821-e891-4f44-9e18-27e875f1b75d\",\"displayName\":\"XXXXX\"}},\"parentReference\":{},\"contentType\":{\"id\":\"0x0100E19591A4ECA81542AEA41A6AAFED6781\"},\"fields#odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items('12')/fields/$entity\",\"fields\":{\"#odata.etag\":\"\\\"7c8e80ed-6fea-408a-9594-2b7b13e3691b,3\\\"\",\"SerialNumber\":\"20180824-1456-DC6-Generator-C\",\"id\":\"12\"}}]}"
Which will JObject.Parse to this:
{{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items",
"value": [
{
"#odata.etag": "\"a69b1840-239d-42ed-9b20-8789761fb06a,3\"",
"createdDateTime": "2018-08-25T22:44:16Z",
"eTag": "\"a69b1840-239d-42ed-9b20-8789761fb06a,3\"",
"id": "9",
"lastModifiedDateTime": "2018-08-25T22:44:16Z",
"webUrl": "https://XXXXX.sharepoint.com/sites/GeneratorApp/Lists/GenApp/9_.000",
"createdBy": {
"user": {
"email": "XXXXX#XXXXX.com",
"id": "b0465821-e891-4f44-9e18-27e875f1b75d",
"displayName": "XXXXX"
}
},
"lastModifiedBy": {
"user": {
"email": "XXXXX#XXXXX.com",
"id": "b0465821-e891-4f44-9e18-27e875f1b75d",
"displayName": "XXXXX"
}
},
"parentReference": {},
"contentType": {
"id": "0x0100E19591A4ECA81542AEA41A6AAFED6781"
},
"fields#odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items('9')/fields/$entity",
"fields": {
"#odata.etag": "\"a69b1840-239d-42ed-9b20-8789761fb06a,3\"",
"SerialNumber": "20180824-1353-DC6-Generator-A",
"id": "9"
}
},
{
"#odata.etag": "\"13f60f9e-1bf2-4803-93b9-c45234963d47,3\"",
"createdDateTime": "2018-08-25T22:45:55Z",
"eTag": "\"13f60f9e-1bf2-4803-93b9-c45234963d47,3\"",
"id": "10",
"lastModifiedDateTime": "2018-08-25T22:45:55Z",
"webUrl": "https://XXXXX.sharepoint.com/sites/GeneratorApp/Lists/GenApp/10_.000",
"createdBy": {
"user": {
"email": "XXXXX#XXXXX.com",
"id": "b0465821-e891-4f44-9e18-27e875f1b75d",
"displayName": "XXXXX"
}
},
"lastModifiedBy": {
"user": {
"email": "XXXXX#XXXXX.com",
"id": "b0465821-e891-4f44-9e18-27e875f1b75d",
"displayName": "XXXXX"
}
},
"parentReference": {},
"contentType": {
"id": "0x0100E19591A4ECA81542AEA41A6AAFED6781"
},
"fields#odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items('10')/fields/$entity",
"fields": {
"#odata.etag": "\"13f60f9e-1bf2-4803-93b9-c45234963d47,3\"",
"SerialNumber": "20180824-1416-DC6-Generator-B",
"id": "10"
}
},
{
"#odata.etag": "\"00024848-0d4e-4ee8-b018-f1653af2a577,3\"",
"createdDateTime": "2018-08-25T22:47:30Z",
"eTag": "\"00024848-0d4e-4ee8-b018-f1653af2a577,3\"",
"id": "11",
"lastModifiedDateTime": "2018-08-25T22:47:30Z",
"webUrl": "https://XXXXX.sharepoint.com/sites/GeneratorApp/Lists/GenApp/11_.000",
"createdBy": {
"user": {
"email": "XXXXX#XXXXX.com",
"id": "b0465821-e891-4f44-9e18-27e875f1b75d",
"displayName": "XXXXX"
}
},
"lastModifiedBy": {
"user": {
"email": "XXXXX#XXXXX.com",
"id": "b0465821-e891-4f44-9e18-27e875f1b75d",
"displayName": "XXXXX"
}
},
"parentReference": {},
"contentType": {
"id": "0x0100E19591A4ECA81542AEA41A6AAFED6781"
},
"fields#odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items('11')/fields/$entity",
"fields": {
"#odata.etag": "\"00024848-0d4e-4ee8-b018-f1653af2a577,3\"",
"SerialNumber": "20180824-1438-DC6-Generator-R",
"id": "11"
}
},
{
"#odata.etag": "\"7c8e80ed-6fea-408a-9594-2b7b13e3691b,3\"",
"createdDateTime": "2018-08-25T23:02:43Z",
"eTag": "\"7c8e80ed-6fea-408a-9594-2b7b13e3691b,3\"",
"id": "12",
"lastModifiedDateTime": "2018-08-25T23:02:43Z",
"webUrl": "https://XXXXX.sharepoint.com/sites/GeneratorApp/Lists/GenApp/12_.000",
"createdBy": {
"user": {
"email": "XXXXX#XXXXX.com",
"id": "b0465821-e891-4f44-9e18-27e875f1b75d",
"displayName": "XXXXX"
}
},
"lastModifiedBy": {
"user": {
"email": "XXXXX#XXXXX.com",
"id": "b0465821-e891-4f44-9e18-27e875f1b75d",
"displayName": "XXXXX"
}
},
"parentReference": {},
"contentType": {
"id": "0x0100E19591A4ECA81542AEA41A6AAFED6781"
},
"fields#odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('XXXXX.sharepoint.com%2C495435b4-60c3-49b7-8f6e-1d262a120ae5%2C0fad9f67-35a8-4c0b-892e-113084058c0a')/lists('18a725ac-83ef-48fb-a5cb-950ca2378fd0')/items('12')/fields/$entity",
"fields": {
"#odata.etag": "\"7c8e80ed-6fea-408a-9594-2b7b13e3691b,3\"",
"SerialNumber": "20180824-1456-DC6-Generator-C",
"id": "12"
}
}
]
}}
What I ultimately want to do is create a dropdown that is populated with the SerialNumber. When the SerialNumber is selected in the dropdown, it will return the id so that I can then plug that into a GET request to retrieve the appropriate listitems.
I am trying to figure out if I need to do a foreach to create a LIST<> or something else all together.
I do have this class setup, but wasn't sure if I could use it the way I thought I could.
public class Lookup
{
string id { get; set; };
string SerialNumber { get; set; }
}
This is the final working code:
private async void GetButton_Click(object sender, RoutedEventArgs e)
{
var (authResult, message) = await Authentication.AquireTokenAsync();
ResultText.Text = message;
if (authResult != null)
{
var httpClient = new HttpClient();
HttpResponseMessage response;
var request = new HttpRequestMessage(HttpMethod.Get, geturl);
//Add the token in Authorization header
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
response = await httpClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
JObject json = JObject.Parse(content);
var result = JsonConvert.DeserializeObject<SharePointListItems.RootObject>(content);
foreach (var d in result.value)
{
Lookups.Add(new SharePointListItems.Lookup() { id = d.fields.id, SerialNumber = d.fields.SerialNumber });
}
TestComboBox.ItemsSource = Lookups;
}
}
private void TestComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (TestComboBox.SelectedIndex != -1)
{
var mylookupId = (TestComboBox.SelectedItem as SharePointListItems.Lookup).id;// get your id and do further processing here.
ResultText.Text = mylookupId;
}
}
public class SharePointListItems
{
public class Lookup
{
public string SerialNumber { get; set; }
public string id { get; set; }
public override string ToString()
{
return SerialNumber;
}
}
public class Value
{
public Lookup fields { get; set; }
}
public class Fields
{
[JsonProperty("#odata.etag")]
public string ODataETag { get; set; }
...
}
public class RootObject
{
[JsonProperty("#odata.context")]
public string ODataContext { get; set; }
[JsonProperty("#odata.etag")]
public string ODataETag { get; set; }
[JsonProperty("fields#odata.context")]
public string FieldsODataContext { get; set; }
public Fields Fields { get; set; }
public List<Value> value { get; set; }
}
}
There are two way can create model easily.
You can use Web Essentials in Visual Studio, use Edit > Paste special > paste JSON as class, you can easier to know the relation between Json and model.
If you can't use Web Essentials you can instead of use http://json2csharp.com/ online JSON to Model class.
You can try to use those models to carry your JSON Format.
public class Lookup
{
public string SerialNumber { get; set; }
public string id { get; set; }
}
public class Value
{
public Lookup fields { get; set; }
}
public class RootObject
{
public List<Value> value { get; set; }
}
Then you can use obj.value property collection directly.
var obj = JsonConvert.DeserializeObject<RootObject>(jsonData);
foreach (var item in obj.value)
{
//item.fields.id
//item.fields.SerialNumber
}
A good example of how to bind a list of data to Combobox ( dropdown ) is here : https://www.c-sharpcorner.com/article/data-binding-in-xaml-uwp-using-combobox/
in this example the class is a Student with id and Name and it shows how u can show the name in combobox.
I will modify it a little for your scenario but if you want to go in depth than you can visit the provided link above.
This is the class
public class Fields
{
public string SerialNumber { get; set; }
public string id { get; set; }
public override string ToString()
{
return this.SerialNumber; // so that we can just bind to the object and get serial number in the ui.
}
}
Backend for adding items to the List
public sealed partial class MainPage: Page
{
List<Lookup> Lookups = new List<Lookup>();
public MainPage()
{
this.InitializeComponent();
Lookups.Add(new Lookup() {id = 1, SerialNumber = "S1"});
Lookups.Add(new Lookup() {id = 2, SerialNumber = "S2"});
Lookups.Add(new Lookup() {id = 3, SerialNumber = "S3"});
Lookups.Add(new Lookup() {id = 4, SerialNumber = "S4"});
//add as many items here as u want, u can even use a for loop or foreach loop or a Deserializer with newsoft json to get objects from ur json like below.
//var data = JsonConvert.DeserializeObject<RootObject>(jsonData);
//foreach (var d in data.value)
//{
// //d.fields.id //this is how u can get the inside properties.
//}
yourComboBox.ItemSource = Lookups;//setting item source to UI.
}
}
after you successfully bind the data with UI you can use SelectionChanged event of your combobox to do further logic as you require,
void MyComboBox_SelectionChanged(object sender, object args)
{
if(MyCombobox.SelectedIndex!=-1)
{
var mylookupId = (MyCombobox.SelectedItem as Lookup).id;// get your id and do further processing here.
}
}
I think this will be easy when using newtonsoft:
var dynamicObject = JObject.Parse(yourstring);
var list = new List<Lookup>();
//now you have a dynamic object containing an array.
//this should be doable with linq as well.
//note, the type is dynamic
foreach (dynamic thing in dynamicObject )
{
list.Add(new Lookup()
{
id = thing.fields.id,
SerialNumber = thing.fields.SerialNumber
});
}
disclaimer: not tested in any way ;-)
"fields": [
{
"field": {
"name": "SMS",
"value": "Yes"
}
},
{
"field": {
"name": "Email",
"value": ""
}
},
{
"field": {
"name": "Total",
"value": ""
}
},
]
I have tried to form the JSON format like above, so i formed the class like below. While serialization it does not return expected form, how can i achieve this one.
public class Test
{
public List<Field> fields;
}
public class Field
{
public string name { get; set; }
public string value { get; set; }
}
Response:
"fields": [{
"name": "SMS",
"value": "Yes"
}, {
"name": "Email",
"value": ""
},{
"name": "Total",
"value": ""
}]
Use this website http://json2csharp.com and generate all the classes automatically. Just copy-paste your json there.
You can customize resulting JSON object with anonymous types and LINQ. Please try this code:
var test = new Test {fields = new List<Field>()};
test.fields.Add(new Field {name = "f1", value = "v1"});
test.fields.Add(new Field {name = "f2", value = "v2"});
var json = JObject.FromObject(new { fields = test.fields.Select(f => new {field = f}).ToArray() })
.ToString();
A json variable would be:
{
"fields": [
{
"field": {
"name": "f1",
"value": "v1"
}
},
{
"field": {
"name": "f2",
"value": "v2"
}
}
]
}
You just missed a class level:
public class Test
{
public List<FieldHolder> fields;
}
public class FieldHolder
{
public Field field { get; set; }
}
public class Field
{
public string name { get; set; }
public string value { get; set; }
}