Deserialising JSON files in C# - c#

I keep getting following error:
Object reference not set to an instance of an object
This is my Json string in a file at C:\part_param.json
{
"part_parameters" : {
"bar_diameter" : 300.4,
"core_height" : 132,
"roughing_offset" : 0.3
}
}
and the code I am using is as follows:
public class PLMpartParameter
{
public class Parameters
{
public float bar_diameter;
public float core_height;
public float roughing_offset;
public Parameters(float barD, float coreH, float roughingO)
{
bar_diameter = barD;
core_height = coreH;
roughing_offset = roughingO;
}
}
public Parameters parameters;
public PLMpartParameter(Parameters param)
{
parameters = param;
}
}
public static void LoadJson()
{
using (System.IO.StreamReader r = new System.IO.StreamReader(#"C:\part_param.json"))
{
string json = r.ReadToEnd();
_logger.Info(string.Format("Read entire file complete. File Values: {0}", json));
try
{
PLMpartParameter part = Newtonsoft.Json.JsonConvert.DeserializeObject<PLMpartParameter>(json);
}
catch (Exception e)
{
_logger.Info(string.Format("Read Json failed {0}", e.Message));
}
}
What am I missing here?

I think the problem is your property is called 'parameters' but in your json it's 'part_parameters'.

You must add a JSON attribute above your property, so that your properties are recognized when deserializing your object.
you will find an example just below
public class Parameters
{
[JsonProperty("bar_diameter")]
public float bar_diameter;
[JsonProperty("core_height")]
public float core_height;
[JsonProperty("roughing_offset")]
public float roughing_offset;
public Parameters(float barD, float coreH, float roughingO)
{
bar_diameter = barD;
core_height = coreH;
roughing_offset = roughingO;
}
}

Quoting Prasad Telkikar's answer as that fixed it right away
Use json2csharp to get model for your json file, then deserialize your
json. You can use visual studio in build function to create class i.e.
Edit -> Paste special -> Paste JSON as Class
Here is class
> public class PartParameters {
> public double bar_diameter { get; set; }
> public int core_height { get; set; }
> public double roughing_offset { get; set; } }
>
> public class RootObject {
> public PartParameters part_parameters { get; set; } }
To deserialize, use below code
PLMpartParameter part =
Newtonsoft.Json.JsonConvert.DeserializeObject(json);
My final code looks like this, and its working!!
public class PartParameters
{
public double bar_diameter { get; set; }
public int core_height { get; set; }
public double roughing_offset { get; set; }
}
public class RootObject
{
public PartParameters part_parameters { get; set; }
}
public static void LoadJson()
{
using (System.IO.StreamReader r = new System.IO.StreamReader(#"C:\part_param.json"))
{
string json = r.ReadToEnd();
try
{
RootObject part = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(json);
_logger.Info(string.Format("list values : bardiameter: {0}, coreHeight: {1}, roughingOffset: {2}",
part.part_parameters.bar_diameter,part.part_parameters.core_height, part.part_parameters.roughing_offset));
}
catch (Exception e)
{
_logger.Info(string.Format("Read Json failed {0}", e.Message));
}
}
}

You have a few issues with your code:
You need to have default constructors for the classes (this is due to how serializers work with types - they are not going to understand your class-specific paramaterised constructor).
Your fields need to be settable properties (Just add {get;set;} and you should be good to go).
I would suggest you decorate the parameters property with [JsonProperty("part_parameters")] to get the deserialization
behaviour you're expecting.

Related

Protobuf-net serialization of object (generic) throws error No serializer defined for type: System.Object

How to serialize a generic(T) object which can hold any type of data (int / string / DateTime) using Protobuf-net. Following is my code
[ProtoContract]
public class E1DataRow
{
[ProtoMember(1)]
public List<NameValue> NameValues { get; set; }
public E1DataRow()
{
NameValues = new List<NameValue>();
}
public void AddNameValue(string name, object obj, Type type)
{
NameValues.Add(new NameValue { Name = name, Value = obj, ValueType = type });
}
}
[ProtoContract]
public class NameValue
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public object Value { get; set; }
[ProtoMember(3)]
public Type ValueType { get; set; }
}
serialization code
var e1DataRows = new List<E1DataRow>();
/*
Code to add Data rows to e1DataRows
e1DataRow.AddNameValue(column.ColumnName, value, column.TypeOfColumn);
*/
using (var stream = File.OpenWrite(path))
{
Serializer.Serialize(stream, e1DataRows);
}
[ProtoMember(2, DynamicType = true)]
public object Value { get; set; }
Above code throws following error (DynamicType = true)
ProtoMemberAttribute.DynamicType' is obsolete: 'Reference-tracking and dynamic-type are not currently implemented in this build; they may be reinstated later; this is partly due to doubts over whether the features are adviseable, and partly over confidence in testing all the scenarios (it takes time; that time hasn't get happened); feedback is invited'
It would be great if you can help with how to serialize a List using Protobug-net. Thanks...
You may want to look at https://github.com/dotarj/protobuf-net-data - this isn't affiliated with protobuf-net (different authors etc), but it uses protobuf-net to perform serialization of DataTable and data-readers, so it might do what you want ready-made.
As for implementing it yourself:
protobuf-net does not support object (or dynamic, which is just a fancy way of spelling object), fundamentally. There are ways of working around this, essentially similar to the oneof handling in protobuf - i.e. something like (in protobuf terms):
message Foo {
oneof payload {
string payload_string = 1;
bool payload_bool = 2;
int32 payload_int32 = 3;
float payload_float = 4;
// etc
}
}
This is pretty easy to put together in protobuf-net thanks to "conditional serialization", which means you could do something like:
public object Value { get; set; }
[ProtoMember(1)]
public string ValueString
{
get => (string)Value;
set => Value = value;
}
public bool ShouldSerializeValueString()
=> Value is string;
[ProtoMember(2)]
public string ValueBoolean
{
get => (bool)Value;
set => Value = value;
}
public bool ShouldSerializeValueBoolean()
=> Value is string;
// etc
If on c# >= 4 you might want to try the following:
[ProtoContract]
public class E1DataRow
{
[ProtoMember(1)]
public List<NameValue<dynamic>> NameValues { get; set; }
public E1DataRow()
{
NameValues = new List<NameValue<dynamic>>();
}
public void AddNameValue(string name, dynamic obj)
{
NameValues.Add(new NameValue<dynamic> { Name = name, Value = obj });
}
}
public class NameValue<T>
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public T Value { get; set; }
[ProtoMember(3)]
public Type ValueType { get { return Value.GetType(); } }
}
Not sure if Protobuf-net likes the List<NameValue<dynamic>>, can't test it as of now.
ProtoMember(3) at ValueType possibly is not necessary as of being readonly anyways.

C# JsonConvert.DeserializeObject returns 0?

I am attempting to write a Windows form app that pulls player data via a text file formatted in json but have run into issues. Any data I try to deserialize returns a 0 value in my text box.... I am new to coding and stuck, any help would be appreciated.
My code is as follows:
string json = System.IO.File.ReadAllText("textfile");
StatsCounts newStats = JsonConvert.DeserializeObject<StatsCounts>(json);
earningsTextBox.Text = Convert.ToString(newStats.earnings);
My Json Class Formating:
public class StatsCounts
{
public int earnings { get; set; }
public int firsts { get; set; }
public int seconds { get; set; }
public int thirds { get; set; }
public int starts { get; set; }
}
public class RootObject
{
public StatsCounts statsCounts { get; set; }
}
And my text file formatting:
{
"statsCounts": {
"earnings": 4576702,
"firsts": 131,
"seconds": 102,
"thirds": 80,
"starts": 590
}
}
You need to deserialize for the type RootObject, not StatsCounts, so it should read:
static void Main(string[] args)
{
var rootObject = JsonConvert.DeserializeObject<RootObject>("{\n \"statsCounts\": {\n \"earnings\": 4576702,\n \"firsts\": 131,\n \"seconds\": 102,\n \"thirds\": 80,\n \"starts\": 590\n }\n}");
var a = Convert.ToString(rootObject.statsCounts.earnings);
}
You have the correct classes, but you're not using them. Use RootObject to deserialize into.
Change to this:
var results = JsonConvert.DeserializeObject<RootObject>(json);
StatsCounts newStats = results.statsCounts;

DeserializeObject<T>(string s) in generic method in C# using Newtonsoft.JSON is not working

Currently I am just returning the json string to corresponding file from where Test1() is called and Deserializing there as ResponseClass r = JsonConvert.DeserializeObject(response_json)
Send part I forget to make a class [Serializable].Its working fine now.
Part1:
public class Movie
{
public string Name { get; set; }
public string Description { get; set; }
public string Classification { get; set; }
public string Studio { get; set; }
public DateTime? ReleaseDate { get; set; }
public List<string> Genres{ get; set; }
}
public class ResponseClass
{
public string SuccessStatus{ get; set; }
public string next_link { get; set; }
}
private void Test1<T,Q>()
{
string json = #"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
//Here making network call with above json and getting correct response_josn
Q response_obj = JsonConvert.DeserializeObject<Q>(reponse_json);
print(response_obj);
}
I am calling Test1() as follows on button click:
Test1<Movie, ResponseClass>();
For the above example I am getting print log as ClassName+Movie (T FullName).
I want to deserialize the string into that class. How to achieve that?
Part2 : If I have class as:
[Serializable]
public class Movie
{
public string Name;
public string Description;
public string Classification;
public string Studio;
public DateTime ReleaseDate;
public SubClass subClass;
public List<SubClass> lsubclass;
}
[Serializable] //This was the mistake.
public class SubClass
{
public string a;
public string b;
public List<string> ReleaseCountries;
}
private Movie createValidMovieJson()
{
Movie m = new Movie();
SubClass sc = new SubClass();
sc.a = "aaa";
sc.b = "bbb";
sc.ReleaseCountries = new List<string>();
sc.ReleaseCountries.Add("Japan");
sc.ReleaseCountries.Add("India");
List<SubClass> lsC = new List<SubClass>();
lsC.Add(sc);
lsC.Add(sc);
m.Name = "Bad Boys";
m.Studio = "Pixa";
m.subClass = sc;
m.lsubclass = lsC;
Debug.Log(JsonUtility.ToJson(m)); // value n log = {"Name":"Bad Boys","Description":"","Classification":"","Studio":"Pixa"}
return m;
}
JsonUtility is returning empty value in place of subclass after using ToJson() as shown in above function.
Based on the screenshot you added I think you are expecting to be able to treat the deserialized type as a Movie. This is the way to achieve that:
var movie = JsonConvert.DeserializeObject<Movie>(json);
Currently your deserialized object is being treated as type T - which could be anything since you have no generic type constraints on your method.
Like I said in the comment section, JsonUtility should do it.
I just replaced T m = JsonConvert.DeserializeObject(json); with T
m = JsonUtility.FromJson(json); it gives an error
ArgumentException: JSON parse error: Missing a name for object member.
Your json is invalid for JsonUtility. I believe you are using ' instead of ". This is why you are getting this error.
Use the function below to generate a valid json:
void createValidMovieJson()
{
Movie m = new Movie();
m.Name = "Bad Boys";
m.ReleaseCountries = new List<string>();
m.ReleaseCountries.Add("Japan");
m.Studio = "Pixa";
Debug.Log(JsonUtility.ToJson(m));
}
You will get:
{"Name":"Bad Boys","Description":"","Classification":"","Studio":"Pixa","ReleaseCountries":["Japan"]}
When ecaped for testing, you will get:
{\"Name\":\"Bad Boys\",\"Description\":\"\",\"Classification\":\"\",\"Studio\":\"Pixa\",\"ReleaseCountries\":[\"Japan\"]}
For JsonUtility to work, you must add [Serializable] to the class and remove { get; set; } from them class variables.
If your goal is to convert any json to any data type then you have to return generic type then use Convert.ChangeType to convert it to that type.
It should look something like this:
// Use this for initialization
void Start()
{
string json = "{\"Name\":\"Bad Boys\",\"Description\":\"\",\"Classification\":\"\",\"Studio\":\"Pixa\",\"ReleaseCountries\":[\"Japan\"]}";
Movie movie = Load<Movie>(json);
print(movie.Name);
}
[Serializable]
public class Movie
{
public string Name;
public string Description;
public string Classification;
public string Studio;
public DateTime? ReleaseDate;
public List<string> ReleaseCountries;
}
private T Load<T>(string json)
{
object resultValue = JsonUtility.FromJson<T>(json);
return (T)Convert.ChangeType(resultValue, typeof(T));
}

ServiceStack.Text deserialize string into single object null reference

I have the following code. With JSON.NET it works fine where I can deserialize the string into the CustomMaker object. With ServiceStack.Text I get null. I've tried doing { get; set; } and removing and adding the constructor.
With JSON.NET it simply worked like JsonConvert.DeserializeObject(xString);
Any idea why this does not work with ServiceStack.Text?
static void Main(string[] args) {
string xString = "{\"error\":\"Invalid token 1 #556264\"}";
Console.WriteLine(xString);
CustomMaker xSLBM = TypeSerializer.DeserializeFromString<CustomMaker>(xString);
Console.WriteLine(string.IsNullOrWhiteSpace(xSLBM.error) ? "error is null" : xSLBM.error);
Console.ReadLine();
}
[Serializable]
public class CustomMaker {
public int UserID;
public String error;
public CustomMaker() { }
}
edit: This code also produces null:
static void Main(string[] args) {
JsConfig.IncludePublicFields = true;
string xString = "{\"error\":\"Invalid token 1 #556264\"}";
Console.WriteLine(xString);
CustomMaker xSLBM = TypeSerializer.DeserializeFromString<CustomMaker>(xString);
Console.WriteLine(string.IsNullOrWhiteSpace(xSLBM.error) ? "error is null" : xSLBM.error);
Console.ReadLine();
}
[Serializable]
public class CustomMaker {
public CustomMaker() { }
public int UserID { get; set; }
public String error { get; set; }
}
By Default ServiceStack only serializes public properties so you could refactor your DTO to include properties, e.g:
public class CustomMaker {
public int UserID { get; set; }
public String error { get; set; }
}
Or if you wanted to serialize public fields you can specify this with:
JsConfig.IncludePublicFields = true;
Also you need to use the JsonSerializer class, e.g:
CustomMaker xSLBM = JsonSerializer.DeserializeFromString<CustomMaker>(xString);
Or string.ToJson() or T.FromJson<T>(string) extension methods, e.g:
CustomMaker xSLBM = xString.FromJson<CustomMaker>();
The TypeSerializer class is only for serializing/deserializing the JSV Format, not JSON.

Add root element to json serialization in C#

I am creating a webservice to interact with a JSON API.
This API needs me to set a root element in the string, but I just cannot get this to happen.
The place where it all happens - right now just made to just show me the json output:
public static string CreateServiceChange(ServiceChange change)
{
string json = JsonConvert.SerializeObject(change);
return json;
}
This is the ServiceChange class:
public class ServiceChange
{
[JsonProperty("email")]
public string requesterEmail { get; set; }
[JsonProperty("description_html")]
public string descriptionHtml { get; set; }
[JsonProperty("subject")]
public string subject { get; set; }
[JsonProperty("change_type")]
public int changeType { get; set; }
}
And the method binding those two together:
public string copyTicketToChange(int ticketId)
{
HelpdeskTicket.TicketResponseActual ticket = getHelpdeskTicket(ticketId);
ServiceChange change = new ServiceChange();
change.descriptionHtml = ticket.Response.DescriptionHtml;
change.requesterEmail = ticket.Response.Email;
change.subject = ticket.Response.Subject;
change.changeType = 1;
string Response = Dal.CreateServiceChange(change);
return Response;
}
The json output looks like this right now:
{"email":"test#test.com","description_html":"This is a test","subject":"Testing","change_type":1}
And the expected output:
{ "itil_change": {"email":"test#test.com","description_html":"This is a test","subject":"Testing","change_type":1}}
How can I achieve this?
Wrap your ServiceChange into another object and serialize it:
public class ServiceChangeWrapper
{
public ServiceChange itil_change { get; set; }
}
...
public static string CreateServiceChange(ServiceChange change)
{
ServiceChangeWrapper wrapper = new ServiceChangeWrapper { itil_change = change};
string json = JsonConvert.SerializeObject(wrapper);
return json;
}

Categories