Yossi Dahan [BizTalk]

Google
 

Saturday, March 15, 2008

Creating a message "from scratch"

A question I get asked repeatedly is how to create a message in an orchestration “from scratch”, i.e. – when the message is not meant to be created from any other message.

Initially one might think this does not make sense, but I find myself doing it quite often actually; two typical scenarios are when one has to create a message before branching the process to satisfy the compiler (and avoid the “use of unconstructed message” error), a second is when one needs to return a message that simply contains few values obtained from, say, a database call, or some calculation etc.

In this case often it is simpler to create the shell of the message with the elements/attributes required and then use xlang’s xpath function to push the values into the right places.

Whatever the scenario is, there are, I believe, two options to create empty messages (corresponding to the two options to create messages in orchestrations in general, actually) –

1. Using a map
2. Using a message assignment shape (and a helper method).

The first one is quite obvious – you create a map, pick any message you may have in the process (you are likely to have at least one message in your process already) - use that as your input message and the message you want to create as your output message; then you’re facing two alternatives – the first one is to use xsl – you can create an xsl file that effectively has the XML you want to create hard coded in it and instruct the map to use that xsl.

The input message is completely ignored (and so is completely irrelevant) and the output message is always the way you want it to look like. You are not sensitive to any changes in the schema of your input message.

The other alternative, which I like less, is to actually use the mapper; in this alternative you would probably map the root node of your input message to the root node of your output message and then set up default values in the output message for any element/attribute that you wish to include in your output message.

The reason I believe this is not as good as the first alternative is that it is less obvious how the output message would look like; one has to follow up on the nodes to see what is set (or test the map) to see the output while in the xsl alternative one look at the xsl is usually enough to show what the output is going to look like.

Either alternative you choose – I used to think that using the mapper is a better option (as opposed to using the message assignment shape which I will describe shortly) – mostly because I thought this is a more standard way to create messages, and so it is more obvious, looking at the process and the project, where such constructions take place but mostly,I believed, if you’re using xsl files to create the output it would be very easy to spot, read and change them in the solution when necessary (simply find the xsl files and change them, no need to look for anything else).

Thanks to several people, but mostly to Ben Gimblett with whom I work with in one of the projects I'm involved with and who has insisted not to follow my advice and use helper methods to create messages, I now agree that using helper classes is the better way, mostly because using them you don’t have to use a dummy input message (as you do in the map) – which, I have to agree, can get quite confusing to anyone trying to understand the process but also because, I suspect (but have not tried to prove), a helper class will perform better than the mapper option.

When using a helper class you again have to alternatives –

You could have a message assignment shape in which you call a method that returns a .net type (class) that has been generated (using xsd.exe) from your schema.
All you need to do in your method now is create an instance of that generated return type – populate whatever members you require and return it.

In the assignment shape you assign the return value from the method to your message[part] and so BizTalk will take care of the serialization and will convert the class to the schema and because the class and the schema both represent exactly the same thing the serialisation would work just fine.

The benefit of this approach over the mapper option is mostly that there's no need for any dummy input message, no need to write xml or xsl; only very simple (and quite minimalist) code is required.

The downside – you need to generate those .net classes to represent any schema you wish to return, and maintain them as your schemas evolve.

The second alternative is simpler on the one hand as it does not involve generating and maintaining classes; it does, however, require a bit more wiring –

It starts the same way – a message assignment calls a method whose return value is assigned to the constructed message[type].

The difference is that the method does not return a strong type; instead it returns an XmlDocument whose contents are loaded from compiled resource within the assembly.

The function takes in the name of the xml that needs to be used to create the constructed message, retrieves the resource from the resources in the assembly, loads it into an xml document and returns it to the caller.

I find that this last approach works best for me in most cases – all the generated xmls are in one place which makes them easy to maintain (which I liked in the xsl option), there’s very little co-ordination that’s required – only the name of the xml file (or any other key one wishes to use) must be known to the caller and the xml resource should match the schema – but as it is stored in one location AS XML this is very easy to achieve and maintain.

Update: I've done some performance comparison between the different methods, the results of which can be read here

Labels: , ,

6 Comments:

  • Hi Yossi,

    There is another option to create messages from scratch. One could use the 'DocumentSpec' class. This class has a method 'CreateXMLInstance' which creates an instance from the schema definition as stored in the BizTalk management database.
    The big advantage of this option is that automatically adheres to changes in the schema. I.e. if the schema changes and is deployed to the BizTalk management database the 'CreateXMLInstance' method will return the instance in the new structure.
    One possible drawback could be that this is more suited for creating message instances in a custom pipeline scenario. However I have used this option from an orchestration and it works fine. Other drawbacks can be performance and the fact the this option is an undocumented feature.

    The 'Pro BizTalk 2006' (the book with the VB.Net code samples ;-))(Chapter 5) contains a detailed description of this way of creating message instances.

    What is your opinion on this?

    By Anonymous Randal van Splunteren, at 18/03/2008 09:16  

  • Hi Yossi, I also use an undocumented BizTalk API to generate schema instances for me. I have a custom class that keeps the already generated instances in an IDictionary for caching. With these methods you don't need to know what the schema looks like in your custom class, BizTalk does it for you. Of course you would need to update the field values inside the orchestration once the instance is created. The main methods are CreateXmlInstance and CreateXmlInstanceWithData in the DocumentSpec class inside the Microsoft.BizTalk.Pipeline dll. I got parts of the code from here and it's been working very well for me:
    http://blogs.charteris.com/blogs/valerym/archive/2006/11/28/The-Power-Of-Love-To-_2E002E002E00_-Undocumented-APIs-_2800_Part-1_2900_.aspx

    Perhaps I should blog about it...

    Thiago Almeida
    http://connectedthoughts.wordpress.com

    By OpenID thiagoblog, at 19/03/2008 03:14  

  • Thank you both for your great comments - they brought one of those "how did I not think of that!" moments.

    I have been using this method in unit tests (to test serialisation between schemas and their respective class representation to make sure the two are aligned), but I did not think about using it to generate a message in a process.

    There's only one caveat to this that I can think of (and I might be wrong - it's been a while since I used this "hands-on") - it would generate a complete xml instance according to the schema - with all the possible nodes..

    I guess if we're creating a message that we're going to be completely overwrite later, or if there are only a few nodes whose values we can replace using xpaths, that's great.

    But if the schema is large, and we only need a portion of it for our message, the other methods would be more useful.

    I also wonder if you had the chance to check the performance of this (I'm being optimistic and hope you will actually read this reply comment :-)) - I wonder if this uses reflection or not and what would be the performance impact - another task to my never ending list of things to look at....

    By Blogger Yossi Dahan, at 19/03/2008 08:18  

  • Hi Yossi,

    You are correct, I only use this method for small schemas that won't be mapped from another schema. I haven't had to create messages from scratch for large schemas before, but I would use your second method for that.
    The CreateXmlInstance method is good for schemas like error reporting, SQL Server control table inserts, etc.
    I don't have any numbers but I assume it would perform better than using a dummy map because you can cache the instances it generates. You can also cache the instances generated by your second method of course, but the advantage to the CreateXmlInstance method is that you don't have to know what the schema looks like in your helper class.

    Cheers,
    Thiago Almeida
    http://connectedthoughts.wordpress.com

    By OpenID thiagoblog, at 19/03/2008 21:24  

  • Hi Yossi,

    I've been working the 'DocumentSpec' method of message creation and it works OK until you have a Schema with multiple root nodes. such as WCF, Web Service generated schema. Then the method fails with very little in the way of information why. I think it is because you have not nomiated a root node for generation similar as you would when using this type of schema with a map. I cannot find anywhere in the API to do this.

    By Anonymous Paul Kingswood, at 04/06/2008 17:21  

  • From the MSDN documentation:
    "DocumentSpec.CreateXmlInstance Method
    This method supports the BizTalk Server 2006 infrastructure and is not intended to be used directly from your code. "

    If you plan on upgrading your BizTalk server to future versions it might not be a good idea to use this since it might change or not be present at all in coming versions.

    By Blogger Johan Rex, at 22/06/2009 12:01  

Post a Comment

<< Home