Introduction to MSBuild

Introduction to MSBuild

What is MSBuild ?

MSBuild is the Microsoft Build Engine used for building and creating deployment packages for applications. It comes as a pre installed application with Visual Studio and can also be installed as a standalone application on environments where we do not have Visual Studio to build our projects.

If you have ever created a project in Visual Studio you have already encountered an MSBuild file. If we unload a project in Visual Studio and try to edit the .csproj file in case of C# based projects, we see an XML file which is exactly a MSBuild file. All the instructions written inside the MSBuild file or .csproj file is processed by the MSBuild.exe to build our projects. The .csproj files can be further customised to do a wide variety of activites based on our requirement of building and deploying a project.

Visual Studio internally invokes MSBuild.exe and provides our .csproj XML files as an input to MSBuild.exe to give us the build output. Although the .csproj files or MSBuild files for a project is automatically created by Visual Studio while creating a project , we can create our own build files to build the project.

The build files created by Visual Studio usually have an extension of .csproj, .vbproj, .dbproj indicating the type of project i.e C#, VB or Database Project. When we create an MSBuild file to build our projects we generally create a file with the extension .proj which indicates that the file is a build file for building other projects.

When you are creating a build file for building multiple projects there might be a need of having some settings that you would want to apply while building other projects. We generally create those files as .targets extension and these files just contain some common instructions of building projects. This file can then be imported to your build file to include the instructions into your build process. It is quite obvious that this is done for code reusability and you might have already encountered .targets files while navigating through the MSBuild directory in your Visual Studio folder in your installation directory like Program Files.

Structure of an MSBuild File

A typical MS build file contains the following tags -

1. Project - This is the root of the Build XML file. It can have attributes like 'DefaultTarget' to specify the entry point for the build process and xmlns (XMLNameSpace) attribute to specify the XML schema for the project file.

2. PropertyGroup and Property - These tags are like variable and constant declaration in a typical programming language where the PropertyGroup is a container of all the variable/constant names and Property is the name of the single variable/constant and the value of the Property element contains the static value of the Property. We can have multiple Property tags nested inside a PropertyGroup.

The PropertyGroup is typically used to provide information like server name , connectionStrings, credentials, build configurations, source and destination file paths and other information needed for customization. The Property values can be accessed inside the file using $(PropertyName) or we can also pass the property value from the command prompt. Also Property is usually evaluation based on certain Condition. The condition attribute of the Property element species the condition for which the property needs to be evaluated.

3. ItemGroup and Item - These tags are like list declaration in a typical programming language where the ItemGroup is the list name and Item specifies each item present in the list. This is mainly used for the code files in the project. Like the PropertyGroup an ItemGroup can have nested Item tags inside it. inside a PropertyGroup.

4. Targets and Tasks - A target contains the logic of the Build file that contains instructions to perform some action. The root element Project usually specifies a DefaultTarget name as the entry point of execution of the logic inside the Build File. A target invocation can depend on the execution of other Targets in the build file to maintain the order of execution of the logic in the Build file.
Tasks are specified inside a target. Some of the built in examples of the tasks are Copy, MakeDir, Delete, CSc, Vbc, Exec, Message etc... The Copy task copies files to a new location. The Csc task invokes the Visual C# compiler. The Vbc task invokes the Visual Basic compiler. The Exec task runs a specified program. The Message task writes a message to a logger

A target can also contain PropertyGroup and ItemGroup inside it and those Property and Item nested inside a Target are evaluated dynamically when the Target is invoked.

When I initially read about the MSBuild file I could relate it to a programming language with the following analogy -

Project - Class PropertyGroup - List of global variables ItemGroup - Lists declared globally. Target - Function with PropertyGroup and ItemGroup as the local declaration of variables and lists inside a function.

I am sorry if its confusing but it really helped me create a mind map of the elements in Build file with respect to a programming language.

Sample .csproj file of a Console App in .NET Framework

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{05928435-3903-49BE-B207-D960B65DDFFB}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <RootNamespace>SampleApp</RootNamespace>
    <AssemblyName>SampleApp</AssemblyName>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Sample .csproj file of a Console App in .NET Core

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
</Project>

As you can see above that the .csproj for .NET Core app has been simplified with the introduction of SDK which carries most of the common instructions which are present in the .csproj of a .NET Framework project file.

We would be able to understand the Structure of the build file if we try to view and edit the project files in Visual Studio. You can also see the default content of the MSBuild file from the Project properties with a UI representation. If you modify the values on the UI and unload and edit the .csproj file you would be able to see the changes in the .csproj file.

Just like learning any programming language we would create "Hello World" program printed by out MSBuild file and see it in action in our next post.

If you are interested in learning MSBuild in depth you can go through the official documentation by microsoft from the here

Thank you for reading and see you in the next post !