I want to serialize an object where one of the attributes maps to 2 xml elements. I'm creating a program that interfaces with a wifi account management system through its RESTful API. Here is the object that I need to serialize to create the account:
[XmlRoot("record")]
class XmlUser
{
[XmlElement("login")]
public string Username { get; set; }
[XmlElement("password")]
[XmlElement("password_confirmation")]
public string Password { get; set; }
// Other attributes...
}
Having two XmlElementAttributes on one attribute throws an exception, saying I need to add the XmlChoiceIdentifierAttribute. I don't need to deserialize the object. Should I abandon this method, and just use a XmlWriter?
You can do,
[XmlElement("password")]
public string Password { get; set; }
[XmlElement("password_confirmation")]
public string PasswordConfirmation{ get { return Password;} set; }
Related
I'm writing a console app to retrieve JSON data from a 3rd party API. I have no control over the API data structures or functionality.
Several of the calls I make will return multiple 'pages' of data. The data is a collection of objects of a certain type e.g. User.
I have created classes in my app to match the various data types from the API.
public class User
{
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
}
public class FooBar
{
[JsonProperty("foo")]
public string Foo { get; set; }
[JsonProperty("bar")]
public string Bar { get; set; }
}
The API response is always in the same format for these calls. While the actual object types in the "data" array will differ depending on what call has been made.
{
"paging":{"page":1},
"data":[{<object>}, {<object>}, {<object>},...]
}
I have created a class to try to deserialize these. The dynamic[] type for the Data property is for illustrative purposes and I am happy to change it if there is a better approach.
public class ApiResponseObject
{
[JsonProperty("paging")]
public Paging PagingInfo { get; set; }
[JsonProperty("data")]
public dynamic[] Data { get; set; }
}
And I would like to have the Data collection resolve to the appropriate type for the objects it contains. e.g.
string userJson = "{\"paging\":{\"page\":1},\"data\":[{\"id\":1,\"first_name\":\"Joe\",\"last_name\":\"Bloggs\"},{\"id\":2,\"first_name\":\"Jane\",\"last_name\":\"Doe\"}]}"; // json string would come from API
string foobarJson = "{\"paging\":{\"page\":1},\"data\":[{\"foo\":\"Lorem\",\"bar\":\"Ipsum\"},{\"foo\":\"Dolor\",\"bar\":\"Amet\"}]}";
var userResponse = JsonConvert.DeserializeObject<ApiResponseObject>(userJson);
var foobarResponse = JsonConvert.DeserializeObject<ApiResponseObject>(foobarJson);
The deserialization succeeds but the Data collection is of type JObject and cannot be cast into the correct type (User, FooBar).
I am trying to avoid having to write specific response object classes for each request if possible.
I will know what type of object I am expecting in the collection when I am requesting it so I could pass that type to the deserializer but I'm not clear on how to achieve that in this particular scenario.
Something like the below psuedo code would be ideal.
var userResponse = JsonConvert.DeserializeObject<ApiResponseObject<User>>(userJson);
Thanks for your help!
You can use the generic type T, like this :
public class ApiResponseObject<T>
{
[JsonProperty("paging")]
public Paging PagingInfo { get; set; }
[JsonProperty("data")]
public T[] Data { get; set; }
}
I have a JSON string and I need some help to deserialize it.
At the moment my result is always null.
var results = JsonConvert.DeserializeObject<Root>(json);
// result == null
My JSON:
{"First":{"FirstData1":{"date":"2018-01-01","hint":""},
"FirstData2":{"date":"2018-01-06","hint":""}},
"Second":{"SecondData1":{"date":"2018-01-01","hint":""},
"SecondData2":{"date":"2018-01-06","hint":""}}}....
Only on the last Node there is actual property naming...
MyObjects
public class Root
{
public IEnumerable<TempModelRoot> Value{ get; set; }
}
public class TempModelRoot
{
[JsonProperty("Key")]
public string Key { get; set; }
[JsonProperty("Value")]
public List<TempModelChild> Value { get; set; }
}
public class TempModelChild
{
[JsonProperty("Key")]
public string Key { get; set; }
[JsonProperty("Value")]
public TempModelInfo Value { get; set; }
}
public class TempModelInfo
{
[JsonProperty("date")]
public string date { get; set; }
[JsonProperty("hint")]
public string hint { get; set; }
}
In addition to #MX D 's answer, I want to add two more useful model generator sites, which takes JSON as an input and gives appropriate model classes.
Json2Csahrp
JsonUtils
Use, whenever you find difficult to generate complex model classes.
Most likely you are having a mismatch between the model you are trying to deserialize to, and the actual expected model based of the json itself.
A easy way to resolve this is by using a tool such as Quick Types Model Generator(unafiliated) which allows you to generate C# models based upon a provided json file.
After generation you can compare and/or replace your models with the generated models.
To spot and resolve the issue with your model.
Case:
I receive a JSON string from third-party server, containing a list of objects.
e.g.
[{"foo": "bar", "someotherfield": "somevalue"}, {etc}, {etc}]
I have a C# class like,
public class MyObject
{
public string A { get; set; }
public string B { get; set; }
}
Now, I want to use JsonConvert.DeserializeObject, but so that it maps "foo" to A and so forth. How would I go about doing this?
You can use the JsonProperty attribute.
[JsonProperty("foo")]
public string A { get; set; }
You can use the JsonPropertyAttribute decorated on the property, giving it the name of the parameter it should find in the JSON message. You can also use a custom JsonConverter, if you do not wish to use an attribute.
I am having issues with understanding how to make this happen.
Basically we have an API, the user sends a JSON of the format:
{
"Profile":[
{
"Name":"Joe",
"Last":"Doe",
"Client":{
"ClientId":"1",
"Product":"Apple",
"Message":"Peter likes apples"
},
"Date":"2012-02-14"
}
]
}
I have a class called Profile with parameters Name, Last, and an object as one of its members called Client as well as property Date.
Something like this:
public class Profile {
public string Name {get; set;}
public string Last {get; set;}
public Client client {get; set;}
public DateTime dDate {get; set;}
}
So basically, I am not sure how to grab the JSON and then map it to my object.
Any help with "helping" me understand would be much appreciated.
You can use Json.NET to deserialize your json string as (with some modifications to your classes)
var yourObject = JsonConvert.DeserializeObject<Root>(jsonstring);
public class Root
{
public Profile[] Profile;
}
public class Profile
{
public string Name { get; set; }
public string Last { get; set; }
public Client Client { get; set; }
public DateTime Date { get; set; }
}
public class Client
{
public int ClientId;
public string Product;
public string Message;
}
You can use a JSON library for this, for example Newtonsoft.Json which is free. It will map json to your types automatically.
Sample:
public static T Deserialize<T>(string json)
{
Newtonsoft.Json.JsonSerializer s = new JsonSerializer();
return s.Deserialize<T>(new JsonTextReader(new StringReader(json)));
}
There is also a NuGet package available.
Easiest way I know is to use JSON.Net by newtonsoft.
To make it easier to understand, I always make matching classes in C# with the same name.
Then its easier to deserialize it.
As an example, if it is an array of objects in js, it will map to a list of object with the same names in C#.
As for the date time, its a bit tricky.
Id do the client side validation and Datetime.tryParse in the serverside, itll take care of the dashes or slashes.
var serializer = new JavaScriptSerializer();
List<abc> abcList = serializer.Deserialize<List<abc>>(PassedInJsonString);
I know this is a long time question, but I would like to add one more option, which does not use third party libraries, and only uses stock .Net libraries, and is available from .Net Core 3.1 onwards.
First of all, I leave a link to the official Microsoft documentation (where you will find examples on how to serialize and deserialize json strings): https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to
Let's build on your example. We have our starting json string:
{
"Profile":[
{
"Name":"Joe",
"Last":"Doe",
"Client":{
"ClientId":"1",
"Product":"Apple",
"Message":"Peter likes apples"
},
"Date":"2012-02-14"
}
]
}
If we build a data structure that can hold that definition, it would be something like:
public class Root
{
public List<Profile> Profile { get; set; }
}
public class Profile
{
public string Name { get; set; }
public string Last { get; set; }
public Client Client { get; set; }
public string Date { get; set; }
}
public class Client
{
public string ClientId { get; set; }
public string Product { get; set; }
public string Message { get; set; }
}
Now, and finally the answer to how to deserialize a json string into a particular object without third party libraries:
Root root = JsonSerializer.Deserialize<Root>(json);
Where json is the variable that contains your json string.
I add another link of interest, the official documentation of the Deserialize(...) method: https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer.deserialize
Something that is really useful is the exception that can be thrown, JsonException: https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonexception
DataContractJsonSerializer does the job, but it uses more sophisticated format for DateTime serialization.
Assume I have a C# class like this:
[XmlRoot("floors")]
public class FloorCollection
{
[XmlElement("floor")]
public Floor[] Floors { get; set; }
}
And I want to serialize it and send to a REST API using WCF. But before sending I need adding an attribute to the floors node in this way: <floors type="array">...</floors>
Any idea?
Just add the type attribute into your collection class:
[XmlRoot("floors")]
public class FloorCollection
{
[XmlAttribute("type")]
public string Type { get; set; }
[XmlElement("floor")]
public Floor[] Floors { get; set; }
}
If you mean adding that without the business code knowing about it, then you'll probably have to use Message Inspectors to modify the message before it is sent.