Ensure values exist when converting from xml - c#

I have a utility that converts an xml file to a class object:
public static T CreateClassFromXml<T>(string fileName, string root) where T : class
{
fileName.ThrowNullOrEmpty("fileName");
File.Exists(fileName).ThrowFalse(string.Format("File '{0}' could not be found", fileName));
var serializer = new XmlSerializer(typeof(T), new XmlRootAttribute() { ElementName = root });
using (var reader = XmlReader.Create(fileName))
{
return (T)serializer.Deserialize(reader);
}
}
The utility reads the xml and creates a class T. Using the above code is there any way I can validate the created class other than writing a wrapper class around it? I need to ensure that data is populated for all mandatory fields.

There are no built in facilities in XmlSerializer to do this. You can do it yourself with reflection. Since XmlSerializer loads just the public properties and fields, you can iterate over all public properties and fields of the class and make sure they all hold data. You'll have to decide how to handle value types (int, DateTime, etc...) because it's not obvious when the have been loaded or not. You will also have to dive in recursively into reference types.
If you need to mark just specific properties\fields as mandatory, you can add your own attribute and decorate the class members with it. In runtime, you will only process properties which have the attribute set.
In short, unless you need a generic mechanism for many different scenarios, better do it manually for the properties you have to validate.

Related

Best way to create an XML document and save to a file

I have an object that I want to create an XML from, what's the best way to do this in ASP.NET 3.5?
I want to save it to a file also (web application).
I don't want to serialize the object, since I will have some custom element names and attributes and values that will be modified during XML creation.
It is a bit hard to answer without knowing how "custom" is "custom", but LINQ-to-XML is a good bet since you have .NET 3.5:
// using variables here to show how the names etc can be decided at runtime
string elName = "Fred";
DateTime when = DateTime.Today;
int id = 123;
string idName = "id";
var el = new XElement(elName, new XAttribute(idName, id), when);
el.Save("out.xml");
Giving the xml:
<Fred id=\"123\">2010-03-01T00:00:00+00:00</Fred>
If the file is huge, then XmlWriter may be more efficient, but the code is harder.
If you don't want to serialize you could use XmlWriter.
You should use System.Xml.Linq, which is the easiest way to manipulate XML by far.
Since you will have dynamic document, I'd suggest System.Xml.Linq.XDocument to generate it. Then you just use XDocument.Save to save it.
You can use the System.Xml namespace.
using System.Xml;
XmlDocument document = new XmlDocument();
XmlNode rootNode = document.CreateElement("root");
document.AppendChild(rootNode);
// Create other nodes related to your object and append them to the root node.
document.Save("path/to/your/xml/file.xml");
I used XmlDocument before I learned about serialization.
Why not implement the ISerializable interface? Then you have full control over the serialization process yourself...
See examples here:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx
and here:
http://msdn.microsoft.com/en-us/library/ms182342(VS.80).aspx
You can combine this with XmlSerializer, if you have a complex object you need to serialize, an you don't want to write all of the serialization yourself.
If it's just part of the object (i.e. some properties) you want to do special serialization of, you can make these objects that implements ISerializable, and change the value to whatever you need it to be, during serialization.
Consider creating a helper class that uses XML serialization. That decouples the XML formatting from the main class's design, and generally speaking is in keeping with the idea of adding functionality to classes through composition. (In fact, it's often a good idea to do it this way even if the helper class doesn't use XML serialization.) It also lets you format the XML declaratively without getting having to write a lot of procedural code.
How to do this: design the helper class so that it exposes public properties in a fashion that XmlSerializer likes, and gets those values from an instance of your class that's passed in to a private constructor. Add a static XmlSerializer property, and a public static method that uses the XmlSerializer to write the data to a file or a stream or whatever. Something like:
[XmlRoot("MyClass")]
public class MyClassXmlWriter
{
private static XmlSerializer Serializer = new XmlSerializer(typeof MyClassXmlWriter);
public static void Write(MyClass source, Stream st)
{
Serializer.Serialize(new MyClassXmlWriter(source), st);
}
private MyClass Source;
private MyClassXmlWriter(MyClass source)
{
Source = source;
}
[XmlElement("SomeElement")]
public string SomeProperty { get { return Source.SomeProperty; } }
}
Using this is as simple as:
using (FileStream fs = new FileStream(filename))
{
MyClassXmlWriter.Write(myObject, fs);
}
Note that if you ever need to implement deserialization, you just give its properties public getters and then implement a static Read method that deserializes into a new MyClassXmlWriter object and then creates and populates a MyClass object from its properties. (You'd probably change the name of the class, though.)

Creating an extensible properties class (OOP)

I have an application which supports multiple types and versions of some devices. It can connect to these devices and retrieve various information.
Depending on the type of the device, I have (among other things) a class which can contain various properties. Some properties are common to all devices, some are unique to a particular device.
This data is serialized to xml.
What would be a preferred way to implement a class which would support future properties in future versions of these devices, as well as be backwards compatible with previous application versions?
I can think of several ways, but I find none of them great:
Use a collection of name-value pairs:
pros: good backward compatibility (both xml and previous versions of my app) and extensibility,
cons: no type safety, no intellisense, requires implementation of custom xml serialization (to handle different value objects)
Create derived properties class for each new device:
pros: type safety
cons: have to use XmlInclude or custom serialization to deserialize derived classes, no backward compatibility with previous xml schema (although by implementing custom serialization I could skip unknown properties?), requires casting for accessing properties in derived classes.
Another way to do it?
I am using C#, by the way.
How about something similar to a PropertyBag ?
If you're not limited to interoperability with an external schema, then you should use Runtime Serialization and the SoapFormatter. The pattern for runtime serialization permits derived classes to specify which of their properties need to be serialized and what to do with them when deserialized.
The XML Serializer requires XmlInclude because, in effect, it needs to define the schema to use.
I like name/value sets for this sort of thing.
Many of your cons can be dealt with -- consider a base class that acts as a general name/value set with no-op methods for validating incoming name/value pairs. For known sets of names (i.e. keys), you can create derived classes that implement validation methods.
For example, Printer may have a known key "PrintsColor" that can only be "true" or "false". If someone tries to load PrintsColor = "CMYK", your Printer class would throw an exception.
Depending on what you're doing, you can go a few different ways in terms of making the validation more convenient -- utility methods in the base class (e.g. checkForValidBoolean()) or a base class that accepts name/type information in its constructor for cleaner code in your derived classes, and perhaps a mostly automated XML serialization.
For intellisense -- your derived classes could have basic accessors that are implemented in terms of the key lookup. Intellisense would present those accessor names.
This approach has worked well for me -- there's sort of a short-sightedness to classic OO design, especially for large systems with plugged-in components. IMO, the clunkier type checking here is a big of a drag, but the flexibility make it worthwhile.
I believe that creating derived properties is the best choice.
You can design your new classes using xml schema. And then just generate the class code with xsd.exe.
With .net isn't hard to develop a generic class that can serialize and deserialize all types to and from xml.
public static String toXmlString<T>(T value)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringWriter stringWriter = new StringWriter();
try { xmlSerializer.Serialize(stringWriter, value); }
catch (Exception e)
{
throw(e);
}
finally { stringWriter.Dispose(); }
String xml = stringWriter.ToString();
stringWriter.Dispose();
return xml;
}
public static T fromXmlFile<T>(string fileName, Encoding encoding)
{
Stream stream;
try { stream = File.OpenRead(fileName); }
catch (Exception e)
{
e.Data.Add("File Name", fileName);
e.Data.Add("Type", typeof(T).ToString());
throw(e);
}
BufferedStream bufferedStream = new BufferedStream(stream);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
TextReader textReader;
if (encoding == null)
textReader = new StreamReader(bufferedStream);
else
textReader = new StreamReader(bufferedStream, encoding);
T value;
try { value = (T)xmlSerializer.Deserialize(textReader); }
catch (Exception e)
{
e.Data.Add("File Name", fileName);
e.Data.Add("Type", typeof(T).ToString());
throw(e);
}
finally
{
textReader.Dispose();
bufferedStream.Dispose();
}
return value;
}
Programatically speaking, this sounds like it might be a job for the Decorator Pattern. Essentially, you have a super class which defines a common interface for all these types of devices. Then you have decorator classes which have other properties which a device might have. And, when creating these devices, you can dynamically add these decorations to define new properties for the device. Graphically:
You can look at the Wikipedia page for a more detailed description. After that, it would just be a matter of doign some serialization to tell the program which decorators to load.
The general idea of what you're trying to accomplish here is precisely what the EAV pattern solves. EAV is a pattern most commonly used in database development but the concept is equally valid for applications.

How can I add a type constraint to include anything serializable in a generic method?

My generic method needs to serialize the object passed to it, however just insisting that it implements ISerializable doesn't seem to work. For example, I have a struct returned from a web service (marked with SerializableAttribute) that serializes to xml just fine, but, as expected, the C# compiler complains.
Is there a way I can check the object is serializable before attempting to serialize it, or, better still, a way of using the where keyword to check the object is suitable?
Here's my full method:
public static void Push<T>(string url, T message)
where T : ISerializable
{
string xml = SerializeMessage(message);
// Send the message to Amazon SQS
SendMessageRequest sendReq = new SendMessageRequest { QueueUrl = url, MessageBody = xml };
AmazonSQSClient client = new AmazonSQSClient(S3User, S3Pass);
client.SendMessage(sendReq);
}
And SerializeMessage:
private static string SerializeMessage<T>(T message)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (StringWriter stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, message);
return stringWriter.ToString();
}
}
If this isn't possible, what's the best way to perform a check that an object is serializable at runtime?
You can't do this totally via generic constraints, but you can do a couple things to help:
1) Put the new() constraint on the generic type (to enable the ability to deserialize and to ensure the XmlSerializer doesn't complain about a lack of default ctor):
where T : new()
2) On the first line of your method handling the serialization (or constructor or anywhere else you don't have to repeat it over and over), you can perform this check:
if( !typeof(T).IsSerializable && !(typeof(ISerializable).IsAssignableFrom(typeof(T)) ) )
throw new InvalidOperationException("A serializable Type is required");
Of course, there's still the possibility of runtime exceptions when trying to serialize a type, but this will cover the most obvious issues.
I wrote a length blog article on this subject that you may find helpful. It mainly goes into binary serialization but the concepts are applicable to most any serialization format.
http://blogs.msdn.com/jaredpar/archive/2009/03/31/is-it-serializable.aspx
The long and short of it is
There is no way to add a reliable generic constraint
The only way to check and see if an object was serializable is to serialize it and see if the operation succeeds
The only way to know if an object is serializable is to try to serialize it.
In fact, you were asking how to tell if a type "is serializable", but the actual question will be with respect to objects. Some instances of a type may not be serializable even if the type is marked [Serializable]. For instance, what if the instance contains circular references?
Instead of
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
try
XmlSerializer xmlSerializer = new XmlSerializer(message.GetType());
C# 8 and up allows the unmanaged constraint to limit types to structs that have nothing but value types in them (on any nested level). What we really want is:
public class MyClass<T> where T : ISerializable or unmanaged
But unfortunately, at the time of writing C# does not support this syntax (constraints are always AND, separated by commas).
A workaround could be a ValueWrapper class:
public class ValueWrapper<U> : ISerializable where U : unmanaged
This takes a U for a constructor argument. It has one property U Value. Now you can treat value types as ISerializable simply by wrapping them in a ValueWrapper.

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.

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