Json Deserialize Protected Property [duplicate] - c#

This question already has answers here:
Json.net serialize specific private field
(2 answers)
JSON.net: how to deserialize without using the default constructor?
(6 answers)
Json.Net - Explicitly include a single private property
(1 answer)
Closed 4 years ago.
I have a class property set, and fixed in the constructor, example below is a Guid.NewGuid()..
The rationale being to only allow the class to populate, on creation.. so it's set in the constructor, and marked only as get; - works fine, until i serialize / deserialize to Json.
It seems that because there is no set; the deserialization fails.. and the constructor steps in and creates a new guid
I have tried internal, private, and protected set .. but all result in a regeneration of the property, the only way i can get it to work is by marking Id as {get;set;},
class Foo
{
public Foo() => Id = Guid.NewGuid().ToString();
public string Id { get; set; }
}
which then means you can simply do:
var obj = new Foo();
obj.Id = "Any Old Rubbish";
Is there a way around this at all?
Short sample:
class Program
{
static void Main()
{
var obj = new Foo();
Console.WriteLine(obj.Id);
var serialize = JsonConvert.SerializeObject(obj);
var deserialize = JsonConvert.DeserializeObject<Foo>(serialize);
Console.WriteLine(deserialize.Id);
Console.ReadLine();
}
}
class Foo
{
public Foo() => Id = Guid.NewGuid().ToString();
public string Id { get; }
}
Output:
7868a298-f20d-4719-85ef-ba64c8658819
34fe422c-9555-4d17-ae1a-9fbf21af1b71

The following image (it is not done by me but is found in this question) shows how the algorithm for JsonConvert.DeserializeObjectworks. As you can see the constructor of the serialized type is called almost always. That's why you have to use a constructor with parameters as the left most path of the image shows.
The following shows a modification of your example using a constructor with parameters.
class Program
{
static void Main()
{
var obj = new Foo(Guid.NewGuid().ToString());
Console.WriteLine(obj.Id);
var serialize = JsonConvert.SerializeObject(obj);
var deserialize = JsonConvert.DeserializeObject<Foo>(serialize);
Console.WriteLine(deserialize.Id);
Console.ReadLine();
}
}
class Foo
{
public Foo(String Id) => this.Id = Id;
public string Id { get; }
}
This will result in having the same guid before and after serialization while there is no need to use public string Id { get; set;} as you didn't want to.

Related

Serialization when inheriting from Dictionary

I'm using System.Web.Script.Serialization.JavaScriptSerializer to serialize / deserialize a class that extends Dictionary.
The problem is, my custom properties are not being serialized. Here is my class:
public class Test : Dictionary<string, object> {
public ushort Id { get; set; }
public string Name { get; set; }
}
And my code:
var jss = new JavaScriptSerializer();
var test = new Test {
Id = 123,
Name = "test"
};
var json = jss.Serialize(test);
The result in json is an empty json {}
I do not want to depend on Newtonsoft or JSON.Net or any other library.
ADDITIONAL INFO
I just noticed some, hm, peculiarities, when using both dynamic and object:
JavaScriptSerializer defaults any number value to int.
Also, Newtonsoft defaults any number to long.
That can cause casting exceptions in a class using property indexer (as suggested in the accepted answer), for example:
public class Test : Dictionary<string, dynamic> {
public ushort Id { get => this[nameof(Id)]; set => this[nameof(Id)] = value; }
}
The Id property getter will try to implicitly convert int to ushort, which will fail.
ADDITIONAL INFO 2
I just found out so many weird behaviors with Newtonsoft:
I added these attributes to solve the 'long to ushort' problem:
[JsonObject(MemberSerialization.OptIn)]
public class Test : Dictionary<string, dynamic> {
[JsonProperty]
public ushort Id { get => this[nameof(Id)]; set => this[nameof(Id)] = value; }
}
The above works! But when the property is a reference type:
[JsonObject(MemberSerialization.OptIn)]
public class Test : Dictionary<string, dynamic> {
[JsonProperty]
public ushort Id { get => this[nameof(Id)]; set => this[nameof(Id)] = value; }
[JsonProperty]
public Test Child { get => this[nameof(Child)]; set => this[nameof(Child)] = value; }
}
It tries to get the property before serializing it, resulting in a 'key not found exception'. I can't see why it tries to get the property only when it's a reference type, seems like a bug to me...
So you have to do something like this:
public Test Child { get => this.ContainsKey(index) ? this[nameof(Child)] : null; ... }
Just to summarize the comments:
MSDN recommends using JSON.NET even on JavaScriptSerializer's own docs
Composition will allow you to use JavaScriptSerializer in this case (instead of inheritance)
To work with existing data structure (inheritance), you would have to implement your own version of JavaScriptObjectDeserializer (https://referencesource.microsoft.com/#system.web.extensions/Script/Serialization/JavaScriptObjectDeserializer.cs,2f8d1f9fbf43dbfa)
The default serializer only supports attribute to ignore attribute (not include/rename)
To use composition, you would just need to modify your test object like this:
public class Test
{
public ushort Id { get; set; }
public string Name { get; set; }
public Dictionary<string, object> Items { get; set; } = new Dictionary<string, object> {};
}
Then the following code would work fine:
var jss = new JavaScriptSerializer();
var test = new Test
{
Id = 123,
Name = "test",
};
test.Items.Add("A", 1);
var json = jss.Serialize(test);
The output would just be:
{"Id":123,"Name":"test","Items":{"A":1}}
UPDATE: Property Indexer
You could add a default indexer to your class so that the following code would work:
test["A"] = 1;
var result = test["A"];
Here is the code to add for the default indexer:
public object this[string key]
{
get { return this.Items[key]; }
set { this.Items[key] = value; }
}
You could extend this into implementing IDictionary I suppose, but I imagine just working with the composition should be easiest.

How to serialize using JSONCONVERT a static variable of the class which is initialized by an instance of the class itself in C# [duplicate]

This question already has answers here:
Json.net serialize specific private field
(2 answers)
JSON.net: how to deserialize without using the default constructor?
(6 answers)
Closed 5 years ago.
My C# class has the following structure
public class Example
{
public static Example Instance1 = new Example (0, "A");
public static Example Instance2 = new Example (1, "B");
protected Example(int value, string name)
{
this.value = value;
this.name = name;
}
private int value;
private string name;
}
Now I am trying to serialize Example.Instance1 as follows
var serializedVariable = JsonConvert.SerializeObject(Example.Instance1);
var OriginalVariable = JsonConvert.DeserializeObject<Example>(serializedVariable);
But it throws the exception that it does not have the constructor specified for JSON, but the value and name are lost in the deserialized version.
Now I added a parameter called [JsonConstructor] for the constructor. It does deserialize successfully but the name and value are lost in the deserialized class.
Can you please help me with, how to serialize such class instances?
The issue is that your Example class does not have a default constructor. When you do not define a constructor in the class definition, the compiler will provide you with one implicitly
(see this answer); however, if do define an overloaded constructor (as you did), the compiler will no longer provide you with a default constructor.
In order to deserialize and instantiate and instance of a class (which is all done through reflection), your class must have a default constructor. See this question.
The code below should now work as expected:
public class Example
{
public static Example Instance1 = new Example (0, "A");
public static Example Instance2 = new Example (1, "B");
//Must have this default constructor!
protected Example()
{//... Add code if needed
}
protected Example(int value, string name)
{
this.value = value;
this.name = name;
}
private int value;
private string name;
}

c#: how to hide a field which is used only for XML serialization retrocompatibility?

The field is used only during the serialization / deserialization process but I would like to immediately encapsulate it and hide from the class.
Is it possible?
Basically, no.
XmlSerializer only works with public members, so you can't make it internal or private. You can add some attributes to make it less glaring especially in UIs that data-bind:
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public int Foo {get; set; }
but that only masks it. You could also look at IXmlSerializable, but that is a horrible API and most implementations of it are simply buggy - I do not recommend implementing this interface.
But: best practice is that whenever serialization requirements conflict with your model's design: create a dedicated DTO model - one that matches perfectly your chosen serialization library and exists purely for that purpose. And then map between the two. Then you don't have to compromise.
Its not possible with XML-Serialization in C# , if you want to do like that than you should make use of DataContractSerialization, It allows this kind of functionality i.e. you can serialize private field of you object.
Below is possible with DataContractSerialization, I hope you like to try out
[DataContract]
class Person
{
[DataMember]
public string m_name;
[DataMember]
private int m_age;
}
This what I tried when I was learning XML to Linq , and this is wired solution but if you want to try , here i created xml string by using xml to linq
here is my article : Object to XML using LINQ or XmlSerializer
Note : here code field of product class is private field but still you can generate xml string
using System.Collections.Generic;
using System.Xml.Linq;
using System.Linq;
class Program
{
public class Product
{
public Product()
{ }
public Product(string name,int code, List<productType> types)
{
this.Name = name;
this.Code = code;
this.types = types;
}
public string Name { get; set; }
private int Code { get; set; }
public List<productType> types { get; set; }
public string Serialize(List<Product> products)
{
XElement productSer = new XElement("Products",
from c in products
orderby c.Code
select new XElement("product",
new XElement("Code", c.Code),
new XElement("Name", c.Name),
new XElement("Types", (from x in c.types
orderby x.type//descending
select new XElement("Type", x.type))
))
);
return productSer.ToString();
}
}
public class productType
{
public string type { get; set; }
}
public static void Main()
{
List<productType> typ = new List<productType>();
typ.Add((new productType() { type = "Type1" }));
typ.Add((new productType() { type = "Type2" }));
typ.Add((new productType() { type = "Type3" }));
List<Product> products =new List<Product>() { new Product ( "apple", 9,typ) ,
new Product ("orange", 4,typ ),
new Product ("apple", 9 ,typ),
new Product ("lemon", 9,typ ) };
Console.WriteLine(new Product().Serialize(products));
Console.ReadLine();
}
}
Assuming you are using XmlSerializer, then only public fields and properties can be serialized, as explained in Troubleshooting Common Problems with the XmlSerializer:
The serializer examines all public fields and properties of the Type to learn about which types an instance references at runtime. It then proceeds to create C# code for a set of classes to handle serialization and deserialization using the classes in the System.CodeDOM namespace.
So, what are your options? If you are able to construct your XmlSerializer directly, you could make use of the XmlSerializer.UnknownElement event to forward the unknown elements to the object being deserialized for processing.
First, define the following attribute and extension methods:
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple = false)]
public class XmlUnknownElementEventHandlerAttribute : System.Attribute
{
}
public static partial class XmlSerializationHelper
{
public static T LoadFromXml<T>(this string xmlString, XmlSerializer serial = null)
{
serial = serial ?? new XmlSerializer(typeof(T));
serial.UnknownElement += UnknownXmlElementEventHandler;
using (StringReader reader = new StringReader(xmlString))
{
return (T)serial.Deserialize(reader);
}
}
public static void UnknownXmlElementEventHandler(object sender, XmlElementEventArgs e)
{
var obj = e.ObjectBeingDeserialized;
foreach (var method in obj.GetType().BaseTypesAndSelf()
.SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
.Where(m => Attribute.IsDefined(m, typeof(XmlUnknownElementEventHandlerAttribute))))
{
method.Invoke(obj, BindingFlags.Public | BindingFlags.NonPublic, null, new object[] { sender, e }, null);
}
}
}
public static class TypeExtensions
{
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}
}
Next, say you have some class like:
public partial class MyClass
{
public string MyValue { get; set; }
}
And some XML containing an element that needs to be post-processed and converted into the current model, e.g. <OldValue>:
<MyClass><OldValue>Hello</OldValue></MyClass>
Then add a method to MyClass that:
Can be private or internal (in full trust) or public;
Has the same signature as XmlElementEventHandler;
Is marked with your custom attribute [XmlUnknownElementEventHandler];
Performs the necessary post-processing on the old element.
And now the unknown element will be forwarded to it when using a serializer constructed by XmlSerializationHelper.LoadFromXml().
E.g., your method might look like:
public partial class MyClass
{
[XmlUnknownElementEventHandler]
void HandleOldElement(object sender, XmlElementEventArgs e)
{
if (e.Element.Name == "OldValue")
{
Debug.WriteLine("{0}: processed property {1} with value {2}", this, e.Element.Name, e.Element.OuterXml);
MyValue = "Old value was: " + e.Element.InnerText;
}
}
}
And you would deserialize as follows:
var model = xmlString.LoadFromXml<MyClass>();
One advantage of this solution is that it doesn't modify the XSD generated for your types in any way.
Sample fiddle. (Note that, because the dotnetfiddle code executes in partial trust, the handlers must be public. That's not necessary in full trust.)

unable to create an xml file from dictionary [duplicate]

This question already has answers here:
Why doesn't XmlSerializer support Dictionary?
(3 answers)
Closed 9 years ago.
i'm using this class
public class Branch
{
public string Name { get; set; }
public User Manager { get; set; }
public User Secretary { get; set; }
public Dictionary<string, User> Broker;
public Dictionary<string, Apartment> Apartments;
public Branch()
{}
public Branch(Branch other)
{
Name = other.Name;
Manager = other.Manager;
Secretary = other.Secretary;
Broker = other.Broker;
Apartments = other.Apartments;
}
}
trying to run this line : Dict2XML.Save_Branch2XML(Branchs);
through this method:
static public void Save_Branch2XML(Dictionary<string, Branch> D)
{
//List<KeyValuePair<string, User>> DictionList = D.ToList();
List<Branch> DictionList = D.Select(p => new Branch(p.Value)).ToList<Branch>();
XmlSerializer Serializer = new XmlSerializer(DictionList.GetType());
TextWriter writer = new StreamWriter(#"C:\Users\tzach_000\Documents\Visual Studio 2013\Projects\RealEstate\RealEstate\DB\XMLBranch.xml");
Serializer.Serialize(writer, DictionList);
writer.Close();
}
and the program collapse when it gets to the XmlSerializer line in save_branch2xml method.
The XmlSerializer doesn't support dictionaries, I don't think it changed for all these years. There are multiple workarounds, two of them could be recommended.
First, change the internal data structure for one that is serializable. A list of pairs would do.
Second, use the DataContractSerializer rather than the xml serializer. The data contract serializer supports serialization of dictionaries.
See this thread
Serialize Class containing Dictionary member
You can use SerializableDictionary if you really want.

Reading from attribute in .NET [duplicate]

This question already has answers here:
Read the value of an attribute of a method
(6 answers)
Closed 9 years ago.
In all of the tutorials out there for custom attributes they teach us how to create and define custom attributes which is no more than simple comment about the class/method.
I am trying to figure out how can I read from those custom attributes in .NET inside some method.
For example:
[SomeCustomAttr(param1, param2)]
public void Method1()
{
read param1 from here
read param2 from here
}
There are really great frameworks out there which do work with the entered data. Does anyone can give me some direction how to deal with this problem ?
Assuming that the parameters you refer to are properties of the custom attribute class:
class Program
{
static void Main(string[] args) {
Test();
Console.Read();
}
[Custom(Foo = "yup", Bar = 42)]
static void Test() {
// Get the MethodBase for this method
var thismethod = MethodBase.GetCurrentMethod();
// Get all of the attributes that derive from CustomAttribute
var attrs = thismethod.GetCustomAttributes(typeof(CustomAttribute), true);
// Assume that there is just one of these attributes
var attr1 = (CustomAttribute)attrs.Single();
// Print the two properties of the attribute
Console.WriteLine("Foo = {0}, Bar = {1}", attr1.Foo, attr1.Bar);
}
}
class CustomAttribute : Attribute
{
public string Foo { get; set; }
public int Bar { get; set; }
}
Note that attributes are a little special, in that they can take named parameters (which correspond to public property names), without declaring any constructor.
Reflection is the right way to get the attribute.
var TypeObj = typeof(Type1);
var MethodInfoObj = TypeObj.GetMethod("Method1");
// var AllAttributes= MethodInfoObj.GetCustomAttributes(true);
var Attributes = MethodInfoObj.GetCustomAttributes(typeof(SomeCustomAttr), true);
if (Attributes.Length > 0)
{
var AttributeObj = Attributes[0] as SomeCustomAttr;
var value_param1 = AttributeObj.param1 ;
}

Categories

Resources