<$BlogRSDUrl$>

Wednesday, September 29, 2004

DateTime Serialization in BizTalk - Possible Bug? 

On a recent project, I came across an interesting issue with assigning the current date and time to a promoted property in a Message Assignment shape.

The problem highlighted itself in our Audit database where we were auditing process state changes. The submission date of each audited record appeared to be 1 hour ahead than the current local time (based on GMT with Daylight Savings Time in effect - meaning we are currently +1 to UTC).

Our scenario involves writing an audit record from the web site that is initiating the process, then each subsequent audit is performed at various steps within a BizTalk orchestration. Each audit record contains some meta data extracted from the envelope, plus the XML fragment of the header within the envelope and optionally the body from within the envelope.

The first audit record is written by the web site. It uses a class created by xsd.exe which is based on the envelope schema deployed in BizTalk (not a BizTalk Envelope schema though). The code populates the class, then uses the XmlSerialization class to serialise the object into XML.

Each subsequent audit within the BizTalk orchestration effectively creates a new message (based on the envelope schema), updates the messageId, processStatus and submissionDate promoted properties within a Message Assignment shape, and then calls the Audit Web Service passing the message (as a string - long story, but that's the way it currently is) as an argument.

The first audit record has the correct time in the Oracle database, but every subsequent audit record has a time that is 1 hour ahead!

In the web site I'm using the expression DateTime.Now to populate the current date/time in the submissionDate property of my object. When serialised by .NET using XmlSerialization, it converts this date into a Sortable Date Time pattern (identified as 's' in .NET) as defined by ISO 8601. In addition, the DateTime.Now value is in local time, and it takes this into account when building the ISO 8601 date string. For example:

2004-09-24T11:24:08.5177508+01:00

From this date value you can clearly see that the date/time is in UTC format with a +01:00 for the adjustment for daylight savings time. So, this is a correct date/time for British Summertime.

When I set the submissionDate promoted property in BizTalk using the expression DateTime.Now, it should output the same or similar value, taking into account that DateTime.Now returns a local time, and that the date string should encode the daylight savings offset. However, it doesn't...

The following is a date string output from BizTalk. Bearing in mind that the message is serialised into XML and then passed to the Audit Web Service. This is what is received by the web service:

2004-09-24T11:24:08.9240060Z

The date/time string format is based on the Universal Sortable Date Time pattern (identified by 'u' in .NET) and is the correct local time but does not have any daylight savings adjustment associated with it! This means that when the Audit Web Service converts the string into a DateTime object using either System.Convert.ToString() or DateTime.Parse(), it takes the daylight savings adjustment into account and adds 1 hour!. It didn't work with DateTime.ParseExact( dateTimeString, "u", System.Globalization.DateTimeInfo.InvariantInfo ) either.

So, in order to fix this, we had to use the DateTime.UtcNow in the orchestration whenever we set the submission date promoted property so that the DateTime.Parse method could take into account current regional settings when converting the string to a DateTime.

Saturday, September 18, 2004

Cool XSD Validation Function for Orchestration 

As I promised in an earlier post, here's a cool XSD validation function that can be called from within orchestration. Just add to a library - I tend to put it into a BizTalk Utilities library full of useful little functions that complement orchestration (most of which should be provided by the orchestration engine, but that's a rant for another day!).

public static void ValidateDocument( XmlDocument businessDocument, string schemaStrongName )
{
  // Constants
  const int PARTS_IN_SCHEMA_STRONG_NAME = 2;
  const int PART_CLASS_NAME = 0;
  const int PART_QUALIFIED_ASSEMBLY_NAME = 1;

  // Parse schema strong name
  string[] assemblyNameParts = schemaStrongName.Split( new char[] { ',' }, PARTS_IN_SCHEMA_STRONG_NAME );
  string className = assemblyNameParts[PART_CLASS_NAME].Trim();
  string fullyQualifiedAssemblyName = assemblyNameParts[PART_QUALIFIED_ASSEMBLY_NAME].Trim();

  // Load assembly
  Assembly schemaAssembly = Assembly.Load( fullyQualifiedAssemblyName );

  // Create instance of the BTS schema in order to get to the actual schemas
  Type schemaType = schemaAssembly.GetType( className );
  Microsoft.XLANGs.BaseTypes.SchemaBase btsSchemaCollection = ( Microsoft.XLANGs.BaseTypes.SchemaBase )Activator.CreateInstance( schemaType );

  // Set up XML validating reader and validate document
  XmlParserContext parserContext = new XmlParserContext( null, null, "", XmlSpace.None );
  XmlValidatingReader reader = new XmlValidatingReader( businessDocument.OuterXml, XmlNodeType.Document, parserContext );
  reader.ValidationType = ValidationType.Schema;
  reader.Schemas.Add( btsSchemaCollection.SchemaCollection );
  while( reader.Read() ) {}
}

In order to call in orchestration, just create an expression shape and use the following:

ValidateDocument( myBtsMessage, myBtsMessage( BTS.SchemaStrongName ) );

Validating using Business Rules 

I tend to get about at work (not in the, ahem, naughty sense!) and while in Norwich a client wanted to validate their document to ensure that the end users had filled in all of the correct details. Simple standard stuff. However, when I explained that validating the document using a pipeline would suspend the message at the first error, they didn't exactly jump with joy!

They wanted to validate the document, but provide all of the errors in one go to the client if the document failed validation.

In order to do this, we proposed following the pattern used by the Swift Accelerator for BizTalk. The accelerator uses a disassembler that implements validation using business rules (run from the disassembler itself) and stores all errors in a separate document. It does not fail at the first error, but simply tries all of its rules and outputs all errors associated with the document in one go by returning the original document plus a document containing the errors.

This allows all sorts of interesting scenarios to occur, such as implementing an orchestration that handles errors allowing resubmission, notification to interested parties, etc. Quite powerful!

In the case of my client, we suggested running the business rules from within orchestration, but the concept remains the same.

Filter Subscriptions on Orchestrations 

I've been working for a large defence client in Portsmouth in the UK and recently come across another limitation in the filter expressions that can be applied to an activatable receive shape of an orchestration.

First some background though. When you drag an operation from a port to an activatable receive, you are effectively creating a subscription for that orchestration in the message box. When you deploy the orchestration, bind it and then enlist, the subscription will be created for that orchestration based on the message type that was defined on the operation that was bound to the receive shape.

This is important: the subscription is based on the message type of the operation defined on the port type. If you look at the subscription viewer and find your orchestration subscription (look for ServiceType of XLANG and the name will be prefixed with Activate), then you'll notice that the subscription has been automatically created with a MessageType filter.

Therein lies the problem. You see, because the subscription has been based on the message type being received, you can't set a filter in the receive shape that points to, say an envelope's promoted properties. This in my opinion is a serious flaw. If I have an envelope that contains meta data about my message, then I want to subscribe to properties on the envelope, but actually receive the message contained in the body of the envelope.

If I want to do this, then I have to define the envelope schema as a normal schema, that is, not a BizTalk Envelope schema. I then ensure that the body element is extensible, in other words, appending an <Any> element with ProcessContents set to Skip and the Namespace to ##any.

Once this has been done, receive the envelope in the orchestration (defined on the receive shape and port type) and then extract, plus optionally validate, the body inside orchestration.

This has an advantage:

The body document can be validated at a 'business' level - effectively allowing any errors from the validation to be handled within the orchestration, rather than being automatically suspended. I'll post some neat code that achieves this in a later post.

However, and this brings me all the way back to the point of my post, if I try and modularise my envelope schema by separating my header schema and then importing it into the main envelope schema, I have a major problem.

The envelope schema exists in one namespace and the header schema in another. The header schema has been imported into the envelope schema. In so far as XSD is concerned, I have a valid schema. In so far as BizTalk is concerned, it can see the header schema and can thus validate the contents (as opposed to using the Any element trick).

However, if I go to set a filter expression on the receive shape, then all of the promoted properties that are defined in the header schema do not display. Only promoted properties of the envelope schema will be displayed!

I've been bitten by filter subscriptions with BizTalk Envelopes and now with imported schemas. I so wish this will be sorted out as it limits the flexibility of the schema design that could be possible, but due to restrictions imposed by BizTalk, isn't.

I would be interested to hear some other view points on this.

BizTalk Hotfix for Business Rules 

It's been a while since my last update, so I'll start off gently with news about a hotfix for business rules if you have installed .NET Framework 1.1 SP1.

Click here for more information.

About the Author

You may be wondering who I am (or may not!), but I've been in the industry 16+ years working on a variety of systems from IBM mainframes as a CICS systems programmer, to developing on Unix and Windows based systems. At the moment, I'm currently working for a Microsoft Gold Partner in the UK called Solidsoft who specialise in systems integration using BizTalk Server. My position is generally dictated by what I'm doing, but normally as a solutions architect/consultant helping clients with their integration projects involving, yes you guessed it: BizTalk Server.

Disclaimer: all the views expressed here are my own and do not necessarily represent the views of Solidsoft Ltd or indeed any other company.