Tuesday, 3 February 2009

Give BizTalk some Object Orientation

The following blog discusses the techniques I use for orchestration development that I think are worth consideration...

Coming from a .net and oo programming background I find that although xlang gives you the power, the solutions always lack finesse that a suite of glorious interoperating classes delivers.  

So why not use messages that are .net data types rather than schema based?

Well, although I know you can create messages that have a .net datatype over a schema, that does not mean that you should...

I have found this is to be a far from perfect solution, especially as you lose the magical mapping capabilities that make transforming messages so productive, the mapper does not allow you to pick a .net data type from the type picker.  Also there are some additional advantages to having a schema represented class that I will discuss later.

So having tried to use a pure “messages as.net objects solution”, setting biztalk property attributes on the .net code to create distinguished fields and promoted properties and a whole load of other faf, I came to the conclusion that this is not the way forward. 

Instead I have found that there is a happy medium where you can use the best of both worlds as it suits you, there is however one Golden Rule and several recommendations that I have found useful listed below.

The “Golden Rule” is that all biztalk message variables are based on schemas and not .net objects!  This may seem a little backwards at first, however I found that when you base a message on a .net class BizTalk will create a schema for this class anyway which can be seen in the admin console(I think it examines a serialized version of the object).  If you need to use a schema representation anywhere else (need to map for example) you will have two definitions of the same message within BizTalk and get problems.

So always start with schemas, using these as the basis for your classes.  

When you need to perform some complex work function in BizTalk, generate a .net class using xsd.exe.  You will get a class that represents your schema which you can then adjust as you see fit, adding constructors and object methods that will help perform functions of that class in BizTalk (or elsewhere).  Now there this method gives you some great flexibility discussed later.

No here is my great discovery... You can “Construct” messages by assigning objects directly to them.  What I mean is you can create an orchestration variable that is of type .net class (the class you created using xsd) then assign it directly to a message within a contruct message shape like so....

SchemaMessage = object;

This means that complex message construction can be done in .net which is more suited for this, and simply assigned to a message.  Proper Bo I tell the....

Note however this is not a two way street, in order to assign messages to objects you need to pass the message to a static de-serialization function to create an instance of the object with the message data

object = namespace.object.deserialize(SchemaMessage); - remember the deserialize method will receive an xmldocument

If you are simply using .net for message creation you do not need to worry about custom de\serialization as the xsd generation give you it out of your box.

This interchange is quite neat and means message construction and manipulation within BizTalk becomes a piece of cake.  

Also, and in my view very powerful bonus is that you get the beginnings of a true data dictionary as your class definitions are defined by a set of schemas, forget the M language, .net has had this stuff for ages if you new how to use it! (Don't get me wrong, M is a shot in thearm for this stuff).  You can even use this technique in a non BizTalk environment to help with visual code generation.  

Anyway now you have a class definition of the schema you can reuse it.  What if you were dumping your BizTalk data into a .net application? Bosh, you have got the re=usable objects already.  What if you are creating an application that calls the orchestration using web services? Bam (no pun intended) you have got a class you can create and reuse instead of the web serice proxy generated one, maintaining one central set of class definitions.... Add to this the ability to persist these objects to sql using the serialization and the sql xml data type (in a Dublin-esque way) and my word now we are getting somewhere……  

  • Anyway back to OO BizTalk….

Recommendations

  • only create classes as and when you need them, and always use xsd.exe (its pretty good)
  • Ensure you use the /order parameter of XSD to avoid strange serialization problems
  • Create a batch file for each schema that gets a class and include this in the project
  • If you intend to alter the class (which is likely) write the xsd output to a file that is not part of your project to prevent automatically overwriting any amendments you may have made when running the batch file.
  • Note ALL amendments made in a separate .txt file in case you lose your amended generated file (see above to mitigate the risk of this)
  • Remove\comment out the “specified” Booleans from the xsd generated code, they are unnecessary
  • Remove\comment out the debugger.stepthrough attribute that xsd adds to the class definitions
  • If your schemas have enums, you must set the “AnonymousType = false” rather than true in the serialization xmlTypeAttribute
  • If you make additions to the class, create these in a separate .cs file making use of the partial classes

If you follow my recommendations you will end up with something like the following

A schema\bts project containing

  • MySchema.xsd             

A compoent project containing

  • MySchema_generated.cs
  • MySchema_Extentions.cs
  • MySchema_GenerateClass.bat

Here are some additional style choices I use that may not be everyones flava

I prefer to work with List rather than the arrays that xsd produces.  This still serializes in exactly the same way, but allows you to use the power of List.  You have to implement your own add, count and other functions in order to use this in good ole xLang, but it is easy and neat and I think worth the effort ( I comment out the array and declare a List in my extension class, using the arrays serialization attributes)

Where a class contains a child class, I almost always create a constructor on the child class and parent so that I can use the new operator to give me an object that has values.  Without this you would need to instantiate a child class and set the parent.child = instantiatedchild which is no good.

This means creating a new message looks like this in biztalk

obj = new obj(param1, param2, param3);

message1 = obj;

Quick and simple

Problems

If a schema changes the classes change, that’s how it is.  If you keep a not of all changes and push your additions to a separate .cs file your changes should be minimal (depending on schema complexity).

You have the possibility of increasing the memory footprint for large documents as the object.

Final Thought

It would be nice if a schema had an associated class with it in much the same way as the webservices proxy wizard does but this is not the case at the moment in BizTalk therefore I am rocking with this happy medium which seems to yield the best of both worlds…

Ciao for now

No comments: