I'm simply trying to use Serialization properties to temporary store datas in a string. I tested many method and those functions are the ones I could use (since in my real classes I have ObjectId, a lot of serialization classes don't work).
However, even with a simple test it doesn't work, my deserialization is null:
public class MyClass
{
public string test = "bob";
}
static public void function()
{
MyClass test = new MyClass();
string data = Newtonsoft.Json.JsonConvert.SerializeObject(test);
object testb = Newtonsoft.Json.JsonConvert.DeserializeObject(data);
MyClass testa = Newtonsoft.Json.JsonConvert.DeserializeObject(data) as MyClass;
}
Results are (debugger):
datab : { "test": "bob"}
testa is null.
Why? How can I convert an object like testb with keys and value to my correct type?
Problem is the way you are type casting.
Try out this one and it should work just fine
MyClass testa = Newtonsoft.Json.JsonConvert.DeserializeObject<MyClass>(data);
That shall be all.
Use the generic de-serialise method:
MyClass testa = Newtonsoft.Json.JsonConvert.DeserializeObject<MyClass>(data);
You should define your classes with public getters and setters:
public class MyData
{
public string Name {get; set;}
}
Then, create an instance of the class and serialize it:
var data = new MyData() { Name = "bob" };
var serialized = JsonConvert.SerializeObject(data);
Console.WriteLine(serialized);
When you deserialize, you can use DeserializeObject<T> to tell JSON.NET which type to deserialize back to:
var deserialized = JsonConvert.DeserializeObject<MyData>(serialized);
Console.WriteLine(deserialized.Name);
Live fiddle: https://dotnetfiddle.net/w4B1IK
Related
I am currently in the progress of enabling non-nullable reference types for my .net core api.
The problem is that the integrationtest fails when trying to deserializeObject because it has no empty constructor. I can't have an empty constructor because that will make property: possible null.
The problem:
JsonConvert.DeserializeObject<ViewModel>(result); calls the constructor which has a constructor with an object argument ViewModel(Model model). In the test this is null.
I have made a simple sample:
The api:
public class Dog
{
public string Name { get; set; } = null!;
}
public class DogViewModel
{
public DogViewModel(Dog dog)
{
Name = dog.Name;
}
public string Name { get; set; }
}
[HttpGet]
[Route("dog")]
public DogViewModel GetDog()
{
var dog = new Dog
{
Name = "Fido"
};
return new DogViewModel(dog);
}
This works when I use a client to call the api, but it fails from the tests:
Test
[Fact]
public async Task GetDog()
{
var response = await Client.GetAsync("dog");
var result = response.Content.ReadAsStringAsync().Result;
Assert.True(response.IsSuccessStatusCode, result);
var responeseAsObject = JsonConvert.DeserializeObject<DogViewModel>(result); <----- this is where it breaks
Assert.IsType<string>(responeseAsObject.Name);
Assert.NotNull(responeseAsObject);
}
JsonConvert.DeserializeObject calls the constructor of DogViewModel; DogViewModel(Dog dog), but dog is null.
Populate the class with default values. With null able reference types, the default value would be null, so in your case just assign the default value that you expect.
public class ClassName
{
public ClassName()
{
Name = string.Empty; //Default value
}
public ClassName(Dog dog)
{
Name = dog.Name;
}
}
Or
public class ClassName
{
public string Name { get; set; } = string.Empty;
public ClassName() {}
public ClassName(Dog dog)
{
Name = dog.Name;
}
}
The serializer will construct a new object. The object contains a string member, and you have disabled null-able reference types. Thus you need to specify what the value will be when the object is created.
If you don't want to use the default constructor (An empty constructor), you can tell the serialiser the constructor you would like to use:
https://www.newtonsoft.com/json/help/html/JsonConstructorAttribute.htm
That's correct behavior JsonConvert.DeserializeObject uses constructor to just create an object. It won't pass any parameter to it and that's why you are getting an error.
What's happening is, dog is null and hence your assignment of Name = dog.Name; throws NullreferenceException.
You should ideally check dog for null before using it in your constructor.
public DogViewModel(Dog dog)
{
Name = dog?.Name;
}
The question is, as #CodeCaster points out, nonsensical- But i found a non-optimal solution.
In the test project i created this:
public class TestDogViewModel : DogViewModel
{
public TestDogViewModel() : base(new Dog {Name = ""})
{
}
}
When deserializing i used this:
var responeseAsObject = JsonConvert.DeserializeObject<TestDogViewModel>(result);
Developers won't use this viewModel by mistake since the project doesn't have a reference to the test project,
So now if you want to have a DogViewModel you would need to have a dog. It kinda makes more sense in my real project :S.
From docs.microsoft:
The Newtonsoft.Json [JsonConstructor] attribute lets you specify which constructor to call when deserializing to a POCO. System.Text.Json supports only parameterless constructors. As a workaround, you can call whichever constructor you need in a custom converter.
--> https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#deserialize-to-immutable-classes-and-structs
Maybe this could be a solution
I am trying to get protobuf serialization working with the RedisSessionStateProvider. I have specified the redisSerializerType as a custom class which implements Microsoft.Web.Redis.ISerializer - here is the deserialization code:
public object Deserialize(byte[] data)
{
return DeserializeDirect(data);
}
private object DeserializeDirect(byte[] data)
{
using (var memoryStream = new MemoryStream(data))
{
return Serializer.Deserialize<object>(memoryStream);
}
return null;
}
As I need to implement Microsoft.Web.Redis.ISerializer the signature for deserialize uses a return type of object and there is no way to pass in the actual type being returned. So when DeserializeDirect tries to use the Protobuf.Serializer to deserialize it (as expected) says "Type is not expected, and no contract can be inferred: System.Object". I am using a web app with .NET framework 4.6.1 and I was hoping somebody could point out what I am doing wrong.
Thanks!
Normally, protobuf-net really wants to know the exact type. You can, however, cheat using DynamicType. This tells protobuf-net to include additional type metadata - something it doesn't usually include.
Note that this can make you code brittle - it may fail if the type changes in you code!
I will be implementing Any soon (as part of 2.3.0), which is another option here.
public static void Main()
{
// the actual object we care about
object obj = new Foo { X = 1 };
// serialize and deserialize via stub
var stub = new Stub { Data = obj };
var clone = Serializer.DeepClone(stub);
// prove it worked
Console.WriteLine(clone.Data);
// prove it is a different instance
Console.WriteLine(ReferenceEquals(obj, clone.Data));
}
[ProtoContract]
public class Foo
{
[ProtoMember(1)]
public int X { get; set; }
public override string ToString() => $"X={X}";
}
[ProtoContract]
public sealed class Stub
{
[ProtoMember(1, DynamicType = true)]
public object Data { get; set; }
}
I have a small problem with passing some parent instance to a constructor when deserializing an object with Newtonsoft.Json.
Let's assume i have the following classes
public class A
{
public string Str1 { get; set; }
public IList<B> Bs { get; set; }
}
public class B
{
public B(A a)
{
// a should not be null!
Console.WriteLine(a.Str)
}
}
And now i serailze and than deserialize the object a like this:
A a = new A()
a.Bs = new List<B>()
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
var json = JsonConvert.SerializeObject(a);
// Here i need to call the constructor of B when creating new instances
var newA = JsonConvert.DeserializeObject<A>(json);
The problem is, that when deserializing the object, null will be passed to the constructor of B. Does any one has solved this issue/problem before?
Thank you very much!
In your question and comments you've said that the class B does not have any public property for A. So, when you serialize B, then no A will be written to the JSON, because Json.Net only serializes the public information by default. Therefore, when deserializing, there will not be enough information to recreate B, because there is no A in the JSON. So, step one is making B's reference to A visible to Json.Net. If you don't want to make it public, that is fine, but you will at least need to mark the member with a [JsonProperty] attribute to allow Json.Net to "see" it.
public class B
{
[JsonProperty]
private A a;
public B(A a)
{
this.a = a; // be sure to set the A member in your constructor
}
}
Now if you do the above you will run into a second problem: your class structure has a reference loop (A has a list of Bs which each refer back to A), and the serializer will throw an exception by default in this case. The solution is to set the serializer's PreserveReferencesHandling setting to Objects (the default is None). This will not only allow the serializer to handle the reference loops during serialization, but will also preserve the original references during deserialization, so that all the Bs will refer to the same A instance. (This is accomplished via special $id and $ref properties that are written into the JSON.)
JsonSerializerSettings settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
var json = JsonConvert.SerializeObject(a, settings);
var newA = JsonConvert.DeserializeObject<A>(json, settings);
Working example: https://dotnetfiddle.net/N0FUID
What I like to do it I have to pass objects in a constructor is to create the object first using my default constructor and then call populate object to set all properties that are not skipped as I decorated the properties with [JsonIgore]
var settings = new JsonSerializerSettings()
{
Error = HandleJsonDeserializationError,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
}
var myObject = new ComplexObject(param1,param2);
JsonConvert.PopulateObject(json, myObject, settings);
You can continue populating objects and deal with any issues if you handle serialisation errors in the JsonSettings property. The signature is as follows:
static void HandleJsonDeserializationError(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs errorArgs)
{
var currentError = errorArgs.ErrorContext.Error.Message;
errorArgs.ErrorContext.Handled = true;
//loging framework logs the error, set brake point etc when debug.
Logger.Log(currentError, LogLevel.Exceptions);
}
I am trying to serialize some data which contains an observable collection of objects and write it into a text tile. My output is [] and I do now know where I have made a mistake.
my object code
public class ObjectList : ObservableCollection<string>, INotify...
{
public ObservableCollection<string> ObjectListInstance = new ObservableCollection<string>();
public string Name;
... get set methods & property changed method
}
my IO code
using (Stream newStream = await Windows.Storage.ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync("file.txt", Windows.Storage.CreationCollisionOption.ReplaceExisting))
{
DataContractJsonSerializer newDataContractJsonSerializer = new DataContractJsonSerializer(typeof(ObservableCollection<ObjectList>));
newDataContractJsonSerializer.WriteObject(newStream, ObjectList);
}
my code stub
ObjectList newObjectList = new ObjectList();
newObjectList.Name = "AAA NAME";
newObjectList.ObjectListInstance.Add("ITEM 1");
newObjectList.ObjectListInstance.Add("ITEM 2");
bool status = await IOClass.IO.WriteCategory(newObjectList);
You can't have a class that is both a collection and has additional properties to be serialized. However, you can have a class that contains a list and has additional properties, which is what I think you are trying to do here. To make it work you will need to make some adjustments to your code:
Your ObjectList should not inherit from ObservableCollection<T> (or any other list type)
You must mark your class with [DataContract], and mark the properties/fields you want to be serialized with [DataMember].
When you create your DataContractJsonSerializer instance, pass to the constructor the top-level type you want to serialize. In your case, this should be ObjectList, not ObservableCollection<ObjectList>.
When you call WriteObject on the serializer, the second parameter should be the object instance you are serializing, not a Type.
Here is the corrected class:
[DataContract]
public class ObjectList
{
[DataMember]
public ObservableCollection<string> ObjectListInstance = new ObservableCollection<string>();
[DataMember]
public string Name;
}
Here is the corrected serialization code:
DataContractJsonSerializer newDataContractJsonSerializer =
new DataContractJsonSerializer(typeof(ObjectList));
newDataContractJsonSerializer.WriteObject(newStream, newObjectList);
With these changes you should get the following JSON output:
{"Name":"AAA NAME","ObjectListInstance":["ITEM 1","ITEM 2"]}
I've got a class which has been serialized into JSON, and which I'm trying to deserialize into an object.
e.g.
public class ContentItemViewModel
{
public string CssClass { get; set; }
public MyCustomClass PropertyB { get; set; }
}
the simple property (CssClass) will deserialize with:
var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);
But PropertyB gets an error...
We added a JavaScriptConverter:
ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});
But when we added 'MyCustomClass' as a 'SupportedType', the Deserialize method was never called. However when we have ContentItemViewModel as the SupportedType, then Deserialize is called.
We've got a current solution which looks something like this:
class ContentItemViewModelConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var cssClass = GetString(dictionary, "cssClass"); //I'm ommitting the GetString method in this example...
var propertyB= GetString(dictionary, "propertyB");
return new ContentItemViewModel{ CssClass = cssClass ,
PropertyB = new MyCustomClass(propertyB)}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new Exception("Only does the Deserialize");
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new List<Type>
{
typeof(ContentItemViewModel)
};
}
}
}
But we'd prefer a simpler solution of only deserializing MyCustomClass, as there are a number of other fields which are on the ViewModel, and it seems a waste to have to edit this converter every time we change/add a property....
Is there a way to Deserialize JUST PropertyB of type MyCustomClass?
Thanks for your help!
Have you considered using DatacontractJsonSerializer
[DataContract]
public class MyCustomClass
{
[DataMember]
public string foobar { get; set; }
}
[DataContract]
public class ContentItemViewModel
{
[DataMember]
public string CssClass { get; set; }
[DataMember]
public MyCustomClass PropertyB { get; set; }
}
class Program
{
static void Main(string[] args)
{
ContentItemViewModel model = new ContentItemViewModel();
model.CssClass = "StackOver";
model.PropertyB = new MyCustomClass();
model.PropertyB.foobar = "Flow";
//Create a stream to serialize the object to.
MemoryStream ms = new MemoryStream();
// Serializer the User object to the stream.
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
ser.WriteObject(ms, model);
byte[] json = ms.ToArray();
ms.Close();
string s= Encoding.UTF8.GetString(json, 0, json.Length);
Console.ReadLine();
}
}
Add all possible classes to DatacontractJsonSerializer.KnownTypes if MyCustomClass has derivations.
For whatever it may be worth after all this time, but I stumbled over the same problem and the solution is that the Deserializer hasn't got a clue about the classes you are deserializing unless you give him the necessary information.
On the top level, it knows the type from the type parameter of Deserialize<>(). That's why your converter for ContentItemViewModel works. For nested objects, it needs __type properties and a JavaScriptTypeResolver.
var ser = new JavaScriptSerializer(new SimpleTypeResolver());
ser.RegisterConverters(myconverters);
MyClass myObject = new MyClass();
string json = ser.Serialize(myObject);
// set a breakpoint here to see what has happened
ser.Deserialize<MyClass>(json);
A TypeResolver adds a __type property to each serialized object. You can write a custom type resolver that uses short names. In this sample, I use the SimpleTypeResolver from .net that "simply" stores the fully qualified type name as __type. When deserializing, the JavaScriptDeserializer finds __type and asks the TypeResolver for the correct type. Then it knows a type and can call a registered JavaScriptConverter.Deserialize method.
Without a TypeResolver, objects are deserialized to a Dictionary because JavaScriptSerializer doesn't have any type information.
If you can't provide a __type property in your json string, I think you'll need to deserialize to Dictionary first and then add a "guessing-step" that interprets the fields to find the right type. Then, you can use the ConvertToType method of JavaScriptSerializer to copy the dictionary into the object's fields and properties.
If you need to use the JavaScriptSerializer that is provides by ASP.NET and can't create your own, consider this section from the .ctor help of JavaScriptSerializer:
The instance of JavaScriptSerializer that is used by the asynchronous communication layer for invoking Web services from client script uses a special type resolver. This type resolver restricts the types that can be deserialized to those defined in the Web service’s method signature, or the ones that have the GenerateScriptTypeAttribute applied. You cannot modify this built-in type resolver programmatically.
Perhaps the GenerateScriptType Attribute can help you. But I don't know what kind of __type Properties are be needed here.