This question already has answers here:
Exception parsing json with System.Text.Json.Serialization
(3 answers)
Closed 2 years ago.
I am trying to use the System.Text.Json.Serialization namespace to deserialize the text within a JSON file into an Object named Note, to then access its properties. With the later intent to read-in multiple Note objects, to then store in a List for example.
There don't seem to be many examples on the usage of this namespace, other than within the DOTNET docs https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to
This is my attempt based on the examples given. Which throws the error shown below, if you know what I'm doing wrong please let me know, thanks.
class Note
{
public DateTime currentDate { get; set; }
public string summary { get; set; }
public Note(DateTime _date, string _sum)
{
currentDate = _date;
summary = _sum;
}
}
class Program
{
static void Main(string[] args)
{
//Write json data
string path = #"D:\Documents\Projects\Visual Projects\Notes Data\ThingsDone.json";
DateTime date = DateTime.Now;
string givenNote = "summary text";
Note completeNote = new Note(date, givenNote);
string serialString = JsonSerializer.Serialize(completeNote);
File.WriteAllText(path, serialString);
//Read json data
string jsonString = File.ReadAllText(path);
Note results = JsonSerializer.Deserialize<Note>(jsonString);
Console.WriteLine(results.summary);
}
}
Also I've looked into Json.NET and other options, but I would rather use this one (if possible)
Your Note class needs a parameterless constructor
class Note
{
public DateTime currentDate { get; set; }
public string summary { get; set; }
// add this
public Note()
{
}
public Note(DateTime _date, string _sum)
{
currentDate = _date;
summary = _sum;
}
}
It might be worth thinking if you need your original two parameter constructor. If you removed it, then you could instantiate a new Note like this
var completeNote = new Note
{
currentdate = date,
summary = givenNote
};
Related
This question already has answers here:
Overlay data from JSON string to existing object instance
(4 answers)
Closed 4 years ago.
I want to create a new object, and during object creation make an RPC call to get properties for it, and then return the object populated with the properties. See this example:
using Newtonsoft.Json;
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Person(int Id)
{
// here would be an RPC call to get the FirstName,LastName. result is JSON
string result = "{\"Id\": 1, \"FirstName\": \"Bob\", \"LastName\": \"Jones\"}";
this = JsonConvert.DeserializeObject<Person>(result);
}
}
class Program
{
static void Main(string[] args)
{
var p = new Person(1);
// p.FirstName should be Bob
}
}
I don't know how to do this in the constructor without getting a StackOverflow Exception.
One option to consider is to use a static method inside Person:
public static Person GetPerson(int Id)
{
// here would be an RPC call to get the FirstName,LastName. result is JSON
string result = "{\"Id\": 1, \"FirstName\": \"Bob\", \"LastName\": \"Jones\"}";
return JsonConvert.DeserializeObject<Person>(result);
}
This avoids the recursive nature of your original code.
Another option is to change the class to a struct. structs allow you to assign to this (unlike classes). And they have a default constructor (separate to your one taking a parameter) so that there is no recursive behaviour.
I have multiple web requests that post JSON object and I have serializable classes with all the fields. For example:
[Serializable]
public class RequestOne()
{
public string date;
public string information;
public string subject;
}
[Serializable]
public class RequestTwo()
{
public int ID;
public string Data;
public string message;
}
And my method takes partially filled request class and I want to fill in any missing fields with default values declared in constant class.
And I want to avoid writing each method with for each request, like :
public static void FillWithDefault(this RequestOne request)
{ if (request.date.Equals(null)) request.date = DEFAULT_DATE;
if (request.information.Equals(null)) request.information = DEFAULT_INFO;
if (request.subject.Equals(null)) request.subject = DEFAULT_SUBJECT;
}
public static void FillWithDefault(this RequestTwo request)
{
//do the same for the fields in RequestTwo
}
I want to know if there is any way to achieve this using generic?
I want to do something similar to this:
public static void FillWithDefault<T>(this T request)
{
if(typeof(T) == typeof(request))
{
//check each member in request and fill with default if it's null
}
.
.
.
}
So that in my main method I can use like this :
RequestOne request = new RequestOne();
request.FillWithDefault();
RequestTwo request2 = new RequestTwo();
request2.FillWithDefault();
Can someone please help with idea on this? Am I overthinking on this? I'm new to generic so please feel free to advise on my code.
Edit
Sorry guys, I did not mention that I will be using this method for test automation. Those request contracts cannot be changed since it's by design. Sorry again for the confusion!
Use constructors. Also make use of properties. Don't gather the default filling code to one place, it's the responsibility of the classes so keep them there.
[Serializable]
public class RequestOne()
{
public string date { get; set; };
public string information { get; set; };
public string subject { get; set; };
public RequestOne()
{
Date = DEFAULT_DATE;
Information = DEFAULT_DATE;
Subject = DEFAULT_SUBJECT;
}
}
[Serializable]
public class RequestTwo()
{
public int ID { get; set; };
public string Data { get; set; };
public string Message { get; set; };
public RequestTwo()
{
Data = DEFAULT_DATA;
message = DEFAULT_MESSAGE;
}
}
Generics are used when the types have common operations/properties defined so you can apply the same routine for each type in one place instead of declaring different methods for each type.
However in this case, you have two different types with different properties, so I would not use generics here. You can achieve it with manual type checking and using reflection to get properties and set them but it's not a good way and definitely wouldn't be a good usage of generics.
Overloading is the way to go.
you can use property
[Serializable]
public class RequestOne()
{
private string _date;
public string date { get { return _date;} set { _date = value ?? DEFAULT_DATE; }};
public string information; // same here
public string subject; //same here
}
I am currently using a list to handle a JSON string which works fine for one instance of this, as can be seen below. What I want to do is make these methods that handle the conversion completely generic so I can use them for multiple JSON strings.
This is a snippet of my current code as it stands.
public class GetPerson
{
public string fooName { get; set; }
public string fooAddress { get; set; }
public string fooPosition { get; set; }
}
public class GetPosition
{
public string fooTitle { get; set; }
public string fooDepartment { get; set; }
public string fooSalary { get; set; }
}
private static List<GetPerson> ConvertToList(string jsonString)
{
List< listJson = new List<JsonObject>();
listJson = (List<GetPerson>)JsonConvert.DeserializeObject<List<GetPerson>>(jsonString);
return listJson;
}
This is just a quick sample but the List<GetPerson> is what I need to be generic so it can be reused, because as it stands the GetPosition will obviously not work with this, as I would want to be able to iterate through my code changing the type accordingly.
Is there a way I can assign a variable as a type? I saw another question about this but it didn't go into detail. Or is there another way that this could be achieved?
Thanks in advance.
Very Simple. You just have to make ConvertToList() generic and pass the desired class as Type Paramter in ConvertToList()
private static List<T> ConvertToList<T>(string jsonString)
{
var listJson = new List<JsonObject>();
listJson = (List<T>)JsonConvert.DeserializeObject<List<T>>(jsonString);
return listJson;
}
var personList = ConvertToList<GetPerson>(jsonString);
var positionList = ConvertToList<GetPosition>(jsonString);
You can use Generics to help make the ConvertToList function reusable for different types
private static List<T> ConvertToList<T>(string jsonString)
{
return (List<T>)JsonConverty.DeserializeObject<List<T>>(jsonString();
}
You can now call it using both GetPerson and GetPosition as the generic type.
var listOfPeople = ConvertToList<GetPerson>(personJson);
var listOfPositions = ConvertToList<GetPosition>(positionJson);
You can read more about Generics on MSDN.
Also, if all that you want to do is to [de]serialize JSON, you might want to consider a third-party library for that like JSON.net, Jil or ServiceStack.Text, all of which have built in functions to do what you are trying to do.
I've created a C# class with a static method that convert's any object to a JSON object. I've used JavaScriptSerializar for this. Here is my code
public class JS
{
public static string GetJSON(object obj)
{
JavaScriptSerializer js = new JavaScriptSerializer();
string retJSON = js.Serialize(obj);
return retJSON;
}
}
I've another class that have only two property, Date & Remark. Here is my class
public class RemarkData
{
public DateTime Date { set; get; }
public string Remark { set; get; }
}
Now, I'm converting a object of the RemarkData class into JSON using following code
JS.GetJSON(objRemarkData);
Here is the output I'm getting
{"Date":"/Date(1389403352042)/","Remark":"Sme Remarks"}
Here is the output that I need
{"Date":1389403352042,"Remark":"Some Remarks"}
What should I do tho get that kind of output? Any help ?
double ticks = Math.Floor(objRemarkData.Date.ToUniversalTime()
.Subtract(new DateTime(1970, 1, 1))
.TotalMilliseconds);
var newob = new { Date =ticks, Remark = objRemarkData.Remark};
JS.GetJSON(newob);
You could try JSON.NET, it serializes Date into ISO string.
public class JS
{
public static string GetJSON(object obj)
{
string retJSON = JsonConvert.SerializeObject(obj);
return retJSON;
}
}
Actually, you can use it directly, don't need to wrap inside another function.
This is also how asp.net web api serializes date objects. For more information why ISO string is a good choice, check out this link http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
This long number is "milliseconds since epoch". We can convert this to normal javascript date by using the following snippet as explained in another so post Converting .NET DateTime to JSON
var d = new Date();
d.setTime(1245398693390);
document.write(d);
One can also use a nice library from http://blog.stevenlevithan.com/archives/date-time-format with the following snippet ..
var newDate = dateFormat(jsonDate, "dd/mm/yyyy h:MM TT");
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Parse JSON in C#
I'm trying to deserialize a JSON string from the openlibrary.org in an ASP.NET (4.5) web application using JSON.NET.
My aim is to be able to read the 5 properties below from a single .Net object.
The example JSON
I have is:
{"ISBN:0201558025":
{
"bib_key": "ISBN:0201558025",
"preview": "noview",
"thumbnail_url": "http://covers.openlibrary.org/b/id/135182-S.jpg",
"preview_url": "http://openlibrary.org/books/OL1429049M/Concrete_mathematics",
"info_url": "http://openlibrary.org/books/OL1429049M/Concrete_mathematics"
}
}
I can get it to work fine without the first line, but I'm a bit lost trying to work out how I should structure my classes.
I'm new to JSON and haven't played with C#/VB.NET in a few years so getting very lost.
Update
I have the following code:
Dim url = "http://openlibrary.org/api/books?bibkeys=ISBN:0201558025&format=json"
Dim webClient = New System.Net.WebClient
Dim json = webClient.DownloadString(url)
Dim book As Book = JsonConvert.DeserializeObject(Of Book)(json)
And the class Book:
Public Class Book
Public bib_key As String
Public preview As String
Public preview_url As String
Public info_url As String
End Class
However, book turns up empty.
There is a website called json2csharp - generate c# classes from json:
public class RootObject
{
public string bib_key { get; set; }
public string preview { get; set; }
public string thumbnail_url { get; set; }
public string preview_url { get; set; }
public string info_url { get; set; }
}
The json format is a little off, remove the {"ISBN:0201558025": since you have the ISBN as the bib_key
Try using JSON.Net
or
JavaScriptSerializer Class
or
DataContractSerializer class
I think it can be deserialized as a Dictionary.
new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Dictionary<string, BookInfoClass>>(jsonString);