Implementing the Xml-Rpc Spec in C#: Part 2

by Law Metzler 11. September 2009 16:29

Sorry for the long span between posts, but things have been pretty busy here.

In the first part of this series, we reviews the Xml-Rpc specifications and used the XSD tool to generate our starting point.  Now, we'll tackle some of the basic changes we've done to those generated files.

Standards and Compliance

The first thing we need to do is to move the classes into a form that that is compliant with the software development standards for Bambit.  This is, for the most part, rather trivial, if not just tedious.  It includes:

  1. Putting each class into it's separate file
  2. Changing properties that simply expose private data variables to auto-properties
  3. Create proper casing for classes, properties and methods

As I said, simple, but (somewhat) tedious.

Class Implementation Changes

MethodCall Class

In the MethodCall class, the xsd file had originally created a special class called methodCallParams, which itself simply wrapped an array of parameter objects.  This was overly redundant to me, so I eliminated the methodCallParams class entirely, and changed the property


[System.Xml.Serialization.XmlElementAttribute("param")]
public parameter[] param {
get {
return this.paramField;
}
set {
this.paramField = value;
}
}

 to

[XmlArray("params")]
[XmlArrayItem("param")]
public List<Parameter> Parameters { get; set; }

This was a lot cleaner.  First, the naming  convention follows our guidelines. Second, we eliminated a class entirely.  Third, we changed from a non-expandable array data type, to a List<>.  This allows us to add to the list at any point in time, so calling code can keep adding parameters, instead of having to assign all parameters at once.

In doing this, we need to create a default ctor to initialize the List<>.  If we don't do this, De-serializing will explode on us, due to the fact that, when de-serializing to a List object, the Framework assumes that the object is valid and simply calls Add instead of putting the entire list on at once, so it will try to call Add on a null object.

Value Class

This class was given a lot of additions to, all having to do with casting.

Since the specifications state that a value can be a whole host of things, it must be stored as an object (outside of customizing the serialization and keeping a whole slew of different type variables).  However, an object is much too vague to be of real use in most situations.  So what we did was to store the actual object as an object, but add cast operators to the Value class itself.  To be effective, we made casts both ways, so that casting from a double, int or any other valid type to a Value would be allowed, as would casting from a Value to any other type (as long as the Value WAS of that type).

To do this, casting from a Double (or any other valid type) to a Value would be an implicit conversion, while converting from a Value back would be an explicit.  The reason for this is that, in an implicit casting, you should NEVER thrown an exception, while explicit conversions allow for an exception to be thrown. Since the Value object can be any other type at any time, it is allowed to be implicitly cast.  However, if the Value already contains an RpcStruct object and we try to cast it to a double, we will blow up.

We then entered every cast possible, in the following form:

public static explicit operator <TYPE>(Value value) { return (<TYPE>)value.Item;}

public static implicit operator Value(<TYPE> item)

{

  return new Value { Item=item, ItemType = <APPROPRIATE ITEM TYPE> } ;
}

 

For instance, the conversion casting for a double was:

public static explicit operator double(Value value) { return (double)value.Item;}
public static implicit operator Value(double item) 

{

   return new Value { Item=item, ItemType = ItemChoiceType .Value } ;
}

 

As you can see, our implicit conversion will never fail, as assigning the "Item" (which is an object) anything is completely legal.  Our explicit will fail only if the framework does not know how to do the conversion itself.  We could have done some checking on ItemChoiceType ourselves, but this would have been a bad idea.  First, it's extra work on our end that is redundant.  Second, if we try to cast to a double and it's an integer, we would fail (unless we actually check all the different types that can be cast to/from), when it is a perfectly legal cast.  As such, it's much better just to let the Framework do the work for us.

 

Well, that covers a few of the design decisions.  In the next installment, I'll go over changes to the RpcStruct and MethodResponse classes.


NOTE:

We've released this project under the LGPL and you can download it at codeplex, BXmlRpc.  The current generated documentation can be found at http://bxmlrpc.bambitinc.com/Documentation/

Tags: , , , , ,

Comments

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen