BizTalk feature deployment using BTDF

When developing a large BizTalk project which has been broken down into features it can be useful to be able to deploy just the current feature you are working on and any associated dependencies, without deploying the entire application.

 

If you are using the BizTalk Deployment Framework (BTDF) this can be achieved relatively easily.

 

Instead of having one single deployment project file, have one tasks file for each feature, for example Deployment.Feature1.tasks; Deployment.Feature2.tasks; etc.

 

This can be constructed in much the same way as the Deployment.btdfproj, so can contain all the normal artefacts. This is an example of a complete feature tasks files, called Deployment.MyFeature1.tasks:

 

<?xml version="1.0" encoding="utf-8"?>
<
Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<!--
External Assemblies -->
<
ItemGroup>
<
ExternalAssemblies Include="MyExternalAssembly.dll">
<
LocationPath>$(BinDir)</LocationPath>
</
ExternalAssemblies>
</
ItemGroup>

<!--
Orchestrations -->
<
ItemGroup>
<
Orchestrations Include="MyOrchestration.dll">
<
LocationPath>$(BinDir)</LocationPath>
</
Orchestrations>
</
ItemGroup>

<!--
Pipelines-->
<
ItemGroup>
<
Pipelines Include="MyPipeline1.dll">
<
LocationPath>$(BinDir)</LocationPath>
</
Pipelines>
<
Pipelines Include="MyPipeline2.dll">
<
LocationPath>$(BinDir)</LocationPath>
</
Pipelines>
</
ItemGroup>

<!--
Schemas -->
<
ItemGroup>
<
Schemas Include="MySchema1.dll">
<
LocationPath>$(BinDir)</LocationPath>
</
Schemas>
<
Schemas Include="MySchema2.dll">
<
LocationPath>$(BinDir)</LocationPath>
</
Schemas>
<
Schemas Include="MySchema3.dll">
<
LocationPath>$(BinDir)</LocationPath>
</
Schemas>
</
ItemGroup>

<!--
Transforms-->
<
ItemGroup>
<
Transforms Include="MyMap.dll">
<
LocationPath>$(BinDir)</LocationPath>
</
Transforms>
</
ItemGroup>

<!--
VDirs-->
<
ItemGroup>
<
VDirList Include="*">
<
Vdir>MyVDir</Vdir>
<
Physdir>..\VDirs\MyVDir</Physdir>
<
AppPool>MyAppPool</AppPool>
<
AppPoolNetVersion>4.0</AppPoolNetVersion>
</
VDirList>
</
ItemGroup>

</
Project>

 

 

In your main project deployment file you can then import all your feature task files as show in the following example:

 

<?xml version="1.0" encoding="utf-8"?>
<!--
Deployment Framework for BizTalk 5.0
Copyright (c) 2008-2010 Thomas F. Abraham and Scott Colestock
-->
<
Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Deploy">

<
Import Project="Deployment.GlobalSettings.tasks" />
<
Import Project="Deployment.Common.tasks" />
<
Import Project="Deployment.MyFeature1.tasks" />
<
Import Project="Deployment.MyFeature2.tasls" />
<
Import Project="$(DeploymentFrameworkTargetsPath)BizTalkDeploymentFramework.targets" />

<
PropertyGroup>
<
DeployDependsOn>
RemoveDuplicateItems;
$(DeployDependsOn);
</DeployDependsOn>
<
UndeployDependsOn>
RemoveDuplicateItems;
$(UndeployDependsOn);
</UndeployDependsOn>
<
DeployBizTalkMgmtDBfalseDependsOn>
RemoveDuplicateItems;
$(DeployBizTalkMgmtDBfalseDependsOn);
</DeployBizTalkMgmtDBfalseDependsOn>
<
UndeployBizTalkMgmtDBfalseDependsOn>
RemoveDuplicateItems;
$(UndeployBizTalkMgmtDBfalseDependsOn);
</UndeployBizTalkMgmtDBfalseDependsOn>
</
PropertyGroup>

<!--
Remove duplicate entries created as a result of importing multiple project files -->
<
Target Name="RemoveDuplicateItems">
<!--
AdditionalFiles -->
<
RemoveDuplicates Inputs="@(AdditionalFiles)">
<
Output TaskParameter="Filtered" ItemName="FilteredAdditionalFiles" />
</
RemoveDuplicates>
<
ItemGroup>
<
AdditionalFiles Remove="@(AdditionalFiles)" />
<
AdditionalFiles Include="@(FilteredAdditionalFiles)" />
</
ItemGroup>

<!--
AdditionalFilesQualified -->
<
RemoveDuplicates Inputs="@(AdditionalFilesQualified)">
<
Output TaskParameter="Filtered" ItemName="FilteredAdditionalFilesQualified" />
</
RemoveDuplicates>
<
ItemGroup>
<
AdditionalFilesQualified Remove="@(AdditionalFilesQualified)" />
<
AdditionalFilesQualified Include="@(FilteredAdditionalFilesQualified)" />
</
ItemGroup>

<!--
ExternalAssembles -->
<
RemoveDuplicates Inputs="@(ExternalAssemblies)">
<
Output TaskParameter="Filtered" ItemName="FilteredExternalAssemblies" />
</
RemoveDuplicates>
<
ItemGroup>
<
ExternalAssemblies Remove="@(ExternalAssemblies)" />
<
ExternalAssemblies Include="@(FilteredExternalAssemblies)" />
</
ItemGroup>

<!--
ExternalAssemblesQualified -->
<
RemoveDuplicates Inputs="@(ExternalAssembliesQualified)">
<
Output TaskParameter="Filtered" ItemName="FilteredExternalAssembliesQualified" />
</
RemoveDuplicates>
<
ItemGroup>
<
ExternalAssembliesQualified Remove="@(ExternalAssembliesQualified)" />
<
ExternalAssembliesQualified Include="@(FilteredExternalAssembliesQualified)" />
</
ItemGroup>

<!--
Repeat for as many different artefact types as you have duplicates for.
These could include:

Orchestrations and OrchestrationsQualified
Pipelines and PipelinesQualified
PipelineComponents and PipelineComponentsQualified
Schemas and SchemasQualified
Transforms and TransformsQualified

VDirs are slightly different, and shown below...
-->

<!--
VDirList -->
<!--
Note that this uses RemoveVDirDuplicates instead of the standard RemoveDuplicates. This
makes uses of an extended MSBuild method and is detailed further on in this blog post
-->
<
RemoveVDirDuplicates Inputs="@(VDirList)">
<
Output TaskParameter="Filtered" ItemName="FilteredVDirList" />
</
RemoveVDirDuplicates>
<
ItemGroup>
<
VDirList Remove="@(VDirList)" />
<
VDirList Include="@(FilteredVDirList)" />
</
ItemGroup>
</
Target>
</
Project>

 

 

A change in here compared to a standard BTDF project file is the addition of all the RemoveDuplicates nodes. If you have multiple feature task files and the same artefact is included in more than one of these files, then you don’t want to deploy it multiple times at deployment time. These RemoveDuplicates tasks strip out duplicates, leaving you with just one instance of each artefact. There is one difference in amongst these - the RemoveVDirDuplicates. Virtual Directory artefacts have to be treated differently, and this is covered below.

 

You will also notice from the above sample that there is a GlobalSettings.tasks file, and a Common.tasks file.

 

The Common.tasks file contains artefacts that are shared between multiple features. For example you might have some shared helper classes that every feature needs. This task file can be similar in structure to the Feature task file example above, containing just the shared artefacts that you need.

 

The GlobalSettings file contains all the standard sections that you would normally expect to find in the Deployment.btdfproj, such as which artefact types to include, the ProductName etc. Importantly it also contains the following at the top of the file, directly beneath the Project Node:

 

<UsingTask TaskName="BTDF.Build.Tasks.RemoveVDirDuplicates"
AssemblyName="BTDF.Build.Tasks.dll"
Condition="'$(Configuration)' == 'Server'" />

<
UsingTask TaskName="BTDF.Build.Tasks.RemoveVDirDuplicates"
AssemblyName="Path_to_BinDir\BTDF.Build.Tasks.dll"
Condition="'$(Configuration)' != 'Server'" />

 

This is used by the RemoveVDirDuplicates task in the Deployment.btdfproj file shown above. The code for this task is shown below. You will need to compile this into an assembly which you then reference in the Deployment.btdfproj as show above. In this example the code has been compiled into BTDF.Build.Tasks.dll.

 

using Microsoft.Build.Framework;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
using System;
using System.Collections;
using System.Runtime;


namespace Biztalk.Build.Tasks
{
public class RemoveVDirDuplicates : Task
{
private ITaskItem[] inputs = (ITaskItem[]) new ITaskItem[0];
private ITaskItem[] filtered;

public ITaskItem[] Inputs
{
[
TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
get
{
return this.inputs;
}
[
TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
set
{
this.inputs = value;
}
}

[
Output]
public ITaskItem[] Filtered
{
[
TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
get
{
return this.filtered;
}
[
TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
set
{
this.filtered = value;
}
}

public override bool Execute()
{
Hashtable hashtable = new Hashtable(this.inputs.Length, (IEqualityComparer)StringComparer.OrdinalIgnoreCase);
ArrayList arrayList = new ArrayList();
foreach (TaskItem taskItem in this.Inputs)
{
if (!hashtable.ContainsValue((object) taskItem.GetMetadata("VDir")))
{
hashtable[(
object)taskItem.ItemSpec] = (object)string.Empty;
arrayList.Add((
object)taskItem);
}
}
this.Filtered = (ITaskItem[]) arrayList.ToArray(typeof (ITaskItem));
return true;
}
}
}

 

 

 

You now have everything you need to get started on deploying either the whole application into BizTalk, or just individual features.

 

To deploy the whole application you have the main Deployment.btdfproj file that you created earlier, which would import all the task files for each individual feature in your entire application.

 

To deploy just a specific feature, create a new Deployment.btdfproj file in a feature folder and simply include the imports of the specific feature task files that you want to deploy, along with the Common.tasks file if you have one. You can also have an individual bindings file for your feature containing just the relevent resources, whilst maintaining a master one for your whole application. This can also be achieved by listing each features binding file and combining them at deployment time, however this requires further changes to the BTDF which will be covered in a future post.

Written by Ed Loveridge at 11:00

Categories :

0 Comments :

Comment

Comments closed