Yossi Dahan [BizTalk]

Google
 

Wednesday, August 30, 2006

Off topic - Whitesands Lodge, Cornwall, England

If you ever decide to go to Cornwall England - whatever you do - DO NOT STAY AT THE WHITESANDS LODGE in Sennen !!!

On top of being quite expensive with very little value for money the owners have been extremely rude to us (as well as other guests) although we were paying premium rates for one of their best rooms in what is probably the highest point of the season - the August bank holiday.

The place used to be great we hear, but the new owners have totally destroyed it.
The peak of it all was when, on our second night, we were actually verbally and physically (!!!) abused simply for pointing out the music in the restaurant is very load and is clearly heard in the rooms upstairs.

One of the owners actually followed my up the stairs and used a such a foul language I dare not repeat it here (let's just say it had lot's of f's in it) and as if that was not enough he then physically assaulted me, and I believe it was just the fact that I did not try to resist or reply that made him go away eventually.

Our holiday was nearly destroyed by this unbalanced couple, they should really learn that a fundamental rule in hospitality and a minimum requirement for returning customers is to not abuse them verbally or physically. Kind of basic really.

Thursday, August 24, 2006

Something I did not realise about xsl and apply-templates

I love xsl. And I used to love apply-templates. Until today.
I always thought that apply when you have and xml that looks like this:

<a>
<b>
<b/>
</b>
<c>
<b/>
</c>
<d>
<b/>
</d>
</a>


Then you could use apply templates to select all the children of a -

<xsl:apply-templates select="a/*">
</xsl:apply-templates >

And have the templates you need to process all the nodes -

<xsl:template match="b">
<B_Processed/>
</xsl:template>

<xsl:template match="c">
<C_Processed/>
</xsl:template>

<xsl:template match="d">
<D_Processed/>
</xsl:template>

Running this would on the provided example will generate, as expected -

<B_Processed/>
<C_Processed/>
<D_Processed/>

The behaviour I did not expect is what happens when the match encounters an unfamiliar node, so if your xml looks like this -


<a>
<b>
<b/>
</b>
<c>
<b/>
</c>
<d>
<b/>
</d>
<e>
<b/>
</e>
</a>

Notice the added <e> tag to which there isn't a template.

The output of the xsl with this input is:

<B_Processed />
<C_Processed />
<D_Processed />
<B_Processed />

Noticed that last B_Processed?

Apparently the xsl match process behaviour is that if it encounters an element in the select (the one you've specifically specified in the apply-templates) that does not have a match it will drill into that node recursively until it does find a match.

In my example <e> is unknown, but it's child <b> has a template which then gets executed.

In my world of using xsl to process xml messages this is a big disadvantage, as it means that in a way I might get unexpected results if I don't cover absolutely every option in the tempales.

For instance - if I need to filter out irrelevant elements from a message, I can't just specify the ones I need, I have to specify all the ones that might occur and I don't need as well, because otherwise they might include, internally, an element to which I have a template, although I never planned to apply it in that level.

I can pretty much state now that I will not be using apply-templates any more! Not unless I know exactly what I'm getting (and that it will never change) - which is pretty much never.

Tuesday, August 15, 2006

Wish list: No "blocking" operations in the BizTalk Admin Console

In my opinion, there are too many things that are "blocking" the BizTalk Admin Console's interface i.e. operations you have to wait until they are completed before you can do anything else with the console.

For instance - why the progress bar what stopping or starting an application has to be modal? why can't I do other things in the meantime? same goes for when I'm restarting a host.

Personally I resort to use other tools, for instance - the services mmc or simply another copy of the admin console running, to do things just so I can keep using the Admin console to do other things.

In my view it makes a lot of sense even when you're only managing one server, but it definitely makes sense when you have more then one on your console.

Friday, August 11, 2006

Wish list: Late bound dynamic ports

Thankfully BizTalk has the concept of late bound ports, which means you don't have to compile configuraiton.

Strangely this concept has not been fully applied as dynamic ports can't be late bound.

If you want to use a port dynamically you have to set it to dynamic in the orchestration port configuration, if you try and set it to late bound it generates a compile time error.

This means that whenever you deploy your solution a dyamic send port is generated for you (yes - with a horribly long name), but what's worse - it is automatically configured to use the default xml receive/transmit pipeline.

so if you need a custom pipeline, or even a passthrough, you have to go back and change that after every deployment.

of course, in most cases, you will use a binding file for your other configuration, and that binding file can override these settings, but it seems a bit odd to me.

ideally there would either be another setting in the orchestration's send port configuration of "Late-bound Dynamic" or alternatively the compiler will let you set the dynamic address on a late bound port and it will be the admin's responsibility to bind that port to a dynamic port in the admin console.

Schema re-use and generated web service proxies

We've found out another piece of puzzling .net proxy behaviour (to us at least)

If you have a complex type definition in an XSD file:

<xs:complexType name="myType">
.
.
.
</xs:complextType>

And then an element that uses this type: (in our case in another XSD file that includes the former XSD file)

<xs:element name="myElement" type="myType"/>

When you then publish an orchestration as a web service that uses this schema as a type of the parameter(s) and/or return values, the proxy generated will use the type name as the class name and not the element name.

So it would generate a class called "myType" and not "myElement" as I have expected.

In many cases it doesn't really matter, other then somewhat weird names in the code, in our case, because we're trying really hard to reuse existing objects thorugh the entire solution (inside and outside the biztalk boundaries), it poses a problem as class names are not as they should be.

This can be solved by changing the type name to match the element name, I was surprised by that by xsd seems to be happy with -

<xs:complexType name="myElement">
.
.
.
</xs:complextType>
<xs:element name="myElement" type="myElement"/>

Thursday, August 10, 2006

Order of operations in an assign shape

I keep forgetting this, but when you create a message in an assign shape, you have to assign to all the message parts before you can assign values to any message context property.

trying to do something like -

MyMessage.PartA = something;
MyMessage(SomeContextProeprty) = someValue;
MyMessage.PartB = somethingElse;

Will result in an error about accessing an unconstructed message.
changing the code to -

MyMessage.PartA = something;
MyMessage.PartB = somethingElse;
MyMessage(SomeContextProeprty) = someValue;

compiles with no problem

Friday, August 04, 2006

…and a transform shape gotcha!

Somehow we seem to get into all the dark corners of BizTalk in the last couple of weeks, this one was recently identified by Oleg Gershikov -

We have two schemas with the same target namespace but different root elements (Schema1.xsd and Schema2.xsd).

We need to map them using map with multiple input message to message with the third schema

If we wish to create a new map there's no problem.
we have two messages defined using the schemas from the referenced assembly, we can set them both as inputs for the new map and it all appears as expected -



The problem occurs when we want to configure the transform shape with an existing map, whether because we need to re-use it somewhere else or because we want to change it (for instance - if we want to replace the output message).

When the transform shape is configure to use existing map (rather then create a new one) it will show both input message types as the first one, ignoring the fact that the second one is of another type -



The only way aroung this is to create a brand new map each time!

I've uploaded a solution that demonstartes this problem here.

Schema Validation -- Gotcha!

I've noticed a long time ago, in the early days of BizTalk 2004 that the "Validate Instance" option in Visual Studio and the validation that actually occurs using the XmlDisassembler or XmlValidator in a receive pipeline are not identical. We had errors not being reported by the validate instance before, which is quite worrying, but our findings from today regarding Schema validation takes it another step -

Apparently "Validate Instance" is not sesitive at all to namespace differences, so if you take a BTS schema, generate an instance using VS 2005, edit the xml to change the target namespace and then validate that [amended] instance in VS 2005; then the validation will succeed, which is wrong.

By comparison, if you run the same [amended] instance through a code xml validate component (I used XmlValidatingReader) then the validation fails, as you would expect. Any de-serialization attempted against that instance would not work either – as expected!

(Thanks to Ben for confirming this one out so carefully!)

Thursday, August 03, 2006

Importing more then one schema from the same namespace

In the BizTalk schema editor you can import an external schema through the "Import" property of the node.

Clicking on the button in this property will open the Imports dialog through which you can import, include or redefine another schema.

However, if you try to import two schemas from the same namespace you get an error.
This puzzled me since as far as I know theirs is no such limitation in xsd.

To me this seems like a designer issue and not an xsd issue, and indeed, if you open the schema using the standard visual studio schema editor (or any other xml editor of you choice, notepad included) and add the xs:imports statement yourself, it all works just fine.

The imports statements would look something like this:

<xs:import schemaLocation="<1st schema full name>" namespace="<same namespace>" />
<xs:import schemaLocation="<2nd schema full name>" namespace="<same namespace>" />

Beware of unit tests!!

It has taken us 3 days(!!!) to figure this one out (well, it took me 3 days to give up and then Ben 10 minutes to find out the solution)

We have a relatively big solution. In fact, it got so big we had to split it, so now we have 3 relatively big solutions.

Since the only way to handle such big solutions is through careful regression testing we've been using unit tests for quite some time now.

Suddenly, one day, map projects stopped compiling - we would get an error that it cannot find the schema.

Strange, we thought, as we opened the map file to re-select the schema, but even stranger - as expected we'd get the dialog saying the schema could not be found and asked whether we would like to select a new one - we answer yes and Visual Studio tries to open the BizTalk type picker to allow us to select the schema, but that fails to open and from now on every single operation in VS will cause an error message. The only remedy is to close and re-open it.

We tried everything, new schemas project, new maps projects, nothing helped.
The only time the type picker would open is when no references exist in the project (other then the default ones).

That's until Ben here took initiative and looked at it more carefully.

What he found out amazed me - it is all because we had unit tests projects in our solution. As soon as we removed those from the solution it all went back to normal.

Wrapping outgoing message in a soap envelope

A colleague asked me yesterday what is the best way to wrap an outgoing message with an (empty) soap envelope.

We're posting the message over http, and while it is not a "real" web service, the remote system does require that each request will be wrapped in a soap envelope, although no special information is required in the soap header.

This can be achieved using the XmlAssembler in the send pipeline.

Simply use the XmlTransmit built-in pipeline in the send port, configure your document schema(s) as appropriate and select the system soap envelope schema as the envelope.

Note: I've posted an update to this entry here

Wednesday, August 02, 2006

Grouping in xslt

One of the 3rd parties we're connection to in our solution uses xml in a quite non-standard way, this constantly adds complexity to our solution. On the up side it does keep things interesting and sharpens our xsl skills!

The latest quirk is when we get an xml that can be represented like this -

<a>
<b/>
<b/>
<c>c1</c>
<d>d1</d>
<b/>
<e>e2</e>
<c>c2</c>
<b/>
<f>f3</f>
<b/>
</a>

You may spot that element b repeats itself several times with elements c, d and e in between. The logic is that all the elements between one b element to another are really children of the former b.

So - this xml should really look like -

<a>
<b/>
<b>
<c>c1</c>
<d>d1</d>
</b>
<b>
<e>e2</e>
<c>c2</c>
</b>
<b>
<f>f3</f>
</b>
<b/>
</a>

The xsl to get from one to the other -

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/a">
<a>
<xsl:for-each select="b">
<b>
<xsl:variable name="thisB" select="generate-id(current())"/>
<xsl:for-each select="following-sibling::*[name()!='b' and generate-id(preceding-sibling::b[1]) = $thisB]">
<xsl:variable name="nextB" select="generate-id(preceding-sibling::b[1])"/>
<xsl:element name="{name()}">
<xsl:value-of select="current()"/>
</xsl:element>
</xsl:for-each>
</b>
</xsl:for-each>
</a>
</xsl:template>
</xsl:stylesheet>

The idea is to loop on each b element, for each one use the generate-id function to generate a unique id and then loop on all the following siblings of the current b node until you get to another b node with a generated id that is different from the current one.