One topic that sometimes causes confusion when developing custom pipeline components
in BizTalk Server is how, and where, should their assemblies should be deployed and
how they are loaded by BizTalk. Let’s talk a little bit about it.

In BizTalk Server 2004, there was only one place to deploy your custom pipeline components:
The “Pipeline Components” folder on your BizTalk installation directory. Some conflicts arose
because of this requirement, and made it “uncomfortable” to have components that had
external dependencies on other assemblies.

In BizTalk Server 2006, this restriction was lifter, and now the recommendation is:
Deploy to the Pipeline Components folder on development machines only; deploy to
the GAC. The former is really only necessary so that the design time infrastructure
(i.e. the pipeline designer) works.

But let’s look at what actually happens when you use a custom pipeline component in
a BizTalk pipeline:

  1. When you add the component to the pipeline, it is referenced in the .BTP file using
    the complete class name that implements the component as well as the partial assembly
    name that contains it (i.e. name only, no version/culture/publictoken). Usually, a
    project reference might be added to the assembly as well, but this is not used during
    compilation. (Thanks to Scott
    for pointing this out).
  2. When the BizTalk project is compiled, a strongly types class is generated representing
    your custom pipeline. That class will dynamically load all pipeline components used
    it in, and does so by using the complete, assembly-qualified name of the component
    class, which does include full assembly name information.

    Each component is loaded by a call to PipelineManager.CreateComponent() which eventually
    loads the component using reflection.

In BizTalk Server 2006, the components are loaded internally by the CreateManagedInstance()
method of the internal ComponentLoader class, which does the following steps:

  1. If it has an explicit assembly path, it will try to use Assembly.LoadFrom() to load
    it. This usually doesn’t happen, btw.
  2. It will then try to use Type.GetType() to get to the class type. If the assembly is
    GAC’ed or in the probing path, then this should cause the assembly to be probed and
    loaded in the Load context without problems. This is the case you’ll usually prefer
    to happen in servers, as it will give you the least trouble.
  3. If that fails, BizTalk will then extract the assembly name from the qualified type
    name, append “.dll” to the base name and then again try to do a LoadFrom() trying
    to load it manually from the Pipeline Components folder.

One could think that perhaps a better option for the BizTalk design would’ve been
to make the Pipeline Components folder part of the probing path for BizTalk and simply
let the runtime do its thing. This is not the case, however. In any case, this wouldn’t
have worked because pipelines are not only used inside the BizTalk Application Hosts
(i.e. BTSNTSvc.exe), but also in isolated hosts like IIS where having the Pipeline
Components folder as part of the probing path is not an option.