We are currently developping an application using XmlSerializer from the .NET framework.
Here is the structure of our classes:
[XmlInclude(typeof(TimeLineMediaClass))]
[XmlInclude(typeof(ImageMediaClass))]
public abstract class MediaClass
{
public string filename { get; set; }
public string maintitle { get; set; }
public string subtitle { get; set; }
public Type typeOfMedia { get; set; }
}
[XmlInclude(typeof(AudioMediaClass))]
[XmlInclude(typeof(VideoMediaClass))]
public abstract class TimeLineMediaClass : MediaClass
{
public string title { get; set; }
public TimeSpan length { get; set; }
public string genre { get; set; }
}
public class AudioMediaClass : TimeLineMediaClass
{
public string artist { get; set; }
}
public class VideoMediaClass : TimeLineMediaClass
{
public string director { get; set; }
public string studios { get; set; }
}
public class ImageMediaClass : MediaClass
{
public string width { get; set; }
public string height { get; set; }
}
Several medias of different types are added to a List, and this is what we want to serialize.
This is how the serializer is instanciated:
XmlSerializer serializer = new XmlSerializer(typeof(List<MediaClass>));
But when we launch the program and try to serialize, an exception is thrown, stating that "AudioMediaClass was not expected".
EDIT: A few things were missing in the code I have provided. I have added some corrections in it ; more details in comments.
You need to decorate your MediaClass class with
[XmlInclude(typeof(TimeLineMediaClass))]
In your example above, you have the casing wrong on TimelineMediaClass meaning the sample won't compile for me. If you remove it, or if you do have a different class with this name, you'll get the error you describe.
Once you correct the casing, it should work - it does for me [noting that I also had to remove the attribute for ImageMediaClass which also doesn't exist in your sample].
I copy your code, and run removing [XmlInclude(typeof(ImageMediaClass))] and correcting this attribute: [XmlInclude(typeof(TimelineMediaClass))] to [XmlInclude(typeof(TimeLineMediaClass))]. Now, running your code, it works fine.
Related
​Using VS 2019, Dot Net Core, Azure Function. HttpTrigger.
I've worked with JSON files previously in .Net Desktop and Server app dev. So, don't know what's happening in Azure and with Newtonsoft. When I try and dump the value of wht.YourName.last, I get the error,
Object reference not set to an instance of an object
which confuses me because in my other programming with System.Text.Json, if I have a class model for a JSON file structure that has a child, the usual function call I use, which is JsonSerializer.Deserialize<jsonclass>(jsonstring), it has no problem setting up the child of the parent parent (reference below, class structure).
Is there a difference between the two function implementations, JsonConvert.DeserializeObject and JsonSerializer.Deserialize?
All of the code samples I've seen seem for Newtonsoft's method seem straight forward as its counterpart in dot net, which doesn't require me to have to do any pre-initalization of the NameBlock class/object.
Hope I explained that well enough considering my brain is kind of fried learning Azure.
Here is my deserialization code using Newtonsoft's method:
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
WebhookTest wht = JsonConvert.DeserializeObject<WebhookTest>(requestBody);
Raw dump of httprequest.Body:
{
"FormID":"1081011",
"UniqueID":"178165183",
"support_request":"",
"your_name":{
"first":"Testy",
"last":"Tester"
},
"email":"jxxxx#gxxxcxxxaxxxxxxxx.com",
"phone":"(111) 867-5309",
"upload_a_file_optional":"",
"request_details":"Testing latest revision of Azure function that deserializes JSON data into a class object."
}
This is what my class structure looks like:
public class NameBlock
{
public string first { get; set; }
public string last { get; set; }
}
public class WebhookTest
{
public string FormID { get; set; }
public string UniqueID { get; set; }
public string SupportRequest { get; set; }
public NameBlock YourName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
[JsonProperty("Uploadafile(optional)")]
public string UploadafileOptional { get; set; }
public string RequestDetails { get; set; }
}
The reason for the error Object reference not set to an instance of an object is the code can't find wht.YourName(because wht.YourName is null). Please change your class structure to:
public class NameBlock
{
public string first { get; set; }
public string last { get; set; }
}
public class WebhookTest
{
public string FormID { get; set; }
public string UniqueID { get; set; }
public string SupportRequest { get; set; }
[JsonProperty(PropertyName = "your_name")]
public NameBlock YourName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
[JsonProperty("Uploadafile(optional)")]
public string UploadafileOptional { get; set; }
public string RequestDetails { get; set; }
}
Just add a line [JsonProperty(PropertyName = "your_name")]
By the way:
When we use System.Text.Json, it will relate your_name(in request json) with YourName(in class structure) automatically according to hump law. But when we use Newtonsoft.Json, it can't do it. So it can't relate your_name with YourName. We need to add [JsonProperty(PropertyName = "your_name")] to let the code know how to relate the two properties.
I have been trying to get this json to deserialize for two days now using RestSharp. I have gone through the RestSharp github site, looked at countless examples, and spent much time here on Stack Overflow to try and find the answer to no avail. My code had previously worked perfectly but the vendor changed their API version and I was forced to do an update to keep using the application for my legal practice. My json is as follows(client info has been removed and replaced with generic info):
{
"data":[
{
"id":1035117666,
"client":
{
"id":905422394,
"name":"client1"
},
"display_number":"11-00012",
"description":"General",
"practice_area":
{
"id":4269978,
"name":"Business"
},
"status":"Open",
"open_date":"2011-12-14",
"close_date":null,
"billing_method":"hourly"
},
{
"id":1035117768,
"client":
{
"id":905422506,
"name":"client2"
},
"display_number":"12-00037",
"description":"HOA",
"practice_area":
{
"id":4269978,
"name":"Business"
},
"status":"Open",
"open_date":"2012-08-07",
"close_date":null,
"billing_method":"hourly"
}
],
"meta":
{
"paging":
{
"next":"https://app.goclio.com/api/v4/matters.json?fields=id%2C+client%7Bid%2C+name%7D%2C+display_number%2C+description%2C+practice_area%7Bid%2C+name%7D%2C+status%2C+open_date%2C+close_date%2C+billing_method&limit=2&page_token=BAh7BjoLb2Zmc2V0aQc%3D--b1ea3eba20c8acefbcdfc7868debd1e0ee630c64&status=Open"
},
"records":91
}
}
I built the following schema within my c# code:
public class MatterList
{
public List<Matter> matters { get; set; }
public Meta meta { get; set; }
}
public class Meta
{
public Paging paging { get; set; }
public int records { get; set; }
}
public class Paging
{
public string previous { get; set; }
public string next { get; set; }
}
[DeserializeAs(Name = "data")]
public class Matter
{
public int id { get; set; }
public Client client { get; set; }
public string display_number { get; set; }
public string description { get; set; }
public PracticeArea practice_area { get; set; }
public string status { get; set; }
public DateTime open_date { get; set; }
public DateTime close_date { get; set; }
public string billing_method { get; set; }
public string type = "matter";
}
public class PracticeArea
{
public int id { get; set; }
public string name { get; set; }
}
public class Client
{
public int id { get; set; }
public string name { get; set; }
}
When I run the RestSharp deserialize method I am sending the result to an object of type MatterList using the following line of code
MatterList matterList = jsonHandler.Deserialize<MatterList>(response);
I have so far attempted to deserialize without the Meta or Paging POCO classes with the accompanying change to the MatterList class (taking out the Meta property).
I have tried with and without the [DeserializeAs(Name="data")] directive.
I have tried to set the RootElement of the json response prior to deserialization.
I have tried to shorthand the deserialization by combining it with the Execute request code
IRestResponse<MatterList> matterList = client.Execute<MatterList>(request);
I have created a container class called MatterContainer which I placed between MatterList and Matter classes in the schema:
public class MatterList
{
public List<MatterContainer> matters { get; set; }
}
public class MatterContainer
{
public Matter matter { get; set; }
}
public class Matter
{
public int id { get; set; }
public Client client { get; set; }
public string display_number { get; set; }
public string description { get; set; }
public PracticeArea practice_area { get; set; }
public string status { get; set; }
public DateTime open_date { get; set; }
public DateTime close_date { get; set; }
public string billing_method { get; set; }
public string type = "matter";
}
I know I am getting the json response back from the server correctly so my request is proper and MatterList is not null after deserialization. The problem is that I cannot get the deserialization to actually populate the List matters within the MatterList class.
I have been looking at this off and on for two days and cannot get past this hurdle. If anyone sees what I did wrong I would greatly appreciate the insight, I am at a point where I cannot progress further with my application.
Thanks!
I think your [DeserializeAs(Name = "data")] attribute is in the wrong place. Try putting it in the root class instead:
public class MatterList
{
[DeserializeAs(Name = "data")]
public List<Matter> matters { get; set; }
public Meta meta { get; set; }
}
alternatively, try renameing that property to data
I have a xml format in following format mentioned below:-
<JobRunnerPluginStaus PluginName="JobRun">
<JobstepStatus>
<JobStatus StepNumber="1" StepStatus="Done"/>
<JobStatus StepNumber="2" StepStatus="Started" />
</JobstepStatus>
</JobRunnerPluginStaus>
I want to get it converted to following class object using Generics and Reflection.
I want to convert the attributes to simple type(PluginName) and the nested property to a list object(JobstepStatus).
public class JobRunnerPluginStaus
{
public List<JobStatus> JobstepStatus { get; set; }
public string PluginName { get; set; }
}
public class JobStatus
{
public int StepNumber { get; set; }
public string StepStatus { get; set; }
}
I mostly use sites like: https://xmltocsharp.azurewebsites.net/
to do the dirty work for me.
Below is how your class hierarchy would look like:
[XmlRoot(ElementName="JobStatus")]
public class JobStatus {
[XmlAttribute(AttributeName="StepNumber")]
public string StepNumber { get; set; }
[XmlAttribute(AttributeName="StepStatus")]
public string StepStatus { get; set; }
}
[XmlRoot(ElementName="JobstepStatus")]
public class JobstepStatus {
[XmlElement(ElementName="JobStatus")]
public List<JobStatus> JobStatus { get; set; }
}
[XmlRoot(ElementName="JobRunnerPluginStaus")]
public class JobRunnerPluginStaus {
[XmlElement(ElementName="JobstepStatus")]
public JobstepStatus JobstepStatus { get; set; }
[XmlAttribute(AttributeName="PluginName")]
public string PluginName { get; set; }
}
I have the following code but unable to deserialize, can you see where I'm going wrong? It only catch the first record on the first array item.
[XmlRootAttribute("Booking")]
public class Reservation
{
[XmlArray("Included")]
[XmlArrayItem("Meals")]
public Meals[] Food { get; set; }
[XmlArrayItem("Drinks")]
public Drinks[] Drink { get; set; }
}
public class Meals
{
[XmlAttribute("Breakfast")]
public string Breakfast { get; set; }
[XmlAttribute("Lunch")]
public string Lunch { get; set; }
[XmlAttribute("Dinner")]
public string Dinner { get; set; }
}
public class Drinks
{
[XmlAttribute("Soft")]
public string Softs { get; set; }
[XmlAttribute("Beer")]
public string Beer { get; set; }
[XmlAttribute("Wine")]
public string Wine { get; set; }
}
Here's the associated XML
<?xml version="1.0" standalone="yes"?>
<Booking>
<Included>
<Meals
Breakfast="True"
Lunch="True"
Dinner="False">
</Meals>
<Drinks
Soft="True"
Beer="False"
Wine="False">
</Drinks>
</Included>
<Included>
<Meals
Breakfast="True"
Lunch="False"
Dinner="False">
</Meals>
<Drinks
Soft="True"
Beer="True"
Wine="True">
</Drinks>
</Included>
</Booking>
I'm a bit of a newbie so any help would be great, unfortunately after trawling through the many exmaples you already have online I still haven't been able to figure this out.
Use the following example and apply this syntax in ListItem array,
[XmlType("device_list")]
[Serializable]
public class DeviceList {
[XmlAttribute]
public string type { get; set; }
[XmlElement( "item" )]
public ListItem[] items { get; set; }
}
following link contains all the syntax & attributes
http://msdn.microsoft.com/en-us/library/2baksw0z.aspx
I see no obvious way your class structure could be matched to the XML document. The underlying organizations seem to be quite different.
The following class hierarchy could be easily deserialized from the XML document you provide (assuming your document covers the general case) :
[Serializable]
[XmlRoot("Booking")]
public class Booking : List<Included>
{
}
[Serializable]
public class Included
{
public Meals Meals { get; set; }
public Drinks Drinks { get; set; }
}
public class Meals
{
[XmlAttribute("Breakfast")]
public string Breakfast { get; set; }
[XmlAttribute("Lunch")]
public string Lunch { get; set; }
[XmlAttribute("Dinner")]
public string Dinner { get; set; }
}
public class Drinks
{
[XmlAttribute("Soft")]
public string Softs { get; set; }
[XmlAttribute("Beer")]
public string Beer { get; set; }
[XmlAttribute("Wine")]
public string Wine { get; set; }
}
Then, deserialization code would be : (serializedObject is the string containing your serialized object)
XmlSerializer ser = new XmlSerializer(typeof (string));
XmlReader reader = XmlTextReader.Create(new StringReader(serializedObject));
var myBooking = ser.Deserialize(reader) as Booking;
I am setting a class in C# to hold a response that I will be receiving from a web service call. I'm using RestSharp to handle the calling / parsing of the JSON data.
The web service documentation describes the response as:
OUTPUT: JSON object similar to example below.
{
"response":"[success] or [failed]",
"messages":"Process succeeded.",
"logonkey":"[logon key]",
"tokenkey":"[security token]",
"reccount":"1",
"filelist":
{
"fileid":"12345",
"status":"N",
"filename":"data.tar",
"fulfilled":"2012-06-15"
}
}
My question is how can I define the filelist array element in my class?
I was thinking something like this:
public class Files
{
public string Response { get; set; }
public string Messages { get; set; }
public string LogonKey { get; set; }
public string TokenKey { get; set; }
public int RecordCount { get; set; }
public List<FileList>
}
public class FileList
{
public string FileID { get; set; }
public string Status { get; set; }
public string Filename { get; set; }
public DateTime Fulfilled { get; set; }
}
However, I'm having a problem with the "public List" statement.
Any suggestions on the best way to handle this scenario would be appreciated.
Also you forgot to give it a name, for example try this
public List<FileList> MyFavouriteList {get;set;}.
A proprety is declared like this "access modifier", "Type", "identifier(or name)", "getter and setter".
The filelist in JSON sample doesn't look like list of objects. Instead it is a single object.
You could try,
public class Files
{
public string Response { get; set; }
public string Messages { get; set; }
public string LogonKey { get; set; }
public string TokenKey { get; set; }
public int RecordCount { get; set; }
public FileList File {get; set; }
}
If you are sure the filelist in JSON is really list of object, you could try,
public List<FileList> Files = new List<FileList>();