I have extracted the below json from ETH. So this is a valid json.
"networks": {
"18": {
"address": "0x478a2763d239b60206006437f5154dad59fef909"
}
}
Trying to parse using:
dynamic Obj = JsonConvert.DeserializeObject(".... json string .....");
Obj.Networks.18.address; // Error
Obj.SelectToken("networks.18.address"); // Null
I can't even compile because a label name cannot start with number.
May I know what is the correct way to access the address?
You can create a model that represents the data
public class RootObject {
public Dictionary<string, network> networks { get; set; }
}
public class network {
public string address { get; set; }
}
And use that to access the desired information
var data = JsonConvert.DeserializeObject<RootObject>(".... json string .....");
var address = data.networks["18"].address;
because of the syntax conflict, string Dictionary was used as a workaround to be able to access the key value pair.
Related
I a class that looks like so:
public class AccountAddress
{
[Key]
public int accountNumber { get; set; }
public int rowNumber { get; set; }
public string civicaddress { get; set; }
public AccountAddress()
{
//Default constructor
}
}
There is a rest API that returns a List of AccountAddress as oData that looks like this to a variable "result":
{
"#odata.context":"http://localhost:52139/odata/$metadata#WEB_V_CIVIC_ADDRESS/Values.Classes.Entities.AccountAddress","value":[
{
"#odata.type":"#Values.Classes.Entities.AccountAddress","accountNumber":123456,"rowNumber":0,"civicaddress":"123 FAKE EAST DRIVE"
},{
"#odata.type":"#Values.Classes.Entities.AccountAddress","accountNumber":123457,"rowNumber":0,"civicaddress":"123 FAKE WEST DRIVE"
}
]
}
When I try to use:
var addressAccountLookup = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AccountAddress>>(result);
I get an error
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[ATPublicTAX.Regina.ca.Values.Classes.Entities.AccountAddress]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
Any help on this would be greatly appreciated.
Thanks.
You're passing the entire object to your deserialization method. You need to pass only the array, which is what it's asking you to do.
JArray array = (JArray) result["value"];
var addressAccountLookup = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AccountAddress>>(array);
Something like that should work.
The solution that I got to work is create a class:
private class oDataResponse<T>
{
public List<T> Value { get; set; }
}
Then deserialize like this:
var oDataRespone = Newtonsoft.Json.JsonConvert.DeserializeObject<oDataResponse<AccountAddress>>(result);
I have the following JSON:
[{
"theme-my-login":
{
"latest_version":"6.4.7",
"last_updated":"2017-01-06T18:14:00.000Z",
"popular":true,
"vulnerabilities":
[
{
"id":6043,
"title":"Theme My Login 6.3.9 - Local File Inclusion",
"created_at":"2014-08-01T10:58:35.000Z",
"updated_at":"2015-05-15T13:47:24.000Z",
"published_date":null,
"references":
{
"url":["http://packetstormsecurity.com/files/127302/","http://seclists.org/fulldisclosure/2014/Jun/172","http://www.securityfocus.com/bid/68254/","https://security.dxw.com/advisories/lfi-in-theme-my-login/"]
},
"vuln_type":"LFI",
"fixed_in":"6.3.10"
}
]
}
},{
"other-item":
{
"latest_version":"6.4.7",
"last_updated":"2017-01-06T18:14:00.000Z",
"popular":true,
"vulnerabilities":
[
{
"id":6043,
"title":"Theme My Login 6.3.9 - Local File Inclusion",
"created_at":"2014-08-01T10:58:35.000Z",
"updated_at":"2015-05-15T13:47:24.000Z",
"published_date":null,
"references":
{
"url":["http://packetstormsecurity.com/files/127302/","http://seclists.org/fulldisclosure/2014/Jun/172","http://www.securityfocus.com/bid/68254/","https://security.dxw.com/advisories/lfi-in-theme-my-login/"]
},
"vuln_type":"LFI",
"fixed_in":"6.3.10"
}
]
}
}]
json2csharp says the object model should look like this, but that's clearly not correct
public class References
{
public List<string> url { get; set; }
}
public class Vulnerability
{
public int id { get; set; }
public string title { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
public object published_date { get; set; }
public References references { get; set; }
public string vuln_type { get; set; }
public string fixed_in { get; set; }
}
public class ThemeMyLogin
{
public string latest_version { get; set; }
public DateTime last_updated { get; set; }
public bool popular { get; set; }
public List<Vulnerability> vulnerabilities { get; set; }
}
public class RootObject
{
public ThemeMyLogin __invalid_name__theme-my-login { get; set; }
}
that I am trying to deserialise into c# classes using Json.NET, but as the top level item doesn't have a traditional name:value pair (the name effectively is "theme-my-login" and the value is the object), it's not deserialising.
Any pointers on how I can get this to deserialise? Do I need to use a custom deserialiser?
The reason I cannot use a dictionary as suggested in How can I parse a JSON string that would cause illegal C# identifiers? is that I need the value "theme-my-login" as one of the values in my model as it defines the object. I have added a second item into the json as this will be a list of items. I previously only included one to show the item structure.
You need to deserialize to List<Dictionary<string, ThemeMyLogin>> like so:
var root = JsonConvert.DeserializeObject<List<Dictionary<string, ThemeMyLogin>>>(json);
The code-generation site http://json2csharp.com/ has some limitations of which you need to be aware:
The JSON standard allows for two types of container:
The array, which is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
The object, which is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace).
If your root container is an array, http://json2csharp.com/ will auto-generate a RootObject model to deserialize each object in the array. To actually deserialize the entire array you need to deserialize to a collection of root objects such as a List<RootObject>. See Serialization Guide: IEnumerable, Lists, and Arrays.
When a JSON property corresponds to an invalid c# identifier, http://json2csharp.com/ will "helpfully" add a property to the containing type that looks like this:
public PropertyType __invalid_name__my-invalid-identifier { get; set; }
Of course this will not compile, so you need to notice any __invalid_name properties and manually fix the generated code. Options for doing this include those covered in How can I parse a JSON string that would cause illegal C# identifiers? and elsewhere:
If the property name is fixed and known in advance, rename the c# property to something valid consistent with your coding conventions and mark it with [JsonProperty("my-invalid-identifier")]. (From the answer by ken2k).
If the containing type consists entirely of variable property names with a fixed schema for their values corresponding to some type T, replace the containing type with a Dictionary<string, T>. (From the answer by L.B.)
If the containing object has a mixture of fixed and variable properties, see Deserialize json with known and unknown fields or How to deserialize a child object with dynamic (numeric) key names?.
You seem to have encountered both limitations. Working sample .Net fiddle.
Ok there are a lot of questions and answers with this, if you know an exact duplicate of this please point me there but I am too dumb to understand how to make it work.
I want to add a worker to a job and everything is good until reaches ModelState. Here are the steps I am doing.
Filling the form
I submit the form and console breakpoint.
Name = "test", Description = "test",
worker = {Id: 21, FirstName: "Will", LastName: "Smith", Job: null}
Angular service in console
jobs = {Name: "test", Description: "test", worker: {…}}
Not sure why the dots in the brackets.
Reaches API method and fails modelstate.
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
In browser console I get:
Message:"The request is invalid."
ModelState:job.worker.Id:["Cannot deserialize the current JSON object (e.g. {…N object. Path 'worker.Id', line 1, position 16."]
Full error message from ModelState is:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'System.Collections.Generic.ICollection`1[TestRotaru.Models.Worker]'
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) 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 'worker.Id', line 1, position
51.
Alright so far this is like a duplicate question but I tried few things and I don't understand some things in answers.
I tried to decorate my models with attributes such as:
These on top of the class
//[Serializable]
//[DataContract(IsReference = true)]
//[JsonObject(MemberSerialization.OptIn)]
On properties
//[JsonProperty]
Now the thing I have no clue and I don't understand:
var dict = JsonConvert.DeserializeObject
<Dictionary<string, Item>>(*Where this string comes from*);
This is just an example, I am concerned about that string in brackets not about if is a Dictionary or something else.
Here is my method:
[ResponseType(typeof(Job))]
public IHttpActionResult PostJob(Job job)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
job.DueDate = DateTime.Now;
db.Job.Add(job);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = job.Id }, job);
}
In all the answers about this everyone has that random json string in the round brackets... From where I am supposed to have that?
Here are my models:
Job Model:
//[Serializable]
//[DataContract(IsReference = true)]
//[Serializable()]
//[JsonObject(MemberSerialization.OptIn)]
public class Job
{
[JsonProperty]
public int Id { get; set; }
[JsonProperty]
public string Name { get; set; }
[JsonProperty]
public string Description { get; set; }
[JsonProperty]
public DateTime DueDate { get; set; }
[JsonProperty]
public bool IsCompleted { get; set; }
//[JsonProperty]
//[System.Runtime.Serialization.IgnoreDataMember]
public virtual ICollection<Worker> Worker { get; set; }
}
Worker Model:
//[Serializable]
//[DataContract(IsReference = true)]
//[JsonObject(MemberSerialization.OptIn)]
public class Worker
{
[JsonProperty]
public int Id { get; set; }
[JsonProperty]
public string FirstName { get; set; }
[JsonProperty]
public string LastName { get; set; }
//[JsonProperty]
//[System.Runtime.Serialization.IgnoreDataMember]
public virtual ICollection<Job> Job { get; set; }
}
Angular component and service:
add(Name: string, Description: string, worker): void {
this.jobsServices.addJob({Name, Description, worker } as Jobs)
.subscribe(jobs => {
this.jobs.push(jobs);
});
}
addJob(jobs: Jobs): Observable<Jobs> {
return this.http.post<Jobs>(this.apiURL, jobs, httpOptions);
}
div class="row">
<div class="col-md-12">
<label class="labelInputs">Select Worker</label><br>
<select [(ngModel)]="worker" class="form-control">
<option [value]="0">Select Worker</option>
<option *ngFor="let worker of workers" [ngValue]="worker">{{worker.FirstName}} {{worker.LastName}}</option>
</select>
</div>
<button class="brn btn-lg btn-block btn-change" (click)="add(name.value, desc.value, worker)">Add Job</button>
Alright is a long question but I wanted to prove myself I did my research and I just didn't thrown the error message and ask for solutions but this is really getting on my nerves.
Since I am posting relational data and my console shows ModelState{job.worker.Id: [,…]} how do I deserialize this? Plus my ModelState shows the worker as null when reaches the API, I can guess because is not converted from json, but worth to know.
Thank you for help.
So, the issue is that on your SPA you are sending worker as a single object and your API expects a list (array) of workers. Now I don't know what you want.. but you can either fix it by changing your API model to expect a single worker or change your SPA to send a list of workers. That no one can answer you.. depends on your app's requirements. But, my best guess is that a Job might have several workers. So:
Api Models (mostly the same.. just removed the attributes and changed Worker to Workers):
public class Job
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime DueDate { get; set; }
public bool IsCompleted { get; set; }
public virtual ICollection<Worker> Workers { get; set; }
}
public class Worker
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
// This is an "array". your spa needs to send in this format.
public virtual ICollection<Job> Job { get; set; }
}
Spa Code:
export class Job {
id: int;
name: string;
// other fields here..
// Workers property that maps API model
workers: Array<Worker>;
constructor(id: int, name: string [other fields..]) {
this.id = id;
// and so on..
}
public addWorker(worker) {
this.workers.push(worker);
}
}
export class Worker {
id: int;
firstName: string;
// other fields here.. No need for array of jobs here!
}
With this model, you can do this before calling the API (on add function):
add(Name: string, Description: string, worker: Worker): void {
// creates a job using constructor
const job = new Job(name, description);
// add Job via function(can even be more complex and add validation and so on..)
job.addWorker(worker);
this.jobsServices.addJob(job)
.subscribe(jobs => {
this.jobs.push(jobs);
});
}
This will call the api with a json like this:
{
"id": 1,
"name": "some name",
[ other fields..]
"workers": [
{ "id:" 1, "name": "some worker name" }
]
}
In servicestack, I am trying to process a webhook which sends the following JSON body to a service stack endpoint:
{
"action": "actionType1",
"api_version": "1.00",
"data": {
"id": "a8d316b8-10a7-4440-a836-9bd354f656db",
//VARIABLE other properties / structure
}
}
Which I am trying to map to the following request object:
[Route("/public/Webhookhandler", HttpVerbs.Post)]
public class MyCustomRequst
{
public string action { get; set; }
public string api_version { get; set; }
public string data { get; set; } //Will be the remaining JSON
}
However, when the service stack framework processes this - the value in "data" is the correct part of the JSON body, but with all of the quotes removed - so it is no longer valid.
I have tried to override the serialization for the whole request object using something like this:
JsConfig<MyCustomRequst>.DeSerializeFn = DeserializeMyRequestDto;
public MyCustomRequst DeserializeMyRequestDto(string rawBody)
{
var result = rawBody.FromJson<MyCustomRequst>();
return result
}
But even in this case, the value of the "rawBody" variable is still the correct JSON data but with all the quotes removed, e.g.
{
action:actionType1,
api_version:1.00,
data:{id:a8d316b8-10a7-4440-a836-9bd354f656db}
}
Am I doing something wrong here? I am unsure whether I am trying to make service stack do something it is not intended to do, or whether I am missing something that would make this work.
Any help would be appreciated :-)
Your DTO should closely match the shape of the JSON, if it's always a flat object you can use a string Dictionary, e.g:
[Route("/public/Webhookhandler", HttpVerbs.Post)]
public class MyCustomRequst
{
public string action { get; set; }
public string api_version { get; set; }
public Dictionary<string,string> data { get; set; }
}
If it's a more nested object structure you can use a JsonObject for a more flexible API to parse dynamically.
I'm trying to deserialize the following JSON into an object in my Win 8 app:
{
"success":true,
"pharmacies":[
{
"name":"Test Pharmacy",
"phone":null,
"description":"sample description",
"pharmacyid":"1234567",
"pic":"/1341864197.png",
"address":"211 Warren St., #205",
"city":"Newark",
"state":"NJ",
"zipcode":"07103",
"delivery":true,
"dob_check":false,
"name_check":false,
"can_pickup":true,
"barcode_template":"9999999XX"
}
]
}
This is the model I'm using:
public class PharmacyList
{
public List<Pharmacy> pharmacies { get; set; }
}
public class Pharmacy
{
public string pharmacyid { get; set; }
public string name { get; set; }
public string phone { get; set; }
}
And here is the code I'm using to de-serialize
json = await results.Content.ReadAsStringAsync();
List<PharmacyList> p = JsonConvert.DeserializeObject<List<PharmacyList>>(json);
I'm getting the following exception:
: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[PharmacyHC.Models.PharmacyList]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
Am I trying to deserialize into the wrong type or should I format the JSON as it comes back from the API differently?
I just realized the dumb mistake I made. p should have been declared as type PharmacyList instead of a list object since the class declaration for PharmacyList contained a List object already.
List<PharmacyList> p = JsonConvert.DeserializeObject<List<PharmacyList>>(json);
it should have been
PharmacyList p = JsonConvert.DeserializeObject<PharmacyList>(json);