I have a problem – I want to automatically generate a license file then embed the file in my C# assembly. This solution works by creating a new MSBuild targets file and embedding it in my project (csproj
) file. Let’s start by modifying my project file.
I imported the new MSBuild targets file near the bottom of my current project file (CustomMSBuild.targets
). At the top of the file, I added the folder of the target file on my local machine. My Azure Pipeline build can easily redirect the directory by defining the $(CustomMSBuildDir)
property prior to loading this project.
<!-- Allow Azure Pipeline to override custom build directory --> <CustomMSBuildDir="'$(CustomMSBuildDir)' == ''">C:\Dev\BuildResources\MSBuild\</CustomMSBuildDir> ... <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(CustomMSBuildDir)CustomMSBuild.targets" />
Next in my custom targets file (CustomMSBuild.targets
), I have inserted my custom build step. (Additional information on this method of adding build steps is at the end of this article.) I want my task to run before the CoreBuildDependsOn targets. If I pick a target that runs later in the build cycle, the file will not be embedded. (It took me a day to realize that I had done this before I hooked into this earlier step.)
<PropertyGroup Condition="$([System.Text.RegularExpressions.Regex]::IsMatch($(DefineConstants), '^(.*;)*SELECT_43(;.*)*$'))"> <CoreBuildDependsOn> CG_AutogenLicenseFile; $(CoreBuildDependsOn) </CoreBuildDependsOn> </PropertyGroup>
Finally, my custom task generates my required file (details omitted), adds it to the collection of files to be embedded and dumps a diagnostic message to the log. The file is written to my main project folder
<Target Name="CG_AutogenLicenseFile"> <CGTask_AutogenLicenseFile <!-- Custom task that generates license file and writes it to filesystem at path "OutputLicenseFilePath" --> <Output PropertyName="OutputLicenseFilePath" TaskParameter="OutputLicenseFilePath" /> </CGTask_AutogenLicenseFile> <ItemGroup> <EmbeddedResource Include="$(OutputLicenseFilePath)" /> </ItemGroup> <Message Text="License file -> $(OutputLicenseFilePath)" Importance="high" /> </Target>
For those that are curious, these are the targets defined in the target we overrode:
<PropertyGroup> <CoreBuildDependsOn> BuildOnlySettings; PrepareForBuild; PreBuildEvent; ResolveReferences; PrepareResources; ResolveKeySource; Compile; ExportWindowsMDFile; UnmanagedUnregistration; GenerateSerializationAssemblies; CreateSatelliteAssemblies; GenerateManifests; GetTargetPath; PrepareForRun; UnmanagedRegistration; IncrementalClean; PostBuildEvent </CoreBuildDependsOn> </PropertyGroup>
Links
Example source: Microsoft.CSharp.targets
Example source: Microsoft.CSharp.CommonVersion.targets