Yossi Dahan [BizTalk]

Google
 

Wednesday, December 12, 2007

Exception, Orchestration, Serialisation.

I was adding a custom exception yesterday to a helper class I’m calling from an orchestration.

Usually, my exception handlers in the orchestration are quite short; this time, however, I wanted to do a bit more, which included calling a web service when a particular expcetion is caught.

While implementing this I learnt something interesting (which, arguably, I should have known a long time ago – just to show how difficult it is to catch up on all the changes in the .net framework) -

In.net framework 2.0 a Data property of type IDictionary was added to the Exception class, which by it's own is not a problem, only that IDictionary is not serialisable and so could have proved rather difficult to anyone using Exception, especially in a BizTlak environment.

Luckily (but not surprisingly) the .net framework team have implemented ISerializable in the Exception class, which helps, but does cause a small headake to the unexpecting BizTalk developer (me).

But first - I have to apologise - again I'm not familiar with all the details around this, and am resorting to pure guesses of a couple of points (will be happy to get more information if you care to enlighten me), still - I'm sure this will be useful to most people...

When you mark a class as [Serializable], as the runtime deserialises a class it attempts to call a parameterless constructor to create an instance of the type; the serialiser will then populates all the members of the class through their public properties (I suspect that this is, partly at least, why Xml Serialisation serialises public members only).

When working with ISerializable, however, the runtime expects a constructor that takes SerializationInfo and StreamingContext as parameters; it is expected that the constructor will populate the members out of the SerializationInfo collection.

I believe that the runtime interrogates the type to be deserialised and, once it finds that the type or any type in its inheritance path implements ISerializable it takes the second approach mentioned.

Not realising the Exception class implements ISerializable ,I did not have the expected constructor in my class, which meant that when BizTalk tried to deserialise the object (between the send shape calling the web service and the receive shape expecting the response) it failed, which now exaplains the error reported in the event log -

The constructor to deserialize an object of type ‘[custom exception class name here]’ was not found.


Adding the constructor with the two parameters to my custom exception class allowed it to pass the deserialisation with no errors; however – I was now facing a second problem – after indicating that my class implements ISerializable and addin the constructor required the members of the Exception class, from which my class inherited, including the Data member now deserialised correctly; my own class' member,however, did not.

There are two ways to overcome this - I could have simply mapped my properties (after all I only had a couple of strings to keep with the exception) to the Exception's Data property (have the getter and setter of each property use the collection internally, and so all the data will be capture in the Exception base class and so serialised with it, or - I could implement ISerializable fully which really only means

1. Firstly - adding my members to the serializationInfo member of GetObjectData:

public override void GetObjectData(SerializationInfo si, StreamingContext
context)
{
base.GetObjectData(si, context);
si.AddValue("member1Name", member1Value);
si.AddValue("member2Name", member2Value);
}

2. Secondly - populating the members back in the constructor:

protected MyCustomException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
member1Name= info.GetString("member1Value");
member2Name= info.GetString("member2Value");
}


Voila! it all serialises and deserialises ok now. if only I didn't have to spend a whole day to figure this out!

Labels: , ,

Sunday, February 11, 2007

AnonymousTypes and serialization

In my current project we have to deal a lot of serialization of deserialization of objects; mostly due to the fact that we have a common object model accross most of our services and that mostly it is these objects that gets passed between web services in our solution.

In fact, almost every object we have is represented by both a .net class and a BizTalk schema and for that reason we have decorated most of our classes with serilization attributes to control the format of the xml generated.

As you all know, when objects are used in exposed web services, a schema that represents them is generated and embedded in the WSDL file, from which proxy classes will be generated in consuming applications.

A while ago I’ve noticed that in most of our classes have within the xml serialization related attributes the following attribute –

System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)

Hvaing this instructs the the schema generator to avoid treating this class/type as a global type which prevents re-use.

To demonsrate the issue consider the following –

I have a web method HelloWorld that takes in 1 parameter myenum of type MyEnum (which is an enumeration)


If the enum type has the discussed dattribute the wsdl is generated as the following –




Notice that that enumeration is a local definition of the element.

Without the attribute the wsdl is generated like this –



Notice that now the enum is declared globally and can be re-used across the methods.

I'm not sure why we had this in, I suspect, if I'm not mistaken, that the xsd.exe tool adds this attribute to classes generated from xml, and we've used this in many cases as our template.
Either way - I now try to avoid this attribute generally and only apply it when it makes sense. otherwise I have all the types declared as non anonymous which enables reuse.

Labels: