Tuesday, 07 July 2009

Hi all

When trying to help the guy I wrote about in http://blog.eliasen.dk/2009/07/07/DistinguishedFieldNotWorking.aspx getting his distinguished field working, another guy suggested that he just used he xpath function instead of trying to get the distinguished field working. Now, he actually ended up using the xpath function because he had a reserved word in the xpath statement to the field he needed to access the field, but I thought I’d just write a post about why the xpath function should be avoided and perhaps generalize the post to the usage of promoted properties, distinguished fields and the xpath function. When to use what and why…

Why use distinguished fields over the xpath function

  1. Readability. Inside an expression shape, it is much easier for a BizTalk developer to look at “Message.MyElement.MyField” than it is to look at “xpath(Message, “string(/*[local-name()=’MyElement’ and namespace-uri()=’http://mynamespace.com/something/somethingmore’]/*[local-name()=’Myfield’ and namespace-uri()=’’])”)”
  2. Maintainability. If you need to change a schema at some point, the distinguished field is automatically updated to correspond to the new xpath expression that points to the relevant field (if you are using the BizTalk Editor, that is). If you use the xpath function, you need to find ALL occurrences of the xpath function in your entire solution that has an xpath expression that needs to be updated.
  3. Performance. If you use the xpath expression to get values form a message, then the entire message needs to be loaded from the database and the xpath expression is then evaluated. Distinguished fields, on the other hand, are kept in the context of the message and is therefore loaded quickly at runtime.

Why use promoted properties over distinguished fields

  1. Routing. Only promoted properties can be used for routing in the internal publish/subscribe engine if you need to route based on the content of a message.
  2. Correlation. If you need to correlate a received message into a specific instance of your orchestrations, then you need to do this using promoted properties, as these are the only properties that can be added to a correlation type. This makes sense when you think of it, because correlation is really just runtime routing - setting up the correct subscriptions at runtime that will make the message hit the correct orchestration instance. And routing can only be done with promoted properties, hence these are needed for correlation.
  3. Tracking. You cannot track distinguished fields – for tracking, you need promoted properties.

Why use the xpath function

  1. Distinguished fields cannot be used because there is a reserved word in the path of the xpath expression
  2. Distinguished fields cannot be used because you need to set or read a value from a reoccurring element

Why use distinguished fields over promoted properties

  1. Performance. You want to keep the number of promoted properties as low as possible, since the messaging engine really needs as few promoted properties as possible to evaluate when finding out which subscriptions match an incoming message that is published to the MessageBox.

So, to sum up: Use distinguished fields whenever possible, switching only to xpath function or promoted properties if really needed.

--
eliasen

Tuesday, 07 July 2009 23:36:10 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 

Hi all

A guy on the forums posted a very small schema, in which he had promoted an element as a distinguished field.

His schema was this:

<?xml version="1.0" encoding="utf-16" ?>
<xsd:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="outbound_task">
    <xsd:annotation>
      <xsd:appinfo>
        <properties xmlns="http://schemas.microsoft.com/BizTalk/2003">
          <property distinguished="true" xpath="/*[local-name()='outbound_task' and namespace-uri()='']/*[local-name()='task' and namespace-uri()='']/*[local-name()='task_id' and namespace-uri()='']" />
        </properties>
      </xsd:appinfo>
    </xsd:annotation>
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="task">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element minOccurs="0" name="task_id" type="xsd:decimal" />
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

His issue was, that when he tried using the distinguished field in an orchestration, the task_id field just didn’t show up in intellisense. And if he just entered the complete value in the expression shape (like this: Message.task.task_id) then he got a compile time error.

I messed around with it a lot, trying all sorts of stuff, but ended up with a quite simple solution: the word “task” is a reserved word. For a complete list of the reserved words, take a look at http://msdn.microsoft.com/en-us/library/aa547020.aspx. So, basically, renaming the “task” element to “Task” or something completely different (but still avoiding any reserved words) will work.

Hope this helps.

--
eliasen

Tuesday, 07 July 2009 22:27:16 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Monday, 06 July 2009

Hi all

A long time ago, I had a post about the toolbox in Visual Studio keeping old functoids on it and crashing and stuff.

The post can be found here: http://blog.eliasen.dk/2006/12/05/RemovingFunctoidFromToolbox.aspx (Note the comments).

With this post I just wanted all to know that the path to the toolbox* file that should be deleted on a Windows Server 2008 with visual Studio 2008 is C:\Users\<User>\AppData\Local\Microsoft\VisualStudio\9.0

Hope it helps

--
eliasen

Monday, 06 July 2009 21:11:22 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 

Hi all

So, yesterday I had to loop through all properties on a message inside a pipeline component.

When you program a general pipeline component, you get an Execute method that looks like this:

public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)

Now, in order to loop through the properties, the common solution is like this (and you can find this in many many blog posts around the great internet):

for (int i = 0; i <= pInMsg.CountProperties; i++)
{
  string name;
  string ns;
  object value = pInMsg.Context.ReadAt(i, out name, out ns);
  // Do something with the vale, name and namespace
}

Now, this is quite all right as it is, but there is one small pitfall that I don’t think most people realize; The CountProperties property is a uint, meaning that it can contain values up to 2^32 = 4294967296. Unfortunately, the first parameter to the ReadAt method is an int, which only holds values up to (2^31) – 1 = 2147483647. So, if there are, say 3000000000 properties, then the CountProperties property will return the correct number of properties, but there is no way of calling the ReadAt method to get the property.

This is kind of silly.

Now, to be fair, I think that the most properties I have seen on a message ever may have been around 40-50 properties. So there is a looooong way to 2 billion properties :-) So in real life, I don’t expect anyone to run into this limitation – if you do, I’ll buy you a beer! :-)

BUT, just to be sure, what you should do to be absolutely correct in your code is this:

uint counter = pInMsg.CountProperties;
string name;
string ns;
if (counter > int.MaxValue)
{
  counter = int.MaxValue;
}
for (int i = 0; i < counter; i++)
{
  object value = pInMsg.Context.ReadAt(i, out name, out ns);
  // Do something with the vale, name and namespace
}

And then, off course, you should somehow notify someone that there were more properties than you could handle – like a Debug statement, an error in the eventlog or the such… perhaps even throw an exception BEFORE trying to enumerate the properties, sine it would be useless, the result you get.

Anyway… hope this is somehow a help to someone… not sure how, though :-)

--
eliasen

Monday, 06 July 2009 19:20:41 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Friday, 03 July 2009

Hi all

During my years on the forums, I have seen plenty, plenty and plenty more posts about the SQL Server Adapter schema generator closing unexpectedly, without any errors or any artifacts created.

Today I ran into it myself for the very first time with a BizTalk 2009 installation. I did some searching and found this post: http://support.microsoft.com/kb/917847 – which only applies to BizTalk 2004 and BizTalk 2006.

This blog post is just to let everyone know that it applies to BizTalk 2009 as well.

Good luck out there…

--
eliasen

Friday, 03 July 2009 22:24:56 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Thursday, 02 July 2009

Hi all.

So, I am very proud to be able to publish that I have been awarded the MVP title again as of July 1’st. This, naturally is a great honor and I am rally happy about it.

Not sure I am as happy about it as Randal van Splunteren, though – because he promised some weeks ago, that if I didn’t get reawarded he would eat his shorts, shoes, hat or something – can’t remember which one, but it is in my log! :-)

The MVP title has lots of advantages, naturally – the title, the prestige, the gifts, the monthly webcasts and what not, but mainly I am happy that I do not have to bother removing the MVP logo from my blog, web site, business cards, et cetera .-)

Anyway, this is my third MVP title – going for the fourth in a year! :-)

--
eliasen

Thursday, 02 July 2009 06:35:50 (Romance Daylight Time, UTC+02:00)  #    Comments [7]  | 
Tuesday, 30 June 2009

Hi all

A friend and colleague of mine has just release SolZip version 1.1 on CodePlex – Find it here: http://solzip.codeplex.com/.

Basically, it is a nifty way of zipping a Visual Studio 2008 C# solution. The utility is pointed towards the .sln file and then zips all files in the solution and projects into one zip file.

To me this is really nice, because as of BizTalk 2009, the project files are just specialized C# projects and therefore, it seems to work just fine for BizTalk 2009 solutions as well. I can use it when blogging to quickly zip up a solution to attach to a blog post without having to zip the entire folder and then deleting the large dll files and other silly stuff. SolZip just takes what is necessary.

I was the very first downloader of the 1.1 version – you should go download it now! :-)

--
eliasen

Tuesday, 30 June 2009 22:02:39 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Sunday, 28 June 2009

Hi all

Recently, I posted a post about handling mapping to and from a comma separated list. You can find it at http://blog.eliasen.dk/2009/06/22/HandlingCommaSeparatedValuesInsideAMapPartI.aspx

I came to think that this was actually also a great opportunity for me to develop my first cumulative functoid. The functoid is then supposed to take the values as input and output the list of values with a comma in between them.

The functoid has been developed and added to my functoid library at http://eebiztalkfunctoids.codeplex.com – free to download. Also another functoid in the library, which has been there for a while is the “CSV Extract” functoid which extracts a specific position from a separated list.

--
eliasen

Sunday, 28 June 2009 00:58:34 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Monday, 22 June 2009

Hi all

Some times people need to convert a list of elements into a comma separated list of values. In the forums this questions arises every now and then, so here goes a solution.

Suppose this input:

<ns0:MultipleElementsRoot xmlns:ns0="http://MapCommaSeparatedValue.MultipleElementsSchema">
  <MyField>Jan</MyField>
  <MyField>Eliasen</MyField>
  <MyField>BizTalk</MyField>
</ns0:MultipleElementsRoot>

And I want this output:

<ns0:CommaSeparatedRoot xmlns:ns0="http://MapCommaSeparatedValue.CommaSeparatedSchema">
  <CommaField>Jan,Eliasen,BizTalk</CommaField>
</ns0:CommaSeparatedRoot>

Inside a map I would handle it like this (2 approached, that share the first two functoids):

multipletocomma

The reoccurring element is used as input to a string concatenate functoid. The functoid takes a comma as the second input. The output of the concatenate functoid is then used as input for a cumulative concatenate functoid, effectively creating a comma separated list of values. The issue with this list is, that it will have a comma at the end of the line, which needs to be removed.

One way of doing this is to use three functoids to pull this last comma away. First, I take the length of the string, then I subtract one from that, and use the string extract functoid to extract the string beginning at position 1 and ending at (length - 1) and send that to the destination element. Works like a charm.

Now, plenty of people out there (Henrik, you know who you are) would have no moral qualms using a C# scripting functoid to get rid of the extra comma. Like this:

public string RemoveLastComma(string input)
{
  return input.Substring(0, input.Length-1);
}

That one scripting functoid would eliminate the last three functoids I added to remove the last comma. But I still prefer the functoid way of doing it, mostly for maintenance reasons. A new BizTalk developer looking at a map with lots of scripting functoids has no idea what is happening, and even after looking at the code in all the scripting functoids, he can’t remember what is happening in more than a couple of them. In my opinion; Always use the built-in functoids if possible.

Now, just for the kick, I thought that some times the opposite could be the case – going from a comma separated list to lots of elements. This, I cannot solve using built-in functoids, unfortunately, so the map ended up like this:

commatomultiple

Just one scripting functoid. The type is an “Inline XSLT Call Template” and the script is:

<xsl:template name="MyXsltSplitTemplate">
  <xsl:param name="param1" />
  <xsl:if test="$param1 != ''">
    <xsl:element name="MyField">
      <xsl:choose>
        <xsl:when test="contains($param1, ',')">
          <xsl:value-of select="substring-before($param1, ',')" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$param1" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
    <xsl:call-template name="MyXsltSplitTemplate">
      <xsl:with-param name="param1" select="substring-after($param1, ',')" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>

Basically, the function substring-before is used to get any string before a comma and output it. If no comma is in the string, the string is output. The string to the right of a comma is then used as a recursive call to the same template. Again; Works like a charm :-)

So, with any luck, this question can be answered by googling soon instead of asking in the forums :-)

Edit on 27’th June:

--
eliasen

Monday, 22 June 2009 22:55:08 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Saturday, 13 June 2009

Hi all

I have received numeral questions from people getting a compile time error when compiling an orchestration that assigns a distinguished field of type xs:integer to a variable of type int32. Without looking into anything, you would expect this would work.

So lets say that we have a schema like this:

schema

with this XSD:

<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns="http://IntegerDecimal.InputSchema" targetNamespace="http://IntegerDecimal.InputSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="InputRoot">
    <xs:annotation>
      <xs:appinfo>
        <b:properties>
          <b:property distinguished="true" xpath="/*[local-name()='InputRoot' and namespace-uri()='http://IntegerDecimal.InputSchema']/*[local-name()='MyInteger' and namespace-uri()='']" />
        </b:properties>
      </xs:appinfo>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element name="MyInteger" type="xs:integer" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

As you can see, it is a simple schema and the “MyInteger” field is of type xs:integer and it is marked as a distinguished field.

In my orchestration, I have a variable of type int32 called “MyInt” and in an expression shape I do this:

MyInt = InputMessage.MyInteger;

and it fails, which is quite surprising at first glance. At compile time I just get this: "The expression that you have entered is not valid.". That doesn’t help, so looking at my expression shape and reading the mouse over on the error in the expression shape I get this: “cannot implicitly convert type ‘System.Decimal’ to ‘System.Int32’”. Changing the line in the expression shape to this:

MyInt = System.Convert.ToInt32(InputMessage.MyInteger);

will make it work, because now you are explicitly casting the value to an integer.

The first times I saw this error, I thought that the compiler had an error, because I thought I was assigning an integer the value of another integer. It turns out, though, that I wasn’t really – only sort of…

If you look here: http://www.w3.org/TR/xmlschema-2/#integer you can see that the xs:integer type is actually a decimal type restricted to whole numbers. So the compiler actually thinks the field is a decimal and not an integer.

This is kind of silly, since the data type IS restricted to whole numbers. The actual error should be that the xs:integer can contain the number 4567234987623409763546387623476149823497862354845 which really is way to large for an int variable in an orchestration.

Anyway, the way to handle this is, naturally, to avoid the xs:integer type if possible and use the xs:int (or variants of this) instead. Sometimes it is needed, though, and in that case you just need to declare your variables of a type that will be able to contain all the possible values you receive. This can be an Int16 sometimes, if the people who have created the schema just didn’t know what the xs:integer type is. Sometimes the values received will be too large even for an Int64 variable, then consider using a decimal, a string or some other data type.

--
eliasen

Saturday, 13 June 2009 21:43:03 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 

Theme design by Jelle Druyts