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);
Related
I'm creating an Api using .Net Core 3.1 in which I need one property input as JSON in the controller, something like:
{
"name": "test",
"JSONData": { "roles": ["data1", "data2"] }
}
so that I can define the request something like:
public class MyRequest
{
public string Name { get; set;}
public JSON JSONData { get; set; }
}
I'm thinking of having it as a string and using Serialize/Deserialize it if we cannot have it as a "JSON" data type.
Is there a way to have a property as JSON type from both request and response?
I've just tried with JsonElement and could see it works; only one issue that the property is not showing up from the swagger UI. So the request is like:
public class MyRequest
{
public string Name { get; set;}
public JsonElement JSONData { get; set; }
}
I have a JSON response like the following
{
"msg": "1",
"code": "2",
"data": [
{
"a": "3",
"b": "4"
}
],
"ts": "5"
}
I would like to create a generic class
public class DTWSResponse<T>
{
public string msg { get; set; }
public string code { get; set; }
public T data { get; set; }
public long ts { get; set; }
}
so this class will map each of the variable. But the data portion can be generic, i.e. it might have different format rather than 2 variables a and b.
So I create another class
public class DTProf
{
public string a { get; set; }
public string b { get; set; }
}
and in my code, I call as
DTWSResponse<DTProf> prof = JsonConvert.DeserializeObject<DTWSResponse<DTProf>>(json);
But I'm getting the following error
An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code
Additional information: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'DataTransfer.DTProfile' 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 'data', line 1, position 40.
Any ideas?
Use the correct type for the generic type argument
the JSON shown has a collection for the data property. So use a collection as the type argument. No need to change the generic class.
var prof = JsonConvert.DeserializeObject<DTWSResponse<IList<DTProf>>>(json);
var a = prof.data[0].a;
Make data a generic list and you should be fine...
public class DTWSResponse<T>
{
public string msg { get; set; }
public string code { get; set; }
public IList<T> data { get; set; }
public long ts { get; set; }
}
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.
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.