Deserializing a class with a Queue<T> with Newtonsoft.Json - json

I have a class that has a property of type Queue. When trying to deserialize the JSON, I get the following error:
Type specified in JSON 'ConsoleApplication1.Task[], ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with 'System.Collections.Generic.Queue`1[[ConsoleApplication1.Task, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Path 'Tasks.$type', line 1, position 140.
I have included the sample application below and I am using Newtonsoft.Json 4.5.10.15407.
The reason I am using a Queue instead of List or Dictionary is because I must preserve insert order. I've also tried searching in the docs and other questions but haven't really found anything concrete. Any help is much appreciated. Thank you.
namespace ConsoleApplication1
{
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
class Program
{
static void Main(string[] args)
{
Message message = new Message
{
MessageID = 1,
Tasks = new Queue<Task>()
};
message.Tasks.Enqueue(new Task{TaskId = 1, Message = "Test1", Parameters = "Param1"});
message.Tasks.Enqueue(new Task{TaskId = 2, Message = "Test2", Parameters = "Param2"});
byte[] bSerialized = SerializeJsonWithPrefix(message);
Message deserializedMessage = DeserializeJson(bSerialized, typeof (Message));
}
public static byte[] SerializeJsonWithPrefix(Message item)
{
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.TypeNameHandling = TypeNameHandling.All;
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(item, jss));
}
public static Message DeserializeJson(byte[] ueaData, Type concreteType)
{
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.TypeNameHandling = TypeNameHandling.All;
// --- Error occurs here ---
var result = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(ueaData), concreteType, jss);
return (Message)result;
}
}
public class Message
{
public int MessageID { get; set; }
public Queue<Task> Tasks { get; set; }
}
public class Task
{
public int TaskId { get; set; }
public string Message { get; set; }
public string Parameters { get; set; }
}
}

Version 5 solves your problem.

I stick to List<T> and Dictionary<string, T> when using JSON.NET serialization, where T is some JSON-serializable type. These correspond nicely to the JSON array and object types (see json.org).
If you serialize a List<T> and then deserialize it, JSON.NET will of course maintain the ordering. I would advise just translating between your Queue<T> and a List<T> for serialization, rather than trying to add behavior for directly serializing the Queue<T>.

Related

System.Text.Json.JsonSerializer.Deserialize returning object with all fields null in .Net Core 3.1 [duplicate]

I am converting my newtonsoft implementation to new JSON library in .net core 3.0. I have the following code
public static bool IsValidJson(string json)
{
try
{
JObject.Parse(json);
return true;
}
catch (Exception ex)
{
Logger.ErrorFormat("Invalid Json Received {0}", json);
Logger.Fatal(ex.Message);
return false;
}
}
I am not able to find any equivalent for JObject.Parse(json);
Also what will be the attribute JsonProperty equivalent
public class ResponseJson
{
[JsonProperty(PropertyName = "status")]
public bool Status { get; set; }
[JsonProperty(PropertyName = "message")]
public string Message { get; set; }
[JsonProperty(PropertyName = "Log_id")]
public string LogId { get; set; }
[JsonProperty(PropertyName = "Log_status")]
public string LogStatus { get; set; }
public string FailureReason { get; set; }
}
One more thing i will be looking for the equivalent of Formating.None.
You are asking a few questions here:
I am not able to find any equivalent for JObject.Parse(json);
You can use JsonDocument to parse and examine any JSON, starting with its RootElement. The root element is of type JsonElement which represents any JSON value (primitive or not) and corresponds to Newtonsoft's JToken.
But do take note of this documentation remark:
This class utilizes resources from pooled memory to minimize the impact of the garbage collector (GC) in high-usage scenarios. Failure to properly dispose this object will result in the memory not being returned to the pool, which will increase GC impact across various parts of the framework.
When you need to use a JsonElement outside the lifetime of its document, you must clone it:
Gets a JsonElement that can be safely stored beyond the lifetime of the original JsonDocument.
Also note that JsonDocument is currently read-only and does not provide an API for creating or modifying JSON. There is an open issue Issue #39922: Writable Json DOM tracking this.
An example of use is as follows:
//https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#using-declarations
using var doc = JsonDocument.Parse(json);
//Print the property names.
var names = doc.RootElement.EnumerateObject().Select(p => p.Name);
Console.WriteLine("Property names: {0}", string.Join(",", names)); // Property names: status,message,Log_id,Log_status,FailureReason
//Re-serialize with indentation.
using var ms = new MemoryStream();
using (var writer = new Utf8JsonWriter(ms, new JsonWriterOptions { Indented = true }))
{
doc.WriteTo(writer);
}
var json2 = Encoding.UTF8.GetString(ms.GetBuffer(), 0, checked((int)ms.Length));
Console.WriteLine(json2);
Also what will be the attribute JsonProperty equivalent?
Attributes that can control JsonSerializer are placed in the System.Text.Json.Serialization namespace and inherit from an abstract base class JsonAttribute. Unlike JsonProperty, there is no omnibus attribute that can control all aspects of property serialization. Instead there are specific attributes to control specific aspects.
As of .NET Core 3 these include:
[JsonPropertyNameAttribute(string)]:
Specifies the property name that is present in the JSON when serializing and deserializing. This overrides any naming policy specified by JsonNamingPolicy.
This is attribute you want to use to control the serialized names of your ResponseJson class:
public class ResponseJson
{
[JsonPropertyName("status")]
public bool Status { get; set; }
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("Log_id")]
public string LogId { get; set; }
[JsonPropertyName("Log_status")]
public string LogStatus { get; set; }
public string FailureReason { get; set; }
}
[JsonConverterAttribute(Type)]:
When placed on a type, the specified converter will be used unless a compatible converter is added to the JsonSerializerOptions.Converters collection or there is another JsonConverterAttribute on a property of the same type.
Note that the documented priority of converters -- Attribute on property, then the Converters collection in options, then the Attribute on type -- differs from the documented order for Newtonsoft converters, which is the JsonConverter defined by attribute on a member, then the JsonConverter defined by an attribute on a class, and finally any converters passed to the JsonSerializer.
[JsonExtensionDataAttribute] - corresponds to Newtonsoft's [JsonExtensionData].
[JsonIgnoreAttribute] - corresponds to Newtonsoft's [JsonIgnore].
When writing JSON via Utf8JsonWriter, indentation can be controlled by setting JsonWriterOptions.Indented to true or false.
When serializing to JSON via JsonSerializer.Serialize, indentation can be controlled by setting JsonSerializerOptions.WriteIndented to true or false.
Demo fiddle here showing serialization with JsonSerializer and parsing with JsonDocument.
This link should get you going, snippets of which I copied below.
https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/
WeatherForecast Deserialize(string json)
{
var options = new JsonSerializerOptions
{
AllowTrailingCommas = true
};
return JsonSerializer.Parse<WeatherForecast>(json, options);
}
class WeatherForecast {
public DateTimeOffset Date { get; set; }
// Always in Celsius.
[JsonPropertyName("temp")]
public int TemperatureC { get; set; }
public string Summary { get; set; }
// Don't serialize this property.
[JsonIgnore]
public bool IsHot => TemperatureC >= 30;
}

How to use Json File to serve as a data source for webapi

I want to retrieve data from Json file with webapi using Json file as data source.
In the controller, I have added following code:
Public HttpResponseMessage Get()
{
var json = File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath(#"~/App_Data\Bim.Json"));
return new HttpResponseMessage()
{
Content = new StringContent(json, Encoding.UTF8, "application/json"),
StatusCode = HttpStatusCode.OK
};
}
and in model,
public class bimModel
{
public string name { get; set; }
public string material { get; set; }
public string tag { get; set; }
public string contentType { get; set; }
}
Actually, I want to use a json file which is located in app_data folder, how to read data from JSON file? I am very new to the webApi, so it will be of great help if the experts can post the entire working code or as many details as possible, please.
If I am correct, I believe you want to deserialize the json text file to model classes, then serialize them back to json for the client.
To do this, you can use https://www.nuget.org/packages/newtonsoft.json/ to help you out. Follow the instructions to get the package installed.
Once you do that, you can write a function such as
public bimModel Get()
{
var json = File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath(#"~/App_Data\Bim.Json"));
var model = JsonConvert.DeserializeObject<bimModel>(json);
return model;
}
If your json file is an array of bimModels, then you can change the return type and type parameter of DeserializeObject to List<bimModel>.
To ensure your server is returning json to the client, make sure your WebApiConfig class is using the JsonMediaTypeFormatter
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
}
And of course, be sure to include using Newtonsoft.Json; and using Newtonsoft.Json.Serialization;

Formatting Json for WebAPI 2 from Ember-Data

I've been struggling with this problem for a few days now and was hoping someone could help me out. I've got an ember front end which communicates with an API written in C#.
I'm making a an update (PUT) request but the model comes through with all the properties as null. The reason for this is because the API expects
{
"Type":1,
"Name":"Hello World"
}
but ember sends it in the format of
{
"Object":
{
"Type":1,
"Name":"Hello World"
}
}
I've seen solutions where you can add a custom JsonConverter onto the API Model, but this has to have it's own converter for each model. I'd like to know if someone help me with a generic one that I can apply to any model.
Here's an example of one that is specific for the profile model, I can't seem to get it to work as a generic though.
[JsonConverter(typeof(ProfileConverter))]
public class Profile
{
public string LoginId { get; set; }
public bool NewProfileOptIn { get; set; }
}
and the converter
public class ProfileConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Profile).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
Log.Information("Reading Json from ProfileSetting");
JToken token = JToken.Load(reader);
if (token["ProfileSetting"] != null)
{
JObject inner = token["ProfileSetting"].Value<JObject>();
if (CheckJsonProperty(inner, "login_id") && CheckJsonProperty(inner, "new_profile_opt_in"))
{
Profile model = new Profile
{
LoginId = inner["login_id"].ToString(),
NewProfileOptIn = (bool)inner["new_profile_opt_in"]
};
return model;
}
return null;
}
Log.Error("Invalid Model Name Passed - Expected 'ProfileSetting'");
return null;
}
private bool CheckJsonProperty(JObject objectToCheck, string expectedJsonProperty)
{
if (objectToCheck[expectedJsonProperty] != null)
{
return true;
}
Log.Error("Invalid or Missing Model Property Name Passed - Expected '" + expectedJsonProperty + "'");
return false;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
If any one has any reading resources or examples that would help, it would be much appreciated.
Thanks,
VB.Net
This Example has been coded with Json.Net.
So I'm working with Vb.net but this should work in C# the same way.
I've been able to do it without an JsonConverter as follows:
Public Class TestController
Inherits ApiController
<HttpGet>
Public Function Index() As String
Dim o As New JObject
o.Add("Data", 10)
Dim j As New JObject
j.Add("Object", o)
Dim obj = j.ToObject(Of EmberDataObject(Of TestObject))()
Return "200 - OK"
End Function
End Class
Public Class EmberDataObject(Of T)
<JsonProperty("Object")>
Public Property DataObject As T
End Class
Public Class TestObject
Public Property Data As Integer
End Class
In the above example the JsonObject with this mark up
{
"Object": {
"Data": 10
}
}
can be transformed easily. You can then access the nested Type as obj.DataObject. Through the set JsonProperty Attribute you can omit the Object key word which at least in Vb is not a legal Property name.
C#
The C# translation would be like this:
public class EmberDataObject<T>
{
[JsonProperty("Object")
public T DataObject {get; set;}
}
public class TestData
{
public int Data {get; set;}
}
And then referencing this from your Controller as follows:
public class MyApiController : ApiController
{
public IActionResult Post(EmberDataObject<TestData> emberObject)
{
/// Inner Object Available as emberObject.Object
}
}

Built in JSON parser in .NET framework [duplicate]

I'm trying to build a Metro application for Windows 8 on Visual Studio 2011.
and while I'm trying to do that, I'm having some issues on how to parse JSON without JSON.NET library (It doesn't support the metro applications yet).
Anyway, I want to parse this:
{
"name":"Prince Charming",
"artist":"Metallica",
"genre":"Rock and Metal",
"album":"Reload",
"album_image":"http:\/\/up203.siz.co.il\/up2\/u2zzzw4mjayz.png",
"link":"http:\/\/f2h.co.il\/7779182246886"
}
You can use the classes found in the System.Json Namespace which were added in .NET 4.5. You need to add a reference to the System.Runtime.Serialization assembly
The JsonValue.Parse() Method parses JSON text and returns a JsonValue:
JsonValue value = JsonValue.Parse(#"{ ""name"":""Prince Charming"", ...");
If you pass a string with a JSON object, you should be able to cast the value to a JsonObject:
using System.Json;
JsonObject result = value as JsonObject;
Console.WriteLine("Name .... {0}", (string)result["name"]);
Console.WriteLine("Artist .. {0}", (string)result["artist"]);
Console.WriteLine("Genre ... {0}", (string)result["genre"]);
Console.WriteLine("Album ... {0}", (string)result["album"]);
The classes are quite similar to those found in the System.Xml.Linq Namespace.
I use this...but have never done any metro app development, so I don't know of any restrictions on libraries available to you. (note, you'll need to mark your classes as with DataContract and DataMember attributes)
public static class JSONSerializer<TType> where TType : class
{
/// <summary>
/// Serializes an object to JSON
/// </summary>
public static string Serialize(TType instance)
{
var serializer = new DataContractJsonSerializer(typeof(TType));
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, instance);
return Encoding.Default.GetString(stream.ToArray());
}
}
/// <summary>
/// DeSerializes an object from JSON
/// </summary>
public static TType DeSerialize(string json)
{
using (var stream = new MemoryStream(Encoding.Default.GetBytes(json)))
{
var serializer = new DataContractJsonSerializer(typeof(TType));
return serializer.ReadObject(stream) as TType;
}
}
}
So, if you had a class like this...
[DataContract]
public class MusicInfo
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Artist { get; set; }
[DataMember]
public string Genre { get; set; }
[DataMember]
public string Album { get; set; }
[DataMember]
public string AlbumImage { get; set; }
[DataMember]
public string Link { get; set; }
}
Then you would use it like this...
var musicInfo = new MusicInfo
{
Name = "Prince Charming",
Artist = "Metallica",
Genre = "Rock and Metal",
Album = "Reload",
AlbumImage = "http://up203.siz.co.il/up2/u2zzzw4mjayz.png",
Link = "http://f2h.co.il/7779182246886"
};
// This will produce a JSON String
var serialized = JSONSerializer<MusicInfo>.Serialize(musicInfo);
// This will produce a copy of the instance you created earlier
var deserialized = JSONSerializer<MusicInfo>.DeSerialize(serialized);
For those who do not have 4.5, Here is my library function that reads json. It requires a project reference to System.Web.Extensions.
using System.Web.Script.Serialization;
public object DeserializeJson<T>(string Json)
{
JavaScriptSerializer JavaScriptSerializer = new JavaScriptSerializer();
return JavaScriptSerializer.Deserialize<T>(Json);
}
Usually, json is written out based on a contract. That contract can and usually will be codified in a class (T). Sometimes you can take a word from the json and search the object browser to find that type.
Example usage:
Given the json
{"logEntries":[],"value":"My Code","text":"My Text","enabled":true,"checkedIndices":[],"checkedItemsTextOverflows":false}
You could parse it into a RadComboBoxClientState object like this:
string ClientStateJson = Page.Request.Form("ReportGrid1_cboReportType_ClientState");
RadComboBoxClientState RadComboBoxClientState = DeserializeJson<RadComboBoxClientState>(ClientStateJson);
return RadComboBoxClientState.Value;
I needed a JSON serializer and deserializer without any 3rd party dependency or nuget, that can support old systems, so you don't have to choose between Newtonsoft.Json, System.Text.Json, DataContractSerializer, JavaScriptSerializer, etc. depending on the target platform.
So I have started this open source (MIT) project here:
https://github.com/smourier/ZeroDepJson
It's just one C# file ZeroDepJson.cs, compatible with .NET Framework 4.x to .NET Core, and .NET 5.
Note it's probably not as good as all the aforementioned libraries (especially in performance area), but it should be reasonably ok and friction-free.
Have you tried using JavaScriptSerializer ?
There's also DataContractJsonSerializer
I have written a small construct to do that long back, it requires System.Runtime.Serialization.Json namespace. It uses DataContractJsonSerializer to serialize & deserialize object with a static method JConvert.
It works with small set of data but haven't tested with big data source.
JsonHelper.cs
// Json Serializer without NewtonSoft
public static class JsonHelper
{
public static R JConvert<P,R>(this P t)
{
if(typeof(P) == typeof(string))
{
var return1 = (R)(JsonDeserializer<R>(t as string));
return return1;
}
else
{
var return2 = (JsonSerializer<P>(t));
R result = (R)Convert.ChangeType(return2, typeof(R));
return result;
}
}
private static String JsonSerializer<T>(T t)
{
var stream1 = new MemoryStream();
var ser = new DataContractJsonSerializer(typeof(T));
ser.WriteObject(stream1, t);
stream1.Position = 0;
var sr = new StreamReader(stream1);
return (sr.ReadToEnd());
}
private static T JsonDeserializer<T>(string jsonString)
{
T deserializedUser = default(T);
var ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
var ser = new DataContractJsonSerializer(typeof(T));
deserializedUser = (T)ser.ReadObject(ms);// as T;
ms.Close();
return deserializedUser;
}
}
Syntax:
To use the JsonHelper you need to call
JConvert<string,object>(str); //to Parse string to non anonymous <object>
JConvert<object,string>(obj); //to convert <obj> to string
Example:
Suppose we have a class person
public class person
{
public string FirstName {get;set;}
public string LastName {get;set;}
}
var obj = new person();//"vinod","srivastav");
obj.FirstName = "vinod";
obj.LastName = "srivastav";
To convert the person object we can call:
var asText = JsonHelper.JConvert<person,string>(obj); //to convert <obj> to string
var asObject = JsonHelper.JConvert<string,person>(asText); //to convert string to non-anonymous object
You can use DataContractJsonSerializer. See this link for more details.
using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
namespace OTL
{
/// <summary>
/// Before usage: Define your class, sample:
/// [DataContract]
///public class MusicInfo
///{
/// [DataMember(Name="music_name")]
/// public string Name { get; set; }
/// [DataMember]
/// public string Artist{get; set;}
///}
/// </summary>
/// <typeparam name="T"></typeparam>
public class OTLJSON<T> where T : class
{
/// <summary>
/// Serializes an object to JSON
/// Usage: string serialized = OTLJSON<MusicInfo>.Serialize(musicInfo);
/// </summary>
/// <param name="instance"></param>
/// <returns></returns>
public static string Serialize(T instance)
{
var serializer = new DataContractJsonSerializer(typeof(T));
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, instance);
return Encoding.Default.GetString(stream.ToArray());
}
}
/// <summary>
/// DeSerializes an object from JSON
/// Usage: MusicInfo deserialized = OTLJSON<MusicInfo>.Deserialize(json);
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public static T Deserialize(string json)
{
if (string.IsNullOrEmpty(json))
throw new Exception("Json can't empty");
else
try
{
using (var stream = new MemoryStream(Encoding.Default.GetBytes(json)))
{
var serializer = new DataContractJsonSerializer(typeof(T));
return serializer.ReadObject(stream) as T;
}
}
catch (Exception e)
{
throw new Exception("Json can't convert to Object because it isn't correct format.");
}
}
}
}

How do I limit NewtonSoft.JSON to serialize an interface?

Very simple example (I use this in my unit tests):
private interface ISampleSubset
{
int id { get; }
}
private class Sample : ISampleSubset
{
public int id { get; set; }
public string name { get; set; }
}
Here's a small wrapper around NewtonSoft's JSON Serialize:
public string Serialize<T>(T t)
{
using (var sw = new StringWriter())
{
using (var jw = new JsonTextWriter(sw))
{
var js = JsonSerializer.Create();
js.Serialize(jw, t);
jw.Flush();
}
return sw.GetStringBuilder().ToString();
}
}
Now I want to serialize ISampleSubset:
And call it like so:
ISampleSubSet t = new Sample()
{
id = 1,
name = "joe"
};
string json = Serialize(t);
I expect to get
{"id":1}
but instead I get
{"id":1,"name":"joe"}
I'm guessing js.Serialize is using reflection to 'see' the other properties on the object 'outside' of the interface. How do I limit it to just those properties on the interface?
The serializer doesn't even know about your interface, so it's giving you everything - it accepts an object, so it doesn't know that you've declared your variable of type ISampleSubset - all it knows is the object itself is an instance of Sample.
Probably not the best solution, but you can use a JsonConverter to restrict the properties that appear in your serialized object.
This code is probably very inefficient - please don't judge - just threw it together, you can clean up the details and implement however you need:
public class MyConverter<T> : JsonConverter {
private readonly string[] _propertyNames;
public MyConverter() {
_propertyNames = typeof(T).GetProperties().Select(p => p.Name).ToArray();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var objectType = value.GetType();
var newObject = new Dictionary<string, object>();
foreach (string propName in _propertyNames) {
var prop = objectType.GetProperty(propName);
if (prop != null) {
newObject[propName] = prop.GetValue(value, null);
}
}
string s = JsonConvert.SerializeObject(newObject);
writer.WriteRaw(s);
}
public override bool CanConvert(Type objectType) {
return true; // ?
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
throw new NotImplementedException();
}
}
public static string Serialize<T>(T t) {
return JsonConvert.SerializeObject(t, new MyConverter<T>());
}
Basically what it's doing is using reflection on the interface type to retrieve its properties, then creating a dictionary using only the properties found on the interface (you can do that a number of ways) - then using the simple JsonConvert class to serialize the dictionary.
NewtonSoft.JSON is serializing the object instance you created based on the default rule (as of .NET 3.5 IIRC) that all properties of an object are by default serializable. It doesn't matter if you declared your variable as an interface type because it's probably doing the serialization by reflection.
If you want to restrict the properties that get serialized the best way is to use theNonSerialized attribute.