5. MSBuild
MSBuild is Microsoft's build platform and is the
technology used by Visual Studio. MSBuild is also included in the .NET
Framework and can be used to build Visual Studio projects without
requiring Visual Studio to be installed.
The ability to take advantage of MSBuild represents
one of the major new features in BizTalk Server 2009. BizTalk has changed its project type to be built on the
standard C# project type. The BizTalk project type then adds other
flavorings to incorporate the additional functionality that is required
by BizTalk on top of the standard C# project type. One of the
capabilities that surfaces through the use of this new project type is
the use of MSBuild.
Evidence that things have changed is that you can now
open a command prompt, navigate to any of your BizTalk Server 2009
projects, type MSBuild <your project name>.btproj, and your project will be compiled.
Additionally, you can now have a build environment
that no longer requires Visual Studio be installed. This is a huge step
forward in being able to integrate with the way that all other .NET
projects are built and in being able to take advantage of build
automation.
5.1. Installing MSBuild
When you install BizTalk Server 2009, you'll see a new check box at the bottom of the available components list, as shown in Figure 3. This check box allows you to install just the deployment components.
When setting up your build server, you will install just the deployment components, as shown in Figure 10-18,
and doing so will install the MSBuild target files. There are two
MSBuild target files that will be installed. They are BizTalkC.Targets
and BizTalkCommon.Targets.
5.2. Incorporating Team Foundation Build
Although build automation is an important step toward
process maturity, a company can take a more encompassing step into the
Application Lifecycle Management role by incorporating the tools and
functionality found in the Team Foundation Build (also called Team
Build) in TFS. Team Foundation Build provides the functionality of the
build server while also being part of, and integrating with the
components of, the Visual Studio Team Foundation Server. With Team
Foundation Build, build managers can synchronize source code, compile an
application, run unit tests, perform code analysis, release builds to
the file server, and publish build reports showing success or failure of
the build and tests. By incorporating Team Foundation Build in your
environment, you can take advantage of the whole build lifecycle.
BizTalk Server 2009 can now fully participate in this part of the ALM
cycle.
5.3. Automating Deployment
So far we have talked about the ability to automate
the build process with MSBuild. You can also use MSBuild to automate the
deployment process.
A number of extension libraries are available. The two most widely known and used are SDC Tasks, found at http://www.codeplex.com/sdctasks, and MSBuildTasks, found at http://msbuildtasks.tigris.org/.
The components in these libraries provide the functionality to create
web sites, create application pools, configure virtual servers, create
Active Directory users, create folder shares, install into the GAC,
configure SQL Server, and configure BizTalk Server. Together these tools
provide the custom tasks to allow you to create a complete automated
deployment script.
If you find that you need additional functionality
that is not supplied with MSBuild or through any of the available
community libraries, you can extend MSBuild through the use of .NET code
by creating components that implement the
Microsoft.Build.Framework.ITask interface.
5.4. Looking at an Example
Fully functional MSBuild script, including the
command-line arguments to call the build. Here's the script:
<! Command line arguments to call this script:
msbuild BtsAutomatedBuildSample.build /p:Configuration=Debug
/logger:FileLogger,Microsoft.Build.Engine;logfile=MyLog.log;
append=true;verbosity=diagnostic;encoding=utf-8
We are using the latest version of the sdc tasks and the
names are still prefixed with BizTalk 2006 but they still apply to BizTalk 2009.
>
<Project DefaultTargets="GetBizTalkInstallLocation;BuildBTSSolution" xmlns=
"http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Sdc_Tasks_2.1.2688.0\Microsoft.Sdc.Common.tasks"/>
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.
Community.Tasks.Targets"/>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<BinPath>.\bin</BinPath>
<BtsInstallLocation>C:\Program Files\Microsoft BizTalk Server 2009
</BtsInstallLocation>
<BtsApplicationName>BtsAutomatedBuildSample</BtsApplicationName>
<ApplicationExists>False</ApplicationExists>
<SchemasAssemblyPath>$(MSBuildProjectDirectory)\
BtsAutomatedBuildSampleSchemas\bin\Development\
BtsAutomatedBuildSampleSchemas.dll</SchemasAssemblyPath>
<MapsAssemblyPath>$(MSBuildProjectDirectory)\BtsAutomatedBuildSampleMaps
\bin\Development\BtsAutomatedBuildSampleMaps.dll</MapsAssemblyPath>
<PipelineComponentsAssemblyPath>$(MSBuildProjectDirectory)\
BtsAutomatedBuildSamplePipelineComponents\bin\Debug\
BtsAutomatedBuildSamplePipelineComponents.dll</PipelineComponentsAssemblyPath>
<PipelinesAssemblyPath>$(MSBuildProjectDirectory)\
BtsAutomatedBuildSamplePipelines\bin\Development\
BtsAutomatedBuildSamplePipelines.dll</PipelinesAssemblyPath>
<OrchestrationsAssemblyPath>$(MSBuildProjectDirectory)\
BtsAutomatedBuildSampleOrchestrations\bin\Development\
BtsAutomatedBuildSampleOrchestrations.dll</OrchestrationsAssemblyPath>
<BindingFilePath>$(MSBuildProjectDirectory)\
BtsAutomatedBuildSample.BindingInfo.xml</BindingFilePath>
</PropertyGroup>
<Target Name="BuildBTSSolution" DependsOnTargets="ApplicationExists;MakeBinDir">
<MSBuild Projects="$(MSBuildProjectDirectory)\BtsAutomatedBuildSample.sln"
Properties="Configuration=Debug" />
<CallTarget Targets="MoveAssembliesToBin" />
<CallTarget Targets="CreateBizTalkApplication" />
<CallTarget Targets="DeployPipelineComponents" />
<CallTarget Targets="DeployBtsResources" />
<CallTarget Targets="DeployBindings" />
<CallTarget Targets="ExportMsi" />
</Target>
<Target Name="MakeBinDir" Condition="!Exists('$(BinPath)')">
<Message Text="Creating bin directory... $(BinPath)" />
<MakeDir Directories= "$(BinPath)"/>
</Target>
<Target Name="MoveAssembliesToBin" DependsOnTargets="MakeBinDir">
<Message Text="Move assemblies to common bin directory" />
<Copy SourceFiles="$(SchemasAssemblyPath);$(MapsAssemblyPath);
$(PipelinesAssemblyPath);$(OrchestrationsAssemblyPath)"
DestinationFolder="$(BinPath)" />
</Target>
<Target Name="CreateBizTalkApplication" Condition="$(ApplicationExists)=='False'">
<Message Text="Creating $(BtsApplicationName) Application..." />
<CallTarget Targets="RemoveApplication" />
<BizTalk2006.Application.Create Application="$(BtsApplicationName)" />
<! <Exec Command ='"$(BtsInstallLocation)\BTSTask" AddApp
/ApplicationName:$(BtsApplicationName)' /> >
</Target>
<Target Name="DeployBtsResources">
<Message Text="Adding Resources (deploying) assemblies to
$(BtsApplicationName)Application" />
<! <Exec Command ='"$(BtsInstallLocation)\BTSTask" AddResource
/ApplicationName:$(BtsApplicationName) /Type:System.BizTalk:BizTalkAssembly
/Source:"$(SchemasAssemblyPath)"' /> >
<BizTalk2006.Assembly.Deploy Application="$(BtsApplicationName)" AssemblyPath=
"$(SchemasAssemblyPath)" InstallInGac="true" />
<BizTalk2006.Assembly.Deploy Application="$(BtsApplicationName)" AssemblyPath=
"$(MapsAssemblyPath)" InstallInGac="true" />
<BizTalk2006.Assembly.Deploy Application="$(BtsApplicationName)" AssemblyPath=
"$(PipelinesAssemblyPath)" InstallInGac="true" />
<BizTalk2006.Assembly.Deploy Application="$(BtsApplicationName)" AssemblyPath=
"$(OrchestrationsAssemblyPath)" InstallInGac="true" />
</Target>
<Target Name="ApplicationExists">
<BizTalk2006.Application.Exists Application="$(BtsApplicationName)">
<Output TaskParameter="DoesExist" PropertyName="ApplicationExists" />
</BizTalk2006.Application.Exists>
<Message text="Application Exists: $(ApplicationExists)" />
</Target>
<Target Name="RemoveApplication" Condition="$(ApplicationExists)=='True'">
<Message Text="Removing $(BtsApplicationName) Application..." />
<BizTalk2006.Application.Stop Application="$(BtsApplicationName)" />
<BizTalk2006.Application.Delete Application="$(BtsApplicationName)" />
</Target>
<Target Name="DeployBindings">
<Message Text="Deploying bindings" />
<Exec Command ='"$(BtsInstallLocation)\BTSTask" ImportBindings /Source:
"$(BindingFilePath)" /ApplicationName:$(BtsApplicationName)' />
</Target>
<Target Name="ExportMsi">
<Exec Command ='"$(BtsInstallLocation)\BTSTask" ExportApp /ApplicationName:
$(BtsApplicationName) /Package:"$(MSBuildProjectDirectory)\
$(BinPath)\$(BtsApplicationName).msi"' />
</Target>
<Target Name="DeployPipelineComponents">
<Message Text="Moving pipeline components to BTS dir" />
<Copy SourceFiles="$(PipelineComponentsAssemblyPath)" DestinationFolder=
"$(BtsInstallLocation)\Pipeline Components" />
</Target>
<Target Name="GetBizTalkInstallLocation">
<Registry.Get RegistryHive="LocalMachine" Key=
"Software\Microsoft\BizTalk Server\3.0\" Value="InstallPath">
<Output TaskParameter="Data" PropertyName="BtsInstallLocation"/>
</Registry.Get>
<Message Text="BizTalk Install Location is $(BtsInstallLocation)" />
</Target>
</Project>
As you look over this script, you'll see a number of
interesting items. The first is that the script will build the solution
by invoking MSBuild inside an MSBuild script. The invocation is done
with the MSBuild task. This task uses the same MSBuild process to
execute the child build process. This approach is faster than using the
Exec task since no new MSBuild process is created.
Next, the BuildBTSSolution target controls what other
targets are called. It becomes very easy to see what steps the script
will follow during execution.
Take a look at the RemoveApplication target. You can
set conditions that will determine whether the target will get executed.
A condition can also be set on the PropertyGroup node. In this sample,
we could create additional PropertyGroup nodes with different conditions
such as Release. The new node would contain the specific data required
for that type of build.
Lastly, our example uses the SDC tasks to provide
specific BizTalk deployment functions. The library currently
differentiates between BizTalk 2004 and BizTalk 2006 functions. The
BizTalk 2006 methods still apply to BizTalk 2009.
5.5. Moving Forward with MSBuild
Our intention has not been to provide a tutorial on
MSBuild. We merely wanted to show how easy it is to create a fully
functional build and deploy script. You can find more information on
MSDN at http://msdn.microsoft.com/en-us/library/0k6kkbsd.aspx.
One useful ability not shown here is being able to keep track of which
targets were successful so that if an error occurred and you needed to
restart the script, it would not rerun the successfully executed
targets.
When looking at deployment technologies, a frequent
question is, why use MSBuild instead of the MSI functionality built into
BizTalk? There are a number of factors that may sway you to one side
over the other.
If you are doing continuous builds or are going to
use the Team Build functionality, then you are most likely already
working with MSBuild. At this point you can continue to expand on the
MSBuild script to include the deployment. This will automate the entire
process including such things as stopping applications and uninstalling,
installing, and restarting hosts.
MSBuild is also beneficial if
you have more artifacts to your application than those contained in
BizTalk. The MSI functionality is primarily focused on artifacts used by
the BizTalk application. MSBuild allows you to script the deployment
and configuration of all portions of the larger application including
security settings, IIS functionality, custom .NET components, and other
server functionality such as SQL Server, Commerce Server, and others.