While chasing incremental build time improvements, I found that .btproj files and thus all other projects that depend on these are rebuilt (partly) on each incremental build. Tracking this all the way to BizTalkCommon.targets, I found that it does a 2 pass compilation of the assembly - but only the first pass respects already built artifacts, thus breaking the incremental part of the dependency chain. The offending target can be seen in BizTalkCommon.targets (line 228):
<!-- Delete the assembly and rerun the build process -->
<Target Name="SecondPass"
Condition="$(SecondBuild)!=true and $(TempAssemblyOnly)!=true">
<Delete Files="@(IntermediateAssembly)" />
<MSBuild Projects="$(MSBuildProjectFile)" Properties="SecondBuild=true"/>
</Target>
I realize that there's a reason for the 2 pass build, but simply cannot believe it wouldn't be possible to specify appropriate in- and outputs for the target to handle incremental builds correctly.
Does anyone know if there's a patch for the .targets file, or if there's another good reason that incremental builds aren't supported?
You can enable incremental compilation of MSBuild BizTalk project with a couple of very simple changes. Basically, you need to override two targets that are defined in the BizTalkCommon.targets
file.
Those targets can be overriden in your own .btproj files and do not require modifying the original .targets file that ships with BizTalk.
How To
First Create you own .targets file to host your customizations, for instance BizTalkCustom.targets
:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\BizTalk\BizTalkC.targets" />
<!-- Rerun the build process (second pass) -->
<Target Name="SecondPass" Condition="$(SecondBuild)!=true and $(TempAssemblyOnly)!=true and @(XLang)!=''">
<MSBuild Projects="$(MSBuildProjectFile)" Properties="SecondBuild=true" />
</Target>
<!-- Compile XLang/s orchestration -->
<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>
Then, replace the last Import
statement in your .btproj file:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MyCustomExtensions)\BizTalkCustom.targets" />
How doe it work
BizTalk Server projects need somehow to be compiled in two passes. The first pass compiles schemas, maps and pipelines, whereas the second pass compiles orchestrations.
You'll notice that the overriden targets are very very similar than the original ones, defined inside the BizTalkCommon.targets file
. In fact, I made two simple changes:
The first change involves modifying the SecondPass
Target and adding an extra test in the Condition
attribute. This test is usefull to prevent the second pass from occurring if your project does not even have Orchestrations.
Unfortunately, if your project contains Orchestrations, the original SecondPass
Target deletes the intermediate assemblies and then proceed to compile the Orchestrations. However, the CompileODX
Target does not need to run if all files are already up to date. Therefore, the second change involves moving the Delete
Task from the SecondPass
Target to the CompiledODX
Target.
That's all there is to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With