Creating an extensible properties class (OOP) - c#

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.

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.

Implementing a DSL in C# for generating domain specific XML

I have a legacy HTTP/XML service that I need to interact with for various features in my application.
I have to create a wide range of request messages for the service, so to avoid a lot of magic strings littered around the code, I've decided to create xml XElement fragments to create a rudimentary DSL.
For example.
Instead of...
new XElement("root",
new XElement("request",
new XElement("messageData", ...)));
I'm intended to use:
Root( Request( MessageData(...) ) );
With Root, Request and MessageData (of course, these are for illustrative purposes) defined as static methods which all do something similar to:
private static XElement Root(params object[] content)
{
return new XElement("root", content);
}
This gives me a pseudo functional composition style, which I like for this sort of task.
My ultimate question is really one of sanity / best practices, so it's probably too subjective, however I'd appreciate the opportunity to get some feedback regardless.
I'm intending to move these private methods over to public static class, so that they are easily accessible for any class that wants to compose a message for the service.
I'm also intending to have different features of the service have their messages created by specific message building classes, for improved maintainability.
Is this a good way to implement this simple DSL, or am I missing some special sauce that will let me do this better?
The thing that leads me to doubt, is the fact that as soon as I move these methods to another class I increase the length of these method calls (of course I do still retain the initial goal of removing the large volume magic strings.) Should I be more concerned about the size (loc) of the DSL language class, than I am about syntax brevity?
Caveats
Note that in this instance the remote service poorly implemented, and doesn't conform to any general messaging standards, e.g. WSDL, SOAP, XML/RPC, WCF etc.
In those cases, it would obviously not be wise to create hand built messages.
In the rare cases where you do have to deal with a service like the one in question here, and it cannot be re-engineered for whatever reason, the answers below provide some possible ways of dealing with the situation.
Have you noticed that all the System.Linq.Xml classes are not sealed?
public class Root : XElement
{
public Request Request { get { return this.Element("Request") as Request; } }
public Response Response { get { return this.Element("Response") as Response; } }
public bool IsRequest { get { return Request != null; } }
/// <summary>
/// Initializes a new instance of the <see cref="Root"/> class.
/// </summary>
public Root(RootChild child) : base("Root", child) { }
}
public abstract class RootChild : XElement { }
public class Request : RootChild { }
public class Response : RootChild { }
var doc = new Root(new Request());
Remember this won't work for 'reading' scenarios, you will only have the strong-typed graph from the XML that your application creates via code.
Hand-cranking xml is one of the things which should be automated if possible.
One of the ways of doing this is to grab the messaging XSD definitions off your endpoint and use them to generate C# types using the xsd.exe tool.
Then you can create a type and serialize it using the XmlSerializer, which will pump out your xml message for you.
I noticed this article for constructing arbitrary XML with C#4.0 which is great.
The source for the library is here - https://github.com/mmonteleone/DynamicBuilder/tree/master/src/DynamicBuilder
At this time, there is a notable deficiency, no xml namespace support. Hopefully that will get fixed though.
As a quick example, here's how it's done.
dynamic x = new Xml();
x.hello("world");
Which yields:
<hello>world</hello>
Here's another quick example yanked from the article.
dynamic x = new Xml();
// passing an anonymous delegate creates a nested context
x.user(Xml.Fragment(u => {
u.firstname("John");
u.lastname("Doe");
u.email("jdoe#example.org");
u.phone(new { type="cell" }, "(985) 555-1234");
}));
Which yields:
<user>
<firstname>John</firstname>
<lastname>Doe</lastname>
<email>jdoe#example.org</email>
<phone type="cell">(985) 555-1234</phone>
</user>
Having used the Ruby library Builder this method of creating arbitrary XML is similarly terse, to the point that it verges on "fun"!
I've marked this as the answer, because, even though it doesn't directly speak to "using a DSL to create arbitrary XML" it tends to remove the need due to the extremely terse and dynamic nature of the syntax.
Personally I think this is the best way to create arbitrary XML in C# if you have the v4.0 compiler and have to crank it by hand, there are of course much better ways to generate XML automatically with serialization. Reserve this for XML which must be in a specific form for legacy systems only.
Writing this in C# seems an awful lot of work. Design your DSL as an XML vocabulary, and then compile it into XSLT, writing the compiler (translator) in XSLT. I've done this many times.

Transforming objects

Is there simple way transform one object in another, first defined in application object model and another defined in web service refference. Definitions of two objects are the same.
If you are using WCF, you can actually share types defined in a WCF service with clients of that service.
See the section Using the Employee Class on the Client of this article:
http://10rem.net/blog/2009/07/13/sharing-entities-between-wcf-and-silverlight
Types defined in your web service become available to (.NET) clients consuming them by electing to reuse types defined on the WCF side.
UPDATE:
As promised in one of my comments, here's code to create a copy of an object using serialization. I'm including both a variant that expects a specific class, and a variant that uses generics to support any serializable type. You can replace DataContractSerializer with BinarySerializer in many cases.
static public Organization Copy(Organization org)
{
MemoryStream stream1 = new MemoryStream();
//Serialize the Record object to a memory stream using DataContractSerializer.
DataContractSerializer serializer = new DataContractSerializer(typeof(Organization));
serializer.WriteObject(stream1, org);
stream1.Position = 0;
//Deserialize the Record object back into a new record object.
Organization orgCopy = (Organization)serializer.ReadObject(stream1);
return orgCopy;
}
static public T Copy<T>(T obj)
{
MemoryStream stream1 = new MemoryStream();
//Serialize the Record object to a memory stream using DataContractSerializer.
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(stream1, obj);
stream1.Position = 0;
//Deserialize the Record object back into a new record object.
T objCopy = (T)serializer.ReadObject(stream1);
return objCopy;
}
you could probably map the objects one to the other having an helper class which copies/assigns member to member.
In general the best approach is anyway to avoid this kind of transformation especially if objects are the same as in your case.
This can be avoided with a good design, for example in WCF specifying data contracts and having such classes implementing a common interface shared in both service and application, then of course you should program in all the places against the interface and not the class which implements it.
for old XML web services, when data contracts were not available yet, something can still be done using interfaces but then it also depends on the way you expose your types, if the service returns a class of its own type or of a type defined in a common class/interface library.
You could use AutoMapper to do this:
AutoMapper is an object-object mapper ... AutoMapper works best as
long as the names of the members match up to the source type's
members. If you have a source member called "FirstName", this will
automatically be mapped to a destination member with the name
"FirstName".

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.

Categories