martedì, febbraio 01, 2011

BizTalk Pipeline Template (Visual Studio 2005)

During years of BizTalk development, I’ve finalized a set of standard pipeline components I use on every pipeline of mine.

What these pipeline components do is not important here (one is the BAM Pipeline Component depicted here, other realize streaming backup, other trace diagnostic information, etc) but the point is that they are came with every pipeline I realize.

I even realized enhanced version of default pipelines (XmlTransmit, XmlReceive, PassThruTransmit, PassThruReceive) already instrumented with these pipeline components.

Unfortunately sometimes the default pipelines are not enough and I need to implement a new pipeline to support custom behaviors (i.e. custom message debatching, disassembling and so on) and, since standard visual studio templates give us an empty pipeline, I have to add again all pipeline components and configure each one with its default parameter.

This is an error prone task and adding a component can be easily forgot by developers new to our infrastructure and this may lead to unpleasant situation as where you told customer “yes enabling backup/BAM/Diagnostic is just a configuration” only to discover a moment after that that particular flow uses a custom pipeline and its developer “forgot” to put in our default pipeline components (therefore requiring a modification, recompilation, redeploy and reconfiguration of all the ports impacted by the modification).

A simple solution to the problem would be writing a “pipeline template” already set with our pipeline components all ready and set.

BizTalk 2006/R2

What we need, in Visual Studio terminology, is an Item Template but, when we try to select the “Export Template…” menu item as depicted here we will se that the option is grayed out for BizTalk projects.

This is not unexpected: when VS2005 was finalized and embraced MSBuild as project format, BizTalk projects retained the old project format (first true integration between MSBuild and BizTalk came in 2009 edition) and therefore we expected something similar.

Inspecting the BizTalk installation directory, inside the Developer Tools directory we find some interesting directories such as BizTalkProjects or BizTalkProjectItems… since we’re interested in Item Templates is natural to open the BizTalkProjectItem directory:

image

Inside that directory we can see all biztalk item templates used by BizTalk:

  1. BTSMap.btm: Template for empty map
  2. BTSSchema.xsd: Template for empty schema
  3. BTSReceivePipeline.btp: Template for empty receive pipeline
  4. BTSSendPipeline.btp: Template for empty send pipeline
  5. BTSService.odx: Template for empty orchestration.
  6. BTSPropertySchema.xsd: template for empty property schema item.
  7. FFSchema.xsd: template for empty flatfile schema.
  8. BTSFlatFileSchema.vsz: probably, matches FlatFileSchema Wizard (see below)

A quick comparison between BizTalk “add new item” screen and directory content show us that they’re somehow related:

image

Inspecting directories (Map Files, Pipeline Files, etc) show us just a single *.vsdir file for each directory.

Both vsz and vsdir files are Visual Studio standard file formats:

  • Vsz is used to invoke a wizard and pass parameters to it (and therefore our idea that BTSFlatFileSchema.vsz is related to FlatFileSchema Wizard option is confirmed).
  • Vsdir is used instead to provide information about how display items in “Add Items” dialog.

Adding template files

The first step we have to do is to create our pipeline templates as normal pipelines in a biztalk solution.

Then we take btp files containing our templates and copy them inside the BizTalkProjectItems directory.

Modifying BTSPipelines.vsdir

Then we start modifying the file BTSPipelines.vsdir in Pipeline Files subdirectory.

We just need to add a row for each btp template added, below a comparison between default BTSTransmitPipeline.btp row and my custom MySendPipeline.btp template.

For field description refer to Vsdir msdn page, what I would like to underline here is that parameters starting with ‘#’ character are simply a reference to a resource identifier and can be replaced directly with a string

Name Default pipeline My custom pipeline
RelPathName ..\BTSTransmitPipeline.btp ..\MySendPipeline.btp
{clsidPackage} {ef7e327e-cd33-11d4-8326-00c04fa0ce8d} {ef7e327e-cd33-11d4-8326-00c04fa0ce8d}
LocalizedName #228 My Custom Send Pipeline
SortPriority 121 121
Description #229 My Send Pipeline instrumented with custom components.
DLLPath or {clsidPackage} 0 0
IconResourceId 233 233
Flags 0 0
SuggestedBaseName #230 #230

 

Modifying BTSProjectItems.vsdir

To complete our work we need to add the row also to the BTSProjectItems.vsdir file contained in the BizTalkProjectItems directory.

The row is exactly the same added in the previous section to the BTSPipelines.vsdir file, the only thing that changes is obviously the RelPathName because now the MySendPipeline.btp file is in the same directory of the vsdir file so there’s no need to use the ‘..\’ prefix.

Below again the comparison of a standard template and my custom template.

Name Default pipeline My custom pipeline
RelPathName BTSTransmitPipeline.btp MySendPipeline.btp
{clsidPackage} {ef7e327e-cd33-11d4-8326-00c04fa0ce8d} {ef7e327e-cd33-11d4-8326-00c04fa0ce8d}
LocalizedName #228 My Custom Send Pipeline
SortPriority 121 121
Description #229 My Send Pipeline instrumented with custom components.
DLLPath or {clsidPackage} 0 0
IconResourceId 233 233
Flags 0 0
SuggestedBaseName #230 #230

Choosing “Add New Item…” will show us our new pipeline template, ready to be used as can be seen below.

image

Unfortunately, I was unable to add references for my custom components directly when adding my custom template, therefore, once added the new pipeline from my template, I need to add reference by hand before being able to compile it.

Conclusion

I’ve focused on Pipeline templates but, obviously, the same process depicted above will allow us to create template for maps (btm), Orchestrations (odx) or Schemas (xsd).

The procedure anyway will work only for Visual Studio 2005 (and therefore to BizTalk 2006/R2), this because starting from BizTalk 2009 (Visual Studio 2008) BizTalk Project became true MSBuild projects and therefore Item Templates are more similar to standard visual studio item templates and less a custom wizard extension.

In the next post we will see how to obtain the same results also on BizTalk 2009

giovedì, gennaio 13, 2011

Overriding BizTalk Dehydration mechanism

On of the most annoying thing I find in orchestration design is the amount of planning one have to put in exception management.

If we consider a BPM process spanning on several weeks (implemented in a long running orchestration) we may proceed for days (and in the meanwhile completing several conversation between several systems) before noticing that some data (maybe even in the message which started the orchestration) is wrong and throws an exception.

What to do if we already contacted five external system when the sixth system rejected the data?

If we’re lucky we can compensate (rolling back) the actions already done on five systems terminating the orchestration without leaving traces (and eventually repeating the request with correct data) but this is not always possibile:

  • Some system may not have a way to rollback (compensate) an action (they may base this rare event resolution on manual fix procedures).
  • Having to rollback single parts of our actions put us in need to redo only part of our actions:
    • Our orchestration should be able to start from each different point of process.
    • Our orchestration should be able to skip particular process steps if necessary.
    • Activation (original message) should contain an itinerary of which steps to execute and which steps skips.

EAI Patterns usually approach these problems implementing steps as atomic actions coordinated by a master process manager (Hohpe, Woolf – 2004).

Even BizTalk main BPM Scenario uses a stage separation of the process for guarantee the ability to modify an order while in execution.

In my experience this approach is often an overkill where a simple, on fly, fix in data would suffice to resume and complete successfully the process.

The most frustrating thing is that, in a similar situation, BizTalk Engine suspends the orchestration as Suspended Resumable allowing the administrator to resume it with its complete state and to retry the faulty operation but since we’re unable to act on orchestration state, the operation is doomed to fail again and again and again.

POCO Domain Model.

Having come recently in contact with DDD discipline I started to implement my orchestrations more as a set of POCO entities representing my model and less as a set of Multi part Messages as I made before (more on this in a future post).

Being the state of my orchestration represented by CLR objects and not by BizTalk messages, which are immutable, allowed me to think about “updating the state” as a way to correct possible anomalies and, why not, inspecting orchestration status without having to run the, a-bit-too-techincal, orchestration debugger.

I was not interested in accessing the data during normal orchestration execution but only when:

  • Orchestration was dehydrated since long time (what on the hell is it doing and what is its actual state?)
  • Orchestration was suspended as consequence of an error (why does it fault and it’s possible to fix its state?)

The most important thing to notice is that, in both cases, orchestration is dehydrated and this means that the whole state (comprising my POCO Domain model) is persisted on the BizTalk Database. Unfortunately the BizTalk Database is not accessible to us.

Serialization

Remember that every class used in a BizTalk orchestration must be marked with the Serializable attribute? (except if used in atomic scopes)

Well in the BizTalk FAQ is explained why it is necessary (as one can imagine … but it’s reassuring to read an official statement :) ):

The XLANGs runtime may persist to the database (dehydrate) your orchestration, including all of its data, at any point (except in the atomic scope). When the orchestration dehydrates and rehydrates, user-defined variables are binary serialized and deserialized.

So, BizTalk simply invoke the BinaryFormatter and asks our objects to serialize by themselves.

But we know that default serialization can be overridden and this will help us to externalize our domain model state.

Here I presents two ways to implement our custom serialization, both have they pro and cons as we will see soon.

Preparing the sample.

For simplicity let’s imagine that the whole state of my orchestration is contained in the simple State object reported below.

   1: [Serializable]
   2: public class State
   3: {
   4:     internal int _integer;
   5:     public int Integer
   6:     {
   7:         get
   8:         {
   9:             return _integer;
  10:         }
  11:     }
  12:  
  13:     internal String _text;
  14:     public String Text
  15:     {
  16:         get { return _text; }
  17:         set { _text = value; }
  18:     }
  19:  
  20:     internal Guid _id;
  21:     public Guid Id
  22:     {
  23:         get
  24:         {
  25:             return _id;
  26:         }
  27:     }
  28: }

It consists of 3 properties: an integer, a string and a Guid (the Guid will be initialized with OrchestrationId during state initialization)

Presenting the Sample Orchestration

The sample orchestration is very simple: it takes a message from a receive port (the message just contains an integer and a text value), initialize the State object with message data and OrchestrationId and enters in the RepeatableScope to repeate if on error.

In the scope I placed a decide shape where a simple check is made:

If Text data from the State (and therefore from the original message) is empty then an exception is raised (simulating an error) otherwise the flow exists the scope (clearing the repeat flag to avoid repeating the loop).

If an exception is raised instead (so Text in state is empty) the catch shape will first raise the repeat flag (because the loop must be repeated) and then suspends the orchestration (persisting therefore State)

When (and if) Orchestration exists the repeatable scope a new Message is created and populated with State data and sent on a send port.

image

Introducing our Repository

According to DDD we won’t access directly the State object, but we will use a Repository object to access it:

The Repository object will be responsible to manage the serialization/deserialization of our State object (representing our Domain Model) therefore our repository will implement just a couple of methods enabling us to set or retrieve our State:

   1: interface IRepository
   2: {
   3:     void SetState(State state);
   4:  
   5:     State CurrentState
   6:     { get; }
   7: }

Using ISerializable

The first IRepository implementation is based on ISerializable implementation:

We have to implement a GetObjectData that will be called by infrastructure when Repository needs to be serialized (therefore it needs to serialize the contained State) and a special constructor (that will be invoked when runtime will deserialize the Repository):

   1: public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
   2: {
   3:     // Here i'm going to serialize to filesystem therefore i'll use guid as a filename, but i could even serialize to a db therefore using a connection string and the guid as lookup value.
   4:     // Using a hardwired foldername just for sample sake, change it to an existing path on your filesystem or, even better, externalize it.
   5:     String filename = String.Format(@"C:\Temp\SerializationStore\{0}.txt", _state.Id);
   6:     // Serialize to the true SerializationInfo (BizTalk DB, remember that BizTalk invoked serialization).
   7:     info.AddValue("SerializedStateFileName", filename);
   8:     // Now that the file location has been saved into BizTalk proceed to save the true data.
   9:     BinaryFormatter bf = new BinaryFormatter();
  10:     FileStream fout = new FileStream(filename, FileMode.Create, FileAccess.Write);
  11:     bf.Serialize(fout, _state);
  12:     fout.Flush();
  13:     fout.Close();
  14: }
  15:  
  16: protected ISerializableRepository(SerializationInfo info, StreamingContext context)
  17: {
  18:     // First of all read the location of file containing persisted state.
  19:     String filename = info.GetString("SerializedStateFileName");
  20:     // Then open the existing file and deserialize the _state object.
  21:     BinaryFormatter bf = new BinaryFormatter();
  22:     FileStream fin = new FileStream(filename, FileMode.Open, FileAccess.Read);
  23:     _state = (State)bf.Deserialize(fin);
  24:     fin.Close();
  25:  
  26:  
  27: }
  28:  
  29: }
  30:  

In this code the serialization will first create a file with the OrchestrationId as name and then will use the normal BinaryFormatter on the newly created file to store it. Deserialization will operate in the reverse: first obtain the filename from serialization stream, and then using BinaryFormatter will deserialize the state object from it.

Let’s consider the following message:

   1: <ns0:Root xmlns:ns0="http://TCPSoftware.CustomDehydration.Orchestrations.Schema">
   2:   <Integer>10</Integer> 
   3:   <Text></Text> 
   4: </ns0:Root>

When such a message will be published on the orchestration, the orchestration will suspend in exception and, as the following screenshot shows, a file with the same OrchestrationId will pop up in the filesystem.

image

image

Now we may resume the message and it, as expected, will continue to execute the loop and resuspend in error.

But using the BinaryFormatter we can recreate and fix the State object persisted on the file outside of biztalk server, for example using the following simple console application that will simulate state correction.

   1: static void Main(string[] args)
   2: {
   3:     // args[0] is filename to fix
   4:     Console.WriteLine("Opening DomainModel from file '{0}'",args[0]);
   5:     FileStream fin = new FileStream(args[0],FileMode.Open,FileAccess.Read);
   6:     BinaryFormatter bf = new BinaryFormatter();
   7:     State state = (State)bf.Deserialize(fin);
   8:     fin.Close();
   9:  
  10:     // State recreated, now fixing it
  11:     if (String.IsNullOrEmpty(state.Text))
  12:     {
  13:         state.Text = "Fixed!";
  14:     }
  15:  
  16:     // Saving fixed state.
  17:     FileStream fout = new FileStream(args[0], FileMode.Create, FileAccess.Write);
  18:     bf.Serialize(fout,state);
  19:     fout.Flush();
  20:     fout.Close();
  21: }
After using the fixer we can resume the suspended message and this time the orchestration will complete publishing the following output message:
   1: <ns0:Root xmlns:ns0="http://TCPSoftware.CustomDehydration.Orchestrations.Schema">
   2:   <Integer>10</Integer> 
   3:   <Text>Fixed!</Text> 
   4: </ns0:Root>

Using OnSerialized / OnDeserializing Attributes

This approach is different from the previous one: instead of overriding the normal serialization mechanism we will side it.

   1: [OnSerializing()]
   2: public void OnSerializing(StreamingContext context)
   3: {
   4:     // Check _serializeExternally and decide if override serialization.
   5:     if (_serializeExternally)
   6:     {
   7:         // for simplicity in this sample a file is used to store data
   8:         _filename = String.Format(@"C:\Temp\SerializationStore\{0}.txt", _state.Id);
   9:  
  10:         // Now filename will be serialized with normal serialization inside BizTalk. Time to serialize externally state.
  11:         BinaryFormatter bf = new BinaryFormatter();
  12:         FileStream fout = new FileStream(_filename, FileMode.Create, FileAccess.Write);
  13:         bf.Serialize(fout, _state);
  14:         fout.Flush();
  15:         fout.Close();
  16:     }
  17:  
  18: }
  19:  
  20: [OnDeserialized()]
  21: public void OnDeserialized(StreamingContext context)
  22: {
  23:     // ONLY if _serializeExternally (&& ) is true then external serialization was done
  24:     if (_serializeExternally)
  25:     {
  26:         // Read from stream.
  27:         BinaryFormatter bf = new BinaryFormatter();
  28:         FileStream fin = new FileStream(_filename, FileMode.Open, FileAccess.Read);
  29:         _state = (State)bf.Deserialize(fin);
  30:         fin.Close();
  31:     }

Before running normal serialization our method marked with OnSerializing Attribute is executed: this method looks if _serializeExternally flag is raised and if it is, the method will create a file with the OrchestrationId as name and will start to serialize the state object to it using the BinaryFormatter.

When normal deserialization completes instead our custom OnDeserialized method is invoked; the method will check if _serializeExternally flag is raised and if it is (in other words if data was serialized externally before) proceed to open the file and Deserialize the state object from it.

Differently from the previous method, this approach will serialize externally ONLY when instructed to do so, in fact our orchestration needs to be modified a bit in order to use this kind of repository:

  • The SetInErrorFlag shape that before was only containing the code to set the boolean retry flag, now contains also the following instruction (which raise our Repository _serializeExternally flag): Repository.EnableExternalSerialization();
  • The ClearInErrorFlag shape similarly will now contain the following instruction: Repository.DisableExternalSerialization();

The main differences between this approach and the previous one (ISerializable) are reported below:

ISerializable

OnXXXAttributes

Data is always serialized externally Data is serialized externally only if explicitly requested
Data is always serialized just once. Data is always serialized inside BizTalk therefore, when also serialized externally, it has to be serialized twice.

There’s not a clear winner here: if you’re scared of persisting your data outside from BizTalk Server you may prefer the OnAttribute way (incurring in the double cost of serialization just when an exception is raised, more than acceptable), if you prefer not to expose persisting mechanism in your domain code (such as the Enable/DisableExternalSerialization methods seen above) and you trust your code enough then you’ll prefer the ISerializable way.

Simplify Workflow with Atomic Shapes

If you look at the above orchestration, chances are that you won’t like it a lot, and I definitely agree.

The point is that there’s too much “infrastructure concepts” leaking into the business process design (orchestration).

The loop shape and the surrounded Catch and Suspend shapes are infrastructure noise, placed there just to enable suspend&retry mechanism.

In fact an atomic scope has almost the behavior we are searching for because an orchestration can’t suspend in the middle of an atomic scope, and therefore if an exception is raised inside an atomic scope, the whole scope will be retried “automatically” next time the suspended instance is resumed.

Unfortunately I said “almost” because there’s a catch: the first time I tried an orchestration with an atomic scope (instead of the above suspend&retry scope) I was puzzled because even if the error was raised there was no file at all in SerializationStore folder.

Thinking about it the reason is obvious and was depicted in the previous post: there’s no persistence point “entering” an atomic scope but only “exiting” and therefore the orchestration was starting, entering the scope without persisting and raising the exception inside the atomic scope.

This means that our Repository had no time to be persisted between its creation and the exception throw and therefore it was doomed to repeat the atomic scope forever without having a chance to persist data :S

Luckily I was able to find a way to programmatically persisting the orchestration allowing the orchestration to persist just before entering the atomic scope and obtaining the whole advantages of External Serialization keeping infrastructure noise outside of my orchestration, just a quick visual comparison between the orchestration below with the one above should convince anyone…

image

You may download from here all the code from this article, hope you'll find it interesting.

BizTalk Versioning Strategy (4/4)

Previous part available here.

Really speaking, versioning problem is not the same for each biztalk artifacts:

Orchestrations

Orchestrations, for example, are not referenced by any other artifacts and therefore, can be updated with the Modify procedure descripted in the previous part without any risk replacing the old orchestration with the new one.

If we want to publish a new version of an orchestration keeping the old version up&running (a often necessary step in presence of long running processes) we can: BizTalk will host the new orchestration and the old one and will let us keeping both active or switch from the old to the new atomically.

Pipelines

Pipelines, as orchestrations, are not referenced by any other artifact (well, orchestration could reference pipelines in some cases even if I don’t recommend them) therefore Modify approach should suffice to replace an existing pipeline with another.

But if pipeline is referenced by ports in other applications obviously the modify will fail.

A quick workaround could be moving temporary all ports in the application containing the pipeline through the administration console, do the Modify, and move back ports to original applications.

In case the workaround will fail too one may increase the version number of the pipeline and redeploy it.

All ports will continue to use the old version and, if needed, WMI scripts can be written easily to move all ports references of the old version to the new version automatically.

Maps

Maps can be used by orchestrations (again, I’m against that kind of usage, maps should be used mainly on ports) and therefore Modify approach may or may not work.

And, as with pipelines, if maps are referenced by ports in other applications the modify will fail but, as with pipelines one may try to move every port and/or orchestrations referencing it to the same application and try to Modify.

If everything else fails one may increase map version number and deploy it.

Ports will continue to use the old map version and, if needed, WMI scripts can be written easily to move all port references of the old map version to the new one automatically.

Orchestration references are not so easy to redirect: references to the old map in fact are compiled statically inside the orchestration code therefore orchestration will continue to reference the old one and there’s no configuration settings from administration console who can help use redirecting the version.

Luckily, the same solution found for schema versioning will work also in this case: deploy a new version of the map and apply publisher policy to it.

Schemas

Schemas are usually very problematic when comes to versioning in BizTalk as seen in previous parts:

Schemas are referenced by nearly all other artifacts (Orchestrations, Maps and Pipelines too) and are usually placed in a Central application shared with several others (because usually schemas are traversal to different processes).

Because of this Modify will almost certainly fail and this makes them nearly un-updateable.

BizTalk engine allow us to deploy new version of schemas simply increasing assembly version number and this will make happy Maps and Pipelines but will break orchestrations.

Luckily the Publishing policy procedure depicted in the previous post will help us in solving this last issue allowing us to update freely every BizTalk artifact in a simple and agile way (once you get used to…).