Per instance configuration for Custom Pipeline Components

As many of you already know, your custom pipeline component can expose properties by implementing IPersitPropertyBag. You can then specify the value of these properties at design time, in Visual Studio .NET 2003 and when your component is initialized, it receives values via the IPersistPropertyBag.Load() method.

This is good if you have only one pipeline using this custom component. In some applications, the same pipeline component is associated with multiple receive locations (or send port) and it becomes useful to overwrite the design time values on a per instance basis. It turns out that the documentation offers an example of per instance configuration here but it does not give a great deal of details.

How do I specify per instance configuration?

The first step is to create an XML document that will hold the desired values for properties. The second step is to actually apply the configuration.

  1. The configuration document:

    The configuration really depends on your component, so I'll take the SDK sample "FixMsg" to illustrate my point. Below is an XML document that can be used to configure a pipeline.

    
    <?xml version="1.0" ?>
      <Root xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"> 
        <Stages>
          <Stage CategoryId="9d0e4103-4cce-4536-83fa-4a5040674ad6">
            <Components>
              <Component Name="Microsoft.Samples.BizTalk.Pipelines.CustomComponent.FixMsg"> 
                <Properties>
                   < PrependDatavt="8">XXXXXXXXXXXXXXXXXXXXXXXXXX</PrependData>  
                </Properties>
              </Component>
            </Components> 
          </Stage> 
        </Stages> 
    </Root> 
    

    The "Stage" node describes which stage of the pipeline is being configured. You can get the stage Guids by creating a new Pipeline in Visual Studio and opening the .btp file into your favorite text editor. A .btp file is actually an XML file with a structure quite similar to the instance above so you should have no problem figuring out stage IDs. In fact, to prepare your per instance configuration document, I suggest you start by copying the .btp file and alter it as appropriate.

    For each stage, we list the component(s) that we would like to configure. Here, I am configuring the out of the box sample FixMsg. Then, come all properties that you want to alter. If a property is not in the <Properties> tag, it does not get configured so the design time value is used.

    The format of a property should be explained a little more. the vt="8" attribute specifies which type the property is. The name "vt" refers to a well known automation enumeration: VARTYPE. Here, I have specified 8 (VT_BSTR) since the PrependData property is a string.

  2. Applying the configuration:

    This is achieved by using the BizTalk Explorer OM. The following code will load the configuration for a receive location known by its name:

    string connectionString = "SERVER=<localhost>;DATABASE=BizTalkMgmtDB;Integrated Security=SSPI";

    // Create the root object and set the connection string
    catalog = new BtsCatalogExplorer();
    catalog.ConnectionString = connectionString;

    // Locate the receive location by its name
    ReceiveLocation receiveLocation = FindReceiveLocation(raeceiveLocationName);
    if (receiveLocation != null)
    {
    // Change the configuration
    receiveLocation.ReceivePipelineData = <String containing your configuration XML> ;

    // Commit the changes
    catalog.SaveChanges();
    }

    The following function returns a receive location knowing its name:

    private ReceiveLocation FindReceiveLocation(string receiveLocationName)
    {
    foreach (ReceivePort port in catalog.ReceivePorts)
    foreach (ReceiveLocation receiveLoc in port.ReceiveLocations)
    if (String.Compare(receiveLocationName, receiveLoc.Name,false, CultureInfo.CurrentUICulture) ==0)
    return receiveLoc;

    return null;
    }

Sir, it does not work!

So you have setup your configuration as explained before, you have applied it and you swear you did everything right but it does not get set. Your values are not passed to the pipeline and you even have setup a breakpoint in the custom pipeline code and watched it use the design time values. After some hair pulling, you go and get yourself a coffee. When you come back ... it works now! Why?

Internally, BizTalk reads this configuration every 60 seconds (the cache refresh's default value) or when you recycle the process. So wait for a minute or if you want your configuration to be applied immediately, recycle the process.

Hopefully, this clarifies the per instance configuration process.