I have an object who as a property that is a Json Schema (JSchema).
JSchema aSchema;
object foo = new {propA = "x", schema = aSchema};
However, when this is serialized:
string str = JsonConvert.SerializeObject(foo);
The JSchema object is serialized along with all its other properties ... and not a clean Json Schema, like the output of its ToString() which just emits the Json Schema string.
What I want is the schema property serialized as a Json Schema object like this:
{
"propA": "x",
"schema": {
"id": "",
"description": "",
"definitions": {
"number": {
"type": "number"
},
"string": {
"type": "string"
}
},
"properties": {
"title": {
"title": "Title",
"type": "string"
}
}
}
}
How would you do this?
public class Number
{
public string type { get; set; }
}
public class String
{
public string type { get; set; }
}
public class Definitions
{
public Number number { get; set; }
public String #string { get; set; }
}
public class Title
{
public string title { get; set; }
public string type { get; set; }
}
public class Properties
{
public Title title { get; set; }
}
public class Schema
{
public string id { get; set; }
public string description { get; set; }
public Definitions definitions { get; set; }
public Properties properties { get; set; }
}
public class RootObject
{
public string propA { get; set; }
public Schema schema { get; set; }
}
Serialize method
dynamic coll = new
{
Root = new RootObject()
{
propA = "x",
schema = new Schema
{
id = "",
description = "",
definitions = new Definitions()
{
number = new Number()
{
type = "number"
},
#string = new String()
{
type = "number"
}
},
properties = new Properties ()
{
title = new Title ()
{
title = "Title",
type = "string"
}
}
}
}
};
var output = JsonConvert.SerializeObject(coll);
Fiddler: https://dotnetfiddle.net/f2wG2G
Update
var jsonSchemaGenerator = new JsonSchemaGenerator();
var myType = typeof(RootObject);
var schema = jsonSchemaGenerator.Generate(myType);
schema.Id = "";
schema.Description = "";
schema.Title = myType.Name;
Fiddler: https://dotnetfiddle.net/FwJX69
Related
I want to create a windows console application to read Json api data, retrieve all the type="folder" items and then save the data to database. How to access to the properties of the Json data?
Json data format:
{
asset:{
path:{
Children:[
0:{
id:xxxx,
type: folder
},
1:{
id:xxxxx,
type: folder
},
2:{
id:xxxx,
type: page
}
...
]
}
},
success:ok
}
FolderModel:
public class FolderModel
{
public string id { get; set; }
public string type { get; set; }
}
//main
static void Main(string[] args)
{
Task T = new Task(ApiCall);
T.Start();
Console.ReadLine();
}
//apicall
static async void ApiCall()
{
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync("https://apiurl/");
response.EnsureSuccessStatusCode();
using (HttpContent content = response.Content)
{
string responseBody = await response.Content.ReadAsStringAsync();
var items = JsonConvert.DeserializeObject<FolderModel>(responseBody);
//items id and type are null here. how to retrieve those information ??
}
}
}
Your JSON and c# model are not identical first you need to create models to deserialize json
public class FolderModel
{
public string id { get; set; }
public string type { get; set; }
}
public class Path
{
public List<FolderModel> Children { get; set; }
}
public class Asset
{
public Path path { get; set; }
}
public class ResponseModel
{
public Asset asset { get; set; }
public string Success { get; set; }
}
Now you can access deserialize using
var response = JsonConvert.DeserializeObject<ResponseModel>(responseBody);
Now you can acess properties using linq or foreach loop
Using Linq
var folderResponse = response.asset.path.Children.Select(x => new
FolderModel { id = x.id, type = x.type });
//or you can access like this if you need to get all fields
var folderResponse = response.asset.path.Children.Select(x => x);
ForEach
foreach (var folder in response.asset.path.Children)
{
//folder.id
//folder.type
}
JSON to parse
{
"asset": {
"path": {
"Children": [
{
"id": "xxxx",
"type": "folder"
},
{
"id": "xxxxx",
"type": "folder"
},
{
"id": "xxxx",
"type": "page"
}
]
}
},
"success": "ok"
}
I have the following WebCleint to call a Restful web service inside my .net console application:-
try
{
using (WebClient wc = new WebClient())
{
wc.Encoding = Encoding.UTF8;
string url = "https://*****/paged?hapikey=*********&properties=website&properties=i_scan&limit=2";//web service url
string tempurl = url.Trim();
var json = wc.DownloadString(tempurl);//get the json
Marketing ipfd = JsonConvert.DeserializeObject<Marketing>(json);//deserialize
}
}
catch (Exception e)
{
//code goes here..
}
where i am using JSON.Net to Deserialize the json object, which will be as follow:-
{
"has-more": true,
"offset": 622438650,
"companies": [
{
"portalId": *******,
"companyId": *****,
"isDeleted": false,
"properties": {
"website": {
"value": "****.net",
"timestamp": 1520938239457,
"source": "CALCULATED",
"sourceId": null,
"versions": [
{
"name": "website",
"value": "*****.net",
"timestamp": 1520938239457,
"source": "CALCULATED",
"sourceVid": [
731938234
]
}
]
}
},
"additionalDomains": [],
"stateChanges": [],
"mergeAudits": []
},
{
"portalId": ******,
"companyId": ******,
"isDeleted": false,
"properties": {
"website": {
"value": "****.***.***",
"timestamp": 1512488590073,
"source": "CALCULATED",
"sourceId": null,
"versions": [
{
"name": "website",
"value": "****.***8.****",
"timestamp": 1512488590073,
"source": "CALCULATED",
"sourceVid": []
}
]
},
"i_scan": {
"value": "Yes",
"timestamp": 1543409493459,
"source": "******",
"sourceId": "**************",
"versions": [
{
"name": "i_scan",
"value": "Yes",
"timestamp": 1543409493459,
"sourceId": *****",
"source": "CRM_UI",
"sourceVid": [],
"requestId": "******"
}
]
}
},
"additionalDomains": [],
"stateChanges": [],
"mergeAudits": []
}
]
}
Here are my classes:-
public class Marketing
{
public Companies companies { get; set; }
}
public class Companies
{
public IList<string> companyId { get; set; }
public IList<Properties> properties { get; set; }
}
public class Properties
{
public IList<Website> website { get; set; }
public IList<I_Scan> i_scan { get; set; }
}
public class Website
{
public string value { get; set; }
}
public class i_Scan
{
public string value { get; set; }
}
but currently i am getting this exception, when i try to de-serialize the JSON object:-
Newtonsoft.Json.JsonSerializationException was caught
HResult=-2146233088
Message=Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'MMarketing.Companies' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'companies', line 1, position 49.
Source=Newtonsoft.Json
StackTrace:
so i am not sure why JSON.NET is unable to do the Deserialize correctly, as in my case the classes are compatible with the returned json object??
At a first glance it looks like you switched two properties in Making them a List and vice versa.
public class Marketing
{
public List<Companies> companies { get; set; }
}
Is "companies": [ in the json, while "companyId": *****, is the id as a string, not array. Properties is not an array also, but the property versions of properties is.
public class Companies
{
public string companyId { get; set; }
public Properties properties { get; set; }
}
If I'm coming to json blind I like to use http://json2csharp.com/ to generate my class structure for me
public class Version
{
public string name { get; set; }
public string value { get; set; }
public object timestamp { get; set; }
public string source { get; set; }
public List<object> sourceVid { get; set; }
}
public class Website
{
public string value { get; set; }
public object timestamp { get; set; }
public string source { get; set; }
public object sourceId { get; set; }
public List<Version> versions { get; set; }
}
public class Version2
{
public string name { get; set; }
public string value { get; set; }
public long timestamp { get; set; }
public int sourceId { get; set; }
public string source { get; set; }
public List<object> sourceVid { get; set; }
public int requestId { get; set; }
}
public class IScan
{
public string value { get; set; }
public long timestamp { get; set; }
public int source { get; set; }
public int sourceId { get; set; }
public List<Version2> versions { get; set; }
}
public class Properties
{
public Website website { get; set; }
public IScan i_scan { get; set; }
}
public class Company
{
public int portalId { get; set; }
public int companyId { get; set; }
public bool isDeleted { get; set; }
public Properties properties { get; set; }
public List<object> additionalDomains { get; set; }
public List<object> stateChanges { get; set; }
public List<object> mergeAudits { get; set; }
}
public class Marketing
{
public bool has_more { get; set; }
public int offset { get; set; }
public List<Company> companies { get; set; }
}
var result = JsonConvert.DeserializeObject<Marketing>(json);
not really sure if I'm asking this in the correct manner. But I am doing a project for my university with CRM systems and API's.
Now I found Flurl to help me do my HTTP request. and it works great until I try and do a get all accounts to my free developer account to salesforce (i added some test accounts). The JSON I receive is this:
{
"objectDescribe": {
"activateable": false,
"createable": true,
"custom": false,
"customSetting": false,
"deletable": true,
"deprecatedAndHidden": false,
"feedEnabled": true,
"hasSubtypes": false,
"isSubtype": false,
"keyPrefix": "001",
"label": "Account",
"labelPlural": "Accounts",
"layoutable": true,
"mergeable": true,
"mruEnabled": true,
"name": "Account",
"queryable": true,
"replicateable": true,
"retrieveable": true,
"searchable": true,
"triggerable": true,
"undeletable": true,
"updateable": true,
"urls": {
"compactLayouts": "/services/data/v39.0/sobjects/Account/describe/compactLayouts",
"rowTemplate": "/services/data/v39.0/sobjects/Account/{ID}",
"approvalLayouts": "/services/data/v39.0/sobjects/Account/describe/approvalLayouts",
"defaultValues": "/services/data/v39.0/sobjects/Account/defaultValues?recordTypeId&fields",
"listviews": "/services/data/v39.0/sobjects/Account/listviews",
"describe": "/services/data/v39.0/sobjects/Account/describe",
"quickActions": "/services/data/v39.0/sobjects/Account/quickActions",
"layouts": "/services/data/v39.0/sobjects/Account/describe/layouts",
"sobject": "/services/data/v39.0/sobjects/Account"
}
},
"recentItems": [
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it9T3AAI"
},
"Id": "0015800000it9T3AAI",
"Name": "Test 5"
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it8eAAAQ"
},
"Id": "0015800000it8eAAAQ",
"Name": "Test 4"
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it8dbAAA"
},
"Id": "0015800000it8dbAAA",
"Name": "Test 3"
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it8dHAAQ"
},
"Id": "0015800000it8dHAAQ",
"Name": "Test 2"
},
{
"attributes": {
"type": "Account",
"url": "/services/data/v39.0/sobjects/Account/0015800000it8ciAAA"
},
"Id": "0015800000it8ciAAA",
"Name": "Test 1"
}
]
}
and the error I receive is the following:
Request to https://eu6.salesforce.com/services/data/v39.0/sobjects/Account/ failed.
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[InHollandCRMAPI.Models.AccountItem]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'objectDescribe', line 1, position 18.
I also found this link on here:
Parsing from json to object using FLURL
but I can't seem to recreate this with my model:
public class AccountItem : ICRMItem
{
public Describe[] ObjectDescribe { get; set; }
public List<Recent> recentItems { get; set; }
public class Recent
{
public Attributes[] Attributes { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
public class Describe
{
public bool activateable { get; set; }
public bool createable { get; set; }
public bool custom { get; set; }
public bool customSetting { get; set; }
public bool deletable { get; set; }
public bool deprecatedAndHidden { get; set; }
public bool feedEnabled { get; set; }
public bool hasSubtypes { get; set; }
public bool isSubtype { get; set; }
public string keyPrefix { get; set; }
public string label { get; set; }
public string labelPlural { get; set; }
public bool layoutable { get; set; }
public bool mergeable { get; set; }
public bool mruEnabled { get; set; }
public string name { get; set; }
public bool queryable { get; set; }
public bool replicateable { get; set; }
public bool retrieveable { get; set; }
public bool searchable { get; set; }
public bool triggerable { get; set; }
public bool undeletable { get; set; }
public bool updateable { get; set; }
public Urls[] urls { get; set; }
}
}
and at last this is how de Deserialize is in my code
response = request.GetAsync();
responseData = await response.ReceiveJson<T>().ConfigureAwait(true);
Edit my controller class where the requests come in:
[HttpGet("{CRM}")]
public IEnumerable<ICRMItem> Get(string CRM)
{
if(CRM == "SalesForce")
{
ICRMService AccountGetAll = new AccountService();
var Account = AccountGetAll.With<AccountItem>().GetAll().ResponseData();
return Account;
}
}
After #Todd Menier his changes
as my response in Todd's message shamefully it didn't do the trick. and i still get this exception message.
Request to https://eu6.salesforce.com/services/data/v39.0/sobjects/Account/ ailed. Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type
'System.Collections.Generic.IEnumerable`1[InHollandCRMAPI.Models.AccountItem]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>)
that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'objectDescribe', line 1, position 18.
Edit
Todd Menier asked me for the path my code takes so here it is:
After I do my call it comes in my controller
ICRMService AccountGetAll = new AccountService();
var Account = AccountGetAll.With<AccountItem>().GetAll().ResponseData();
return Account;
Where after it goes into my service:
public ICRMServiceWithResource<T> With<T>(bool beta = false) where T : ICRMItem
{
var Uri = "https://eu6.salesforce.com/services/data/v39.0/";
return new SalesForceServiceWithResource<T>()
{
Resource = Resources.Resources.GetResource<T>(),
Uri = Uri
};
}
then it gets the Recources
public class Resources
{
public const string Accounts = "sobjects/Account/";
public static string GetResource<T>() where T : ICRMItem
{
var type = typeof(T);
if (type == typeof(AccountItem)) return Accounts;
and it gets into my GetAll function
public ICRMResponse<IEnumerable<T>> GetAll()
{
return Get<IEnumerable<T>>();
}
as you see it goes to a get function
private ICRMResponse<TOut> Get<TOut>(string id = "")
{
return DoRequest<TOut>(Resource + id, "GET", null).Result;
}
from where it goes into the DoRequest:
public async Task<ICRMResponse<T>> DoRequest<T>(string url, string method, object body)
{
ICRMResponse<T> result;
try
{
GetCRM(AppConfig.Key);
var request = Authorise(url);
Task<HttpResponseMessage> response;
T responseData;
switch (method.ToLower())
{
case "post":
if (body == null)
{
throw new ArgumentNullException("body");
}
response = request.PostJsonAsync(body);
responseData = await response.ReceiveJson<T>().ConfigureAwait(false);
break;
case "get":
response = request.GetAsync();
responseData = await response.ReceiveJson<T>().ConfigureAwait(true);
break;
from where it breaks and shows the message as state before
i'll check back around 16:00 GMT+1 or else Tuesday morning hope i gave you everything you needed
In your C# model, urls is an array, but it is not an array in the JSON representation; it is an object.
You didn't post the definition of your Urls class, but I'm going to guess it looks like this:
public class Urls
{
public string compactLayouts { get; set; }
public string rowTemplate { get; set; }
public string approvalLayouts { get; set; }
public string defaultValues { get; set; }
public string listviews { get; set; }
public string describe { get; set; }
public string quickActions { get; set; }
public string layouts { get; set; }
public string sobject { get; set; }
}
The JSON is returning a single object that looks like this, not a collection of them. So, in your Describe class, just drop the array and define it like this:
public Urls urls { get; set; }
UPDATE:
I didn't see this at first but there's a similar problem with objectDescribe and attributes. Those aren't arrays either, so don't define them that way in your C# model. Here's a summary of all changes:
public class AccountItem : ICRMItem
{
public Describe ObjectDescribe { get; set; }
...
public class Recent
{
public Attributes Attributes { get; set; }
...
}
public class Describe
{
...
public Urls urls { get; set; }
}
}
Soo, I just fixed the Error. Was trying to get a List of all Accounts. but salesforce already Lists (part) the Accounts for you.
The Issue was IEnumerable in the GetAll() function (wich works great for most CRM systems) but if you wanna get this done you'd need to change the IEnumerable<T> to just T and that would be the quick fix for SalesForce
The Next step for me is to generate a List of accounts with all account info (as most GetAll's work with CRM API's).
TL;DR
public ICRMResponse<IEnumerable<T>> GetAll()
{
return Get<IEnumerable<T>>();
}
should be
public ICRMResponse<T> GetAll() //Technicly isn't a GetAll But a Get
{
return DoRequest<T>(Resource, "GET", null).Result;
}
This is a Fix to this post not a fix to my eventual wish but I'll close this topic because else we will go off topic
I want to DeserializeObject of x-www-form-urlencoded string
public void TestData1(Stream data)
{
StreamReader sr = new StreamReader(data);
string strJson = sr.ReadToEnd();
var response = Newtonsoft.Json.JsonConvert.DeserializeObject<Recipe>strJson);
}
Below is my Request application/x-www-form-urlencoded
title=test&recipe_accessories=%5B+++++%7B+++++%22accessories_id%22%3A%22ingr001%22+++++++%7D%2C++++++%7B+++++%22ingredient_id%22%3A%22ingr001%22+++++%7D%2C++++++%7B+++++%22ingredient_id%22%3A%22ingr001%22+++++%7D+++%5D&recipe_ingredient=%5B+++++%7B+++++%22ingredient_id%22%3A%22ingr001%22%2C+++++%22ingredient_qty_num%22%3A%222.5%22%2C+++++%22ingredient_qty_unit%22%3A%22cup%22++++++++++++%7D%2C++++++%7B+++++%22ingredient_id%22%3A%22ingr001%22%2C+++++%22ingredient_qty_num%22%3A%222.5%22%2C+++++%22ingredient_qty_unit%22%3A%22cup%22++++++++++++%7D%2C++++++%7B+++++%22ingredient_id%22%3A%22ingr001%22%2C+++++%22ingredient_qty_num%22%3A%222.5%22%2C+++++%22ingredient_qty_unit%22%3A%22cup%22++++++++++++%7D+++%5D&recipe_img=%5B+++++%22http%3A%2F%2Fcontrol%2Fimages%2Ftest.jpg%22%2C+++++%22http%3A%2F%2Fcontrol%2Fimages%2Ftest.jpg%22%2C+++++%22http%3A%2F%2Fcontrol%2Fimages%2Ftest.jpg%22%2C+++++%22http%3A%2F%2Fcontrol%2Fimages%2Ftest.jpg%22%2C+++++%22http%3A%2F%2Fcontrol%2Fimages%2Ftest.jpg%22+++%5D
Error
Error parsing boolean value. Path '', line 1, position 1.'. See server logs for more details. The exception stack trace is: at Json.JsonTextReader.ParseTrue()
Actual Json in Raw format
{
"recipe_img": [
"http://control/images/test.jpg",
"http://control/images/test.jpg",
"http://control/images/test.jpg",
"http://control/images/test.jpg",
"http://control/images/test.jpg"
],
"recipe_ingredient": [
{
"ingredient_id":"ingr001",
"ingredient_qty_num":"2.5",
"ingredient_qty_unit":"cup"
},
{
"ingredient_id":"ingr001",
"ingredient_qty_num":"2.5",
"ingredient_qty_unit":"cup"
},
{
"ingredient_id":"ingr001",
"ingredient_qty_num":"2.5",
"ingredient_qty_unit":"cup"
}
],
"recipe_accessories": [
{
"accessories_id":"ingr001"
},
{
"ingredient_id":"ingr001"
},
{
"ingredient_id":"ingr001"
}
],
"title": "Hello WOrld",
}
When I use the BodyStyle = WebMessageBodyStyle.Bare and pass the Json in RAW format it works fine.
It will not work when the BodyStyle = WebMessageBodyStyle.WrappedRequest
Here is my Class
public class Recipe
{
public IList<string> recipe_img { get; set; }
public IList<RecipeIngredient> recipe_ingredient { get; set; }
public IList<RecipeAccessory> recipe_accessories { get; set; }
public string title { get; set; }
}
public class RecipeIngredient
{
public string ingredient_id { get; set; }
public string ingredient_qty_num { get; set; }
public string ingredient_qty_unit { get; set; }
}
public class RecipeAccessory
{
public string accessories_id { get; set; }
public string ingredient_id { get; set; }
}
I am new in ASP.NET world and I am trying to achieve following.
I need to serialize API of this format
{
"results": {
"profile": {
"firstname": "John,
"lastname": "Newman",
},
"credit": {
"amount": 30
}
}
}
The problem is that I don't know how to model my data. I need a results object, which contains 2 other objects (profile and credit). You can see some sample code below.
public class Results
{
public class Data {
public Profile profile { get; set; }
public Credit credit {get; set; }
}
public class Profile {
public String firstname {get; set; }
public String lastname { get; set; }
}
public class Credit {
public int amount { get; set; }
}
}
static void Main(string[] args)
{
Results results= new Results
{
Data = new Data{
Profile = new Profile {
firstname = "John",
lastname = "Newman"
},
Credit = new Credit {
balance = "30"
}
}
};
string json = JsonConvert.SerializeObject(results);
Console.WriteLine(json);
}
The error I get is "Member Data cannot be initialized. It is not a field or property. What am I doing wrong?
Try this instead:
public class Profile
{
public String firstname { get; set; }
public String lastname { get; set; }
}
public class Credit
{
public int amount { get; set; }
}
public class Result
{
public Profile profile { get; set; }
public Credit credit { get; set; }
}
public class Wrapper
{
public Result results { get; set; }
}
static void Main(string[] args)
{
var wrapper = new Wrapper
{
results = new Result
{
profile = new Profile
{
firstname = "John",
lastname = "Newman"
},
credit = new Credit
{
amount = 30
}
}
};
string json = JsonConvert.SerializeObject(wrapper);
Console.WriteLine(json);
}
Try this :
static void Main(string[]args) {
Base results = new Base() {
Results = new Results() {
profile = new Profile() {
firstname = "John",
lastname = "Newman"
},
credit = new Credit() {
amount = 30
}
}
};
string json = JsonConvert.SerializeObject(results);
Console.WriteLine(json);
Console.ReadLine();
}
public class Base {
public Results Results {get;set;}
}
public class Results{
public Profile profile {get;set;}
public Credit credit {get;set;}
}
public class Profile{
public String firstname {get;set;}
public String lastname {get;set;}
}
public class Credit{
public int amount {get;set;}
}
Class Base wraps Results class to get the required JSON structure.