Design of Serializing classes - c#

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.

Related

Changing method Attributes at runtime

I am trying to serialize objects into xml. I have setup up
public class Foo<t>
{
[XmlElement(ElementName ="test")]
public <t> bar {
get
{
var descriptor = TypeDescriptor.GetProperties(this.GetType())["bar"];
var attrib =(XmlElementAttribute)descriptor.Attributes[typeof(XmlElementAttribute)];
FieldInfo ElementName = attrib.GetType().GetProperty("ElementName")
ElementName.SetValue(attrib, "success");
}
set{}
}
I want to change XmlElement.ElementName at run time but so far have been unsucessfull.
According to this blog you should be able to do it. Also this SO post indicates that I am on the right track.
My Questions are Is what I want to do possible? How do I achieve this?
EDIT:
I want the xml node to be called 'Success' instead of 'test'
The technique in that article only works for .NET components that depend on the TypeDescriptor system, which is a higher level abstraction than raw reflection. XmlSerializer is not one of those components as far as I know.
The closest you can come to "changing attributes at runtime" with respect to XmlSerializer is using XmlAttributeOverrides, but I forget how to use that because I've used it so infrequently. That only allows you to change them for the entire type though, not individual instances as you seem to want. This is partly because XmlSerializer actually compiles a serialization delegate internally that it uses over and over to serialize your type for reasons of performance.
Your best bet is probably to just implement the IXmlSerializable interface to customize the serialization for that particular class. XmlSerializer will honor that interface, and it will allow you to have 100% control over the XML by using XmlReader / XmlWriter. It is more difficult to have to manually write the serialization code, but you have much more control. And you only have to do it for the types in your graph that require custom handling. For an example of using IXmlSerializable see my answer to Override XML Serialization Method.

JSON writer - drop in replacment for xmlwriter?

Without having spent a lot of time on this subject, I'm curious what might be the most straightforward way to allow my existing code to serialize to json in addition to xml. The existing code uses a xmlwriter to perform some sophisticated serialization for a specific purpose, so ultimately I'd like to be able to pass a jsonserializer in place of the xml one and have it produce json instead of xml.
Do any of the json libs handle something like this?
No, there's no direct drop-in replacement. The APIs for existing JSON serializers is much different. They need to have the entire model in memory and serialize it in one step. For example with JSON.NET you would use:
string json = JsonConvert.SerializeObject(product);
The correct way to achieve what you are looking for is to abstract the actual serialization of the object behind an interface:
public interface IMySerializer
{
void Serialize(MyObject instance, Stream stream);
}
Now you could have multiple implementations of this interface such as MySerializerXml, MySerializerJson, MySerializerCsv, ...
Now the code that depends on the serialization would simply work with an IMySerializer. So when you need to handle a new format all you have to do is drop-in an implementation of this interface.
There is no direct replacement for an XmlWriter. If you want to support both XML and JSON, I would suggest serialising via data-contracts, i.e. use attributes on your data objects to indicate the desired serialised format. Take a look at DataContractJsonSerializer for JSON and DataCOntractSerializer for XML.
Your model objects would look something like this:
[DataContract(Name = "Customer", Namespace = "http://www.contoso.com")]
class Person
{
[DataMember()]
public string FirstName;
[DataMember]
public string LastName;
[DataMember()]
public int ID;
}

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.

Using XmlSerializer with private and public const properties

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 { } }

Is there a way to do object (with its attributes) serializing to xml?

Create a class (call it FormElement). That class should have some properties like the metadata they have with data elements (name, sequence number, value—which is just a string, etc).
This class has as attributes of type Validation Application Block Validation classes.
I want to serialize it to xml and deserialize it. Verify that all properties of the class including the validation application block attributes survive serialization.
some suggestion?
The .NET framework has this built in, using C# you would do it like this:
// This code serializes a class instance to an XML file:
XmlSerializer xs = new XmlSerializer(typeof(objectToSerialize));
using (TextWriter writer = new StreamWriter(xmlFileName))
{
xs.Serialize(writer, InstanceOfObjectToSerialize);
}
And this snippet is an example of how to deserialize an XML file back to a class instance:
// this code creates a class instance from the file we just made:
objectToSerialize newObject;
XmlSerializer xs = new XmlSerializer(typeof(objectToSerialize));
using (TextReader reader = new StreamReader(xmlFileName))
{
newObject = (ObjectToSerialize) xs.Deserialize(reader);
}
You must mark your class with the [Serializable] attribute for these to work. If you want to make your XML output a little more pretty, you can use [XmlElement] and [XmlAttribute] attributes on your class properties to have them serialize into your schema of choice.
By saying serialize, do you mean use the official Serialization mechanism, or achieve a similar effect?
If your objects are beans, you could use reflection to write a general service that takes a class and writes down its class name and properties. It can similarly read materials from the XML and generate the object (which is what Apache Digester essentially does).
What Jonathon Holland said.
However, you also asked about validation. If you use the code Jonathan posted, all of your properties will serialize and de-serialize correctly. But if you really want to check it, there is a property you can set with your XmlSerializer object for a *.xsd schema to validate against. You can create the schema easily enough from your class by using the xsd.exe command-line tool that is included with Visual Studio.
Also, it sounds like you might want to control whether certain properties of your class are serialized as attributes or elements. Jonathon touched on that, but I want to show an example:
[Serializable]
public class FormElement
{
[XmlAttribute]
public string Name {get; set;};
[XmlAttribute]
public int Sequence {get; set;};
[XmlAttribute]
public string Value {get; set;};
[XmlElement]
public Validation OnValidate{get; set;}
[NonSerialized]
public string UnimportantProperty {get; set;};
}
Finally, the type for every property that you want to serialize must also be serializable, and complicated types must be serialized as XmlElements. Otherwise you won't be able to do it.
XStream is a pretty good java library for doing just that.

Categories