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:
- 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 Colestock for pointing this out).
- 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:
- If it has an explicit assembly path, it will try to use Assembly.LoadFrom() to load it. This usually doesn’t happen, btw.
- 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.
- 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.