Enabling Incremental Compilation of BizTalk .btproj MSBuild Files

Since BizTalk Server 2009, BizTalk Server project files are MSBuild .btproj XML files.

For some reason, BizTalk projects need to be compiled in two phases.

The first pass compiles schemas, maps and pipelines, and produces an intermediate managed assembly. The second pass deletes the intermediate assembly, compiles the orchestrations and produces the final output assembly.

This behavior is hardcoded in the $(MSBuildExtensionsPath)\Microsoft\BizTalk\BizTalkC.targets file.

Unfortunately, this breaks incremental compilation of large solutions that make use of BizTalk Server projects because it forces a recompile each time a project is being built. Fortunately, there is a solution.

MSBuild being extensible, it is possible to override the default (incorrect) targets and fix this. First, create an appropriate file, say BizTalkCustom.targets to host your customizations, in any location of your choice :

  <!-- Rerun the build process (second pass) if the project hosts orchestrations -->
  <!-- The extra << and @(CSharpOutputFromXLang)!='' >> condition prevents this task -->
  <!-- from taking place if the project does not contain any orchestrations.  -->
  <Target Name="SecondPass" Condition="$(SecondBuild)!=true and $(TempAssemblyOnly)!=true and @(XLang)!=''">
    <MSBuild Projects="$(MSBuildProjectFile)" Properties="SecondBuild=true" />
  </Target>

  <!-- Compile XLang/s orchestration -->
  <!-- Notice that is the MSBuild system has decided to run this Target, -->
  <!-- both intermediately compiled files and intermediately compiled assembly are deleted. -->
  <Target
    Name="CompileODX"
    Condition="$(SecondBuild)==true"
    Inputs="@(XLang);$(MSBuildAllProjects);$(ClrTypesAssembly)"
    Outputs="$(BuildDone)">

    <!-- Delete previously generated C# files from XLang compilation -->
    <Delete Files="@(IntermediateAssembly)" />
    <Delete Files="@(CSharpOutputFromXLang)" />

    <XLangTask XLangItems="@(XLang)"
               ProjectReferences="@(ReferencePath)"
               WarningLevel="$(WarningLevel)"
               BpelCompliance="$(BpelCompliance)"
               DefineConstants="$(DefineConstants)"
               TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
               TempAssembly="$(ClrTypesAssembly)"
               OutputDirectory="$(XLangOutputPath)">

    </XLangTask>
  </Target>

The first part of the solution is to modify the <SecondPass> Target in order to add an extra test in the <Condition> attribute. This prevents the SecondPass from even taking place in case your .btproj does not host orchestrations.

The second part of the solution is to defer the removal of the intermediate managed assembly to the <CompileODX> target. Indeed, this target correctly handles incremental compilation, so it does not run if all files are already up-to-date.

In order to use the overriden targets in your compilations, you need to slightly modify your .btproj project files, and import the preceding .targets file, like so:

<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\BizTalk\BizTalkC.targets" />
<Import
    Condition=" Exists('$(CustomExtensionsPath)BizTalkCustom.targets') "
    Project="$(CustomExtensionsPath)BizTalkCustom.targets" />

Where $(CustomExtensionsPath) represents the path to your custom extensions project files.

This entry was posted in BizTalk, MSBuild, Tips. Bookmark the permalink.

One Response to Enabling Incremental Compilation of BizTalk .btproj MSBuild Files

  1. Pingback: Building Multiple Projects in Order with MSBuild | A Technical Perspective

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s