Using XmlSerializer with private and public const properties - c#

What's the simplest way to get XmlSerializer to also serialize private and "public const" properties of a class or struct? Right not all it will output for me is things that are only public. Making it private or adding const is causing the values to not be serialized.

XmlSerializer only looks at public fields and properties. If you need more control, you can implement IXmlSerializable and serialize whatever you would like. Of course, serializing a constant doesn't make much sense since you can't deserialize to a constant.

Even though it's not possible to serialize private properties, you can serialize properties with an internal setter, like this one :
public string Foo { get; internal set; }
To do that, you need to pre-generate the serialization assembly with sgen.exe, and declare this assembly as friend :
[assembly:InternalsVisibleTo("MyAssembly.XmlSerializers")]

Check out DataContractSerializer, introduced in .NET 3.0. It also uses XML format, and in many ways, it is better than XmlSerializer, including dealing with private data.
See http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/ for a full comparison.
If you only have .NET 2.0, there's the BinarySerializer that can deal with private data, but of course it's a binary format.

It doesn't make sense to consider const members, as they aren't per-instance; but if you just mean non-public instance members: consider DataContractSerializer (.NET 3.0) - this is similar to XmlSerializer, but can serialize non-public properties (although it is "opt in").
See here for more.

One other solution the use of Newtonsoft.Json:
var json = Newtonsoft.Json.JsonConvert.SerializeObject(new { root = result });
var xml = (XmlDocument)Newtonsoft.Json.JsonConvert.DeserializeXmlNode(json);
Sure, this one has unfortunately detour via json.

Here's my solution to putting immutable values in a property that will serialize to XML:
[XmlElement]
public string format { get { return "Acme Order Detail XML v3.4.5"; } set { } }

Related

when we serialize serializable object using JSON.Net, JSON string is different from DatacontractJSON serializer

I have a class some thing like below
[Serializable]
public class sample
{
private int m_width;
private int m_height;
public int Width
{
get
{
return this.m_width;
}
set
{
this.m_width = value;
}
}
public int Height
{
get
{
return this.m_height;
}
set
{
this.m_height = value;
}
}
}
If I use DataContractJsonSerializer to serialize the object of this class i get the json string as below:
{"m_height":1345,"m_width":1234}
If I use Newtonsoft.Json.dll to serialize this I am getting the out put like below:
{"Width":1234,"Height":1345}
Why DataContractSerializer using backing fields for serialization if class marked as serializable ?
Is there any way I can achieve the same thing using Newtonsoft.Json.dll
We have some objects which are marked as [Serializable] so they can be serialised using traditional methods, but which we need to have cleanly serialised in JSON for use with Web API. Setting IgnoreSerializableAttribute to true will stop Newtonsoft.Json from behaving like Microsoft's serialisers and instead it will just serialise the public properties.
TLDR: Add this to WebApiConfig.cs:
((Newtonsoft.Json.Serialization.DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;
Unless you are always communicating from WCF to WCF, your best bet is probably going to be to use the Newtonsoft serializer. Unfortunately, the MS serializer seems to follow some Microsoft-specific standards that do not match the standards that many web apps expect.
Newtonsoft's serializer seems to be more standard, and even MS uses it for WebAPI, and in the Web API http client (nuget will pull it down for you).
Here's another difference that you will find -- try serializing a DateTime type. You will find that the DataContract serialzer serializes the value in a different format that is not compatible with other JSON (you will notice some slashes in it). My understanding is that that alternate format was used by some of the AJAX WebForm controls, but it's specific to Microsoft Webforms.
Here's a little more info about the dates: http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
Here's another thing you might look at:
The differences between DataContractJsonSerializer and Newtonsoft still stand, but as for why you are getting the weird serialization behavior -- you are mixing your serialization standards.
The [Serializable] attribute pertains to the older .Net serialization. DataContractSerialization is backward compatible, but the behavior might be different.
If you want to do this the datacontract way, mark you class with the
[DataContract] attribute instead, and mark each public member that you want to serialize with the [DataMember] attribute. (or remove all serialization attributes, and it should default to all public properties)
That should explain the difference that are seeing, but I would still recommend that you prefer the Newtonsoft serializer.
DefaultContractResolver class in Newtonsoft.Json.dll i found some code which is setting IgnoreSerializableAttribute property to true.
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE || PORTABLE40)
IgnoreSerializableAttribute = true;
#endif
I am using the DotNet4.0 dll so this property set to true and it is ignoring the Serializable attribute. if i make it false it is giving the same output as DataContractSerializer
DataContract serializer requires you to explicitly mark the class with the [DataContract] attribute and then mark each desired property to be serialized with the [DataMember] attribute.
If you do that you will find that the same json string will get out as using the other class.
The issue you are encountering is due to differences of how the 2 serializers treat the default serialization (without additional information specified):
DataContract serializes all private fields unless otherwise specified
NewtonSoft serializes all public properties unless otherwise specified
On how you can make Newtonsoft serialize the private fields i have no other idea than making a wrapper class with m_Width and m_Height properties that on the setters and geters put the values in the correct target properties of the actual object

Design of Serializing classes

I just learned how to serialize and deserialize objects to XML in C#.
Now I would like to add this functionality to my application, I have a class for the object. Should I create a class that contains the serialize and deserialize methods? Or, should there be an Interface or something?
How is this normally done?
You would be best keeping your object and serialisation mechanism seperate DataContractSerializers are good for this in .Net. They allow data annotations (as mentioned in the comment above) to be specified on properties and automate the actual serialisation for you.
There is an interface (ISerializable), but you also have generic classes that exist and can do the job for you. In that cas you'd have to place the right Attributes for the propertyies you want get serialized.
take a look here if you want the documentation about this.
.Net has some built-in serializers (BinaryFormatter and XmlSerializer
if you go with the interface you'll have to write your own methods
Provided your classes are simple enough for serialization you can do this:
using (FileStream stream = File.Create(filename)){
XmlSerializer serializer = new XmlSerializer(typeof(MyRootClassHere));
serializer .Serialize(stream, yourRootInstance);
}
You may need to take a look at XmlElement, XmlAttribute, XmlIgnore, XmlText attributes to control the output better:
[XmlIgnore]
public bool IgnoredBool{ get; set; }
[XmlAttribute("NewXmlName")]
public string RenamedProperty{ get; set; }
This should get you going for the most part.

Why is XmlSerializer so hard to use?

I imagine to use XML serialization like this:
class Foo {
public Foo (string name) {
Name1 = name;
Name2 = name;
}
[XmlInclude]
public string Name1 { get; private set; }
[XmlInclude]
private string Name2;
}
StreamWriter wr = new StreamWriter("path.xml");
new XmlSerializer<Foo>().Serialize (wr, new Foo ("me"));
Edit: I know this code is wrong. It was just to display how I would like to use it.
But this does not work at all:
XmlSerializer is not generic. I have to cast from and to object on (de)serialization.
Every property has to be fully public. Why aren't we just using Reflection to access private setters?
Private fields cannot be serialized. I'd like to decorate private fields with an attribute to have XmlSerializer include them.
Did I miss something and XmlSerializer is actually offering the described possibilities? Are there alternate serializers to XML that handle these cases more sophisticatedly?
If not: We're in 2010 after all, and .NET has been around for many years. XML serialization is often used, totally standard and should be really easy to perform. Or is my understanding possibly wrong and XML serialization ought not to expose the described features for a good reason?
Edit: Legacy is not a good reason imo. Listwas nongeneric at first, too.
(Feel free to adjust caption or tags. If this should be CW, please just drop a note.)
See XmlSerializer class. You'll see you're using it wrong. XmlInclude has a totally different purpose.
You're right. The XML Serializer has been around since .NET 1.0. That's before we had generics, BTW, so it's unlikely to support them.
Also, better technologies have arrived since then:
The DataContractSerializer is faster, and supports serializing as binary
LINQ to XML can be used in many serialization scenarios, and is much more flexible
The XML Serializer is unlikely to be enhanced in the future. I recommend you learn the other alternatives.
First the fixed code, then the answers to your questions:
public class Foo {
public Foo() : this("") {}
public Foo (string name) {
Name1 = name;
Name2 = name;
}
// note only this will be serialized
public string Name1 { get; private set; }
// this won't
private string Name2;
}
or in 3.0:
[DataContract]
class Foo {
public Foo (string name) {
Name1 = name;
Name2 = name;
}
[DataMember]
public string Name1 { get; private set; }
[DataMember]
private string Name2;
}
(and use DataContractSerializer instead of XmlSerializer)
XmlSerializer is not generic. I have to cast from and to object on (de)serialization.
That is common for serializers. I have my own serializer, and initially I did make it fully generic. And it turned out to be a big design mistake. Huge. No, seriously. I'm currently in the process of re-writing every line of code to switch it out.
Simply; serializers generally involve some level of reflection (either for code-gen or for the actual work, depending on the implementation). Reflection and generics don't play nicely, especially on some of the frameworks like WCF. Having your code do the final cast is a fair compromise. I have a number of blog entries on this if you really want...
Every property has to be fully public.
That is indeed a limitation of XmlSerializer (although a list/colletion without a setter is fine, it will throw if you have a public get and private set). Also, the type needs to be public and have a parameterless constructor.
Why aren't we just using Reflection to access private setters?
For performance, XmlSerializer builds an assembly on the fly to do what you want. It doesn't have automatic access to your code's internals. For info, I'm doing something similar but I offer 2 levels of generation; fully static (into a deployable dll), which then only works with public members, or in-memory, which can still access private members. I guess they wanted to settle on only 1 model, which makes sense - and they needed "sgen", which dictates the first model.
Private fields cannot be serialized. I'd like to decorate private fields with an attribute to have XmlSerializer include them.
Then use DataContractSerializer, which will serialize any member (including private) marked [DataMember].
1: legacy. XML Serializer predates generics. It as in with .NET 1.0.
2: Design decision. XML serializer is supposed to work with very limtied rights, compared to other solutions.
3: same as 2.
You can use WCF DataContract serializer in parts.
Your assumption is "limited wrong". XML serialization is supposedly for transfer documents, which - in my projects - are always separate classes doing nothing more. As such, I have no problem with all the limitations.
You don't need the
[XmlInclude]
Like you have it. You can use
[XmlElement]
[XmlAttribute]
...
To describe the way the class is serialized.
Take out the [XmlInclude] and see if that works.
class Foo {
public Foo (string name) {
Name1 = name;
Name2 = name;
}
[XmlAttribute]
public string Name1 { get; set; }
[XmlAttribute]
public string Name2;
}
Foo myFoo = new Foo("FirstName", "LastName");
StreamWriter wr = new StreamWriter("path.xml");
XmlSerializer serializer = new XmlSerializer(typeof(Foo));
serializer.Serialize(wr, myFoo);
Updated, the serialized properties should be public.
By the way DataContract never supports binary serialization , it serializes to xml but supports binary encoding.

C# - what attributes to use to support serializing using both XMLSerializer and DataContractSerializer?

I have some simple POCO object:
public class ProductCategoryDTO
{
public string Name { get; set; }
public DateTime ModifiedDate { get; set; }
}
As sometimes field order is important (for example, if sending to Infopath forms), I need to keep element order when serializing.
And now I am confused, what attributes I should use for the class and for each field. I know that:
DataContractSerializer uses [DataContract] and [DataMember(Order = n)]
XMLSerializer uses [Serializable] and [XmlElementAttribute(Order = n)].
Then what attributes to use if I want to support both XMLSerializer and DataContractSerializer, so it can used in both WCF or ASP. web services?
Strictly speaking, you don't need to use any attributes for either ;-p It used to be that DataContractSerializer would demand [DataContract] / [DataMember] (and they absolutely should be used), but you can use it without (but it then acts in a very dubious way similar to BinaryFormatter). Likewise, XmlSerializer doesn't need anything unless you want to control things. There are, however, some differences you should note:
XmlSerializer demands (and uses) a public parameterless constructor; DataContractSerializer doesn't use a constructor (at all). So watch out for that, and don't (for WCF) rely on code in the ctor - if you have necessary init code, use a serialization callback for WCF.
XmlSerializer demands either public fields (yeuch) or public properties with both get and set (even for lists); DataContractSerializer will happily work against private members, properties with (for example) a public get and private set, and collections without a `set (as long as your type initialises it).
XmlSerializer demands public types; IIRC DataContractSerializer is less fussy
So yes; you can support both serializers, and you can add any number of attributes in parallel, but note the above if you want total compatibility.
Another option is to just use XmlSerializer; you can configure WCF to use XmlSerializer by using [XmlSerialzerFormat]. Both options support inheritance, via [XmlInclude] and [KnownType].
Finally, note that if you implement IXmlSerializable, this takes precedence over either, but it hard to get right. Don't do that unless you have to.
I don't see any reason why you couldn't put both attributes on the class and member properties, if you really must. Doesn't look nice, but if it works for you, that's just fine!
[DataContract(Namespace="....")]
[XmlType]
public class ProductCategoryDTO
{
[DataMember(Order=1)]
[XmlElementAttribute(Order=1)]
public string Name { get; set; }
[DataMember(Order=2)]
[XmlElementAttribute(Order=2)]
public DateTime ModifiedDate { get; set; }
}
Order of XML elements should be dictated by the WSDL and you don't need to worry about it. Starting from .NET 3.5 SP1 you no longer need to use DataContractAttribute and DataMemberAttribute. The serializer will automatically include all public properties. As far as XmlSerializer is concerned, the SerializableAttribute has no effect. This attribute is used for binary serialization by the BinaryFormatter. So to resume, you could leave the class as a POCO, expose it either in WCF or ASP.NET webservice and leave the clients consume it according to the WSDL.

How to use XmlSerializer to deserialize into an existing instance?

Is it somehow possible to use the XmlSerializer to deserialize its data into an existing instance of a class rather than into a new one?
This would be helpful in two cases:
Easily merge two XML files into one object instance.
Let object constructer itself be the one who is loading its data from the XML file.
If the is not possible by default it should work by using reflection (copying each property after the deserialisation) but this would be an ugly solution.
Basically, you can't. XmlSerializer is strictly constructive. The only interesting thing you can do to customize XmlSerializer is to implement IXmlSerializable and do everything yourself - not an attractive option (and it will still create new instances with the default constructor, etc).
Is xml a strict requirement? If you can use a different format, protobuf-net supports merging fragments into existing instances, as simply as:
Serializer.Merge(source, obj);
I think you're on the right track with the Reflection idea.
Since you probably have a wrapper around the XML operations anyway, you could take in the destination object, do the deserialization normally into a new object, then do something similar to cloning by copying over one by one only the properties holding non-default values.
It shouldn't be that complex to implement this, and it would look to consumers from the rest of your application just like in-place deserialization.
I hit the same problem a few weeks ago.
I put a method Deserialize(string serialized form) in the ISelfSerializable interface that an entity class of mine implemented. I also made sure the interface forced the class to have a default constructor.
In my factory I created an object of that type and then deserialized the string into it.
This is not thread safe thing to do... But you can do:
[Serializable]
public class c_Settings
{
static c_Settings Default;
public static SetExistingObject(c_Settings def)
{
Default = def;
}
public string Prop1;
public bool Prop2;
public c_Settings()
{
if (Default == null)
return;
MemberInfo[] members = FormatterServices.GetSerializableMembers(typeof(c_Settings));
FormatterServices.PopulateObjectMembers(this, members, FormatterServices.GetObjectData(Default, members));
}
}
This way you feed your object to deserialiser and deserialiser only overwrites whatever is written in .xml.

Categories