Specifying tests as build target in .NET Framework Applications - c#

I currently have a .NET Framework Application whose build process I'm trying to automate using jenkins. Is there a way to specify the tests in a Target in the Start-up project file so that I can specify a command like:
msbuild /t:Test
and it will run the tests?

I would recommend you create a new proj file, with Test Target.
For example, you will create a file at your repository root, call it jenkins.build, and put the following code in it:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Test">
<ItemGroup>
<UnitTests Include="$(WorkingFolder)\**\bin\$(Configuration)\**\*.UnitTests.dll;" Exclude="$(WorkingFolder)\**\*Microsoft.VisualStudio.*;"/>
</ItemGroup>
<PropertyGroup>
<VSTestPath>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"</VSTestPath>
<VSTestCommand>
$(VSTestPath) #(UnitTests->'"%(FullPath)"', ' ')
</VSTestCommand>
</PropertyGroup>
<Exec Command="$(VSTestCommand)" ContinueOnError="false" />
</Target>
</Project>
Then call this file with msbuild jenkins.build /t:Test.
(Of course, this file is defined a lot of things that are environment-dependent.)

Related

Create a .NET Core Nuget package to autogenerate c# classes

I have a .NET Framework project (A) which generates an exe which takes html file as input and outputs an autogenerated C# class file (like a template of sorts). The .csproj of A looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutputType>Exe</OutputType>
<AssemblyName>ProjectA</AssemblyName>
</PropertyGroup>
<ItemGroup>
<None Include="ProjectA.exe.config">
<ItemGroup>
</Project>
In project B, we're using the exe like this: (part of csproj of project B)
<Target Name="_EX_MyGenerateFile_cs" Inputs="MyHtml.html" Outputs="$(O)\MyGeneratedFile.cs" Condition="'$(BuildingOutOfProcess)' != 'False' AND '$(BuildingProject)' == 'True'" BeforeTargets="BeforeCompile">
<Exec WorkingDirectory="$(MSBuildProjectDirectory)" LogStandardErrorAsError="true" Command="<path to projectA exe> MyHtml.html $(O)\MyGeneratedFile.cs" />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)" LogStandardErrorAsError="true" Command="if errorlevel 1 echo $(ERR_MSG) Unable to compile MyHtml.html to $(O)\MyGeneratedFile.cs" />
</Target>
Now, I wish to create a Nuget package (.NetCore) that achieves similar functionality as projectA (i.e somehow be able to consume this new package in a different netcore application and autogenerate the files- in a similar way projectB is able to use ProjectA's exe to generate the files). As I understand, .NET Core project would create a dll (not an exe); what is the way of using this dll to achieve what I want?
Any help is appreciated!
As .NET Core is a cross platform framework. This DLL file works across all platforms that are supported by the .NET Core runtime (Windows, Linux, and macOS). This is known as "framework dependent" deployment.
For your case there are 2 options :
To run any .dll of .NET Core application , command dotnet yourProject.dll is used.
Part of projectB.csproj will look like this:
<Target Name="_EX_MyGenerateFile_cs" Inputs="MyHtml.html" Outputs="$(O)\MyGeneratedFile.cs" Condition="'$(BuildingOutOfProcess)' != 'False' AND '$(BuildingProject)' == 'True'" BeforeTargets="BeforeCompile">
<Exec WorkingDirectory="$(MSBuildProjectDirectory)" LogStandardErrorAsError="true" Command="dotnet <path to projectA dll> MyHtml.html $(O)\MyGeneratedFile.cs" />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)" LogStandardErrorAsError="true" Command="if errorlevel 1 echo $(ERR_MSG) Unable to compile MyHtml.html to $(O)\MyGeneratedFile.cs" />
</Target>
If you really want exe file, generate exe file using a Self-Contained deployment.
This will create an output that contains its own copy of the .NET Core runtime and an yourProject.exe file.
Con of this approach:
It increases the size of the published application.
It needs to be updated when new versions of the runtime are released.
The resulting application only works on the published operating system published.

When using MSBuild to build a WPF project which files should I specify for compilation? does order matter?

I'm attempting to automate the build process of my WPF project and set up a CI system. I'm following details found in Continuous Integration in .NET by Marcin Kawalerowicz and Craig Bernston. Specifically, details in chapter 3 pertaining to build automation in MSBuild. The authors provide a sample build file for a project consisting of a single C# file, which looks similar to
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build;Deploy;Execute"
xmlns="http://schemas.microsoft.com/developer/msuild/2003">
<PropertyGroup>
<Debug Condition="'$(Delete)'==''">false</Debug>
<OutputFile>SampleMSBuild.exe</OutputFile>
<OutputDirectory>Output</OutputDirectory>
</PropertyGroup>
<ItemGroup>
**<CompileFile Include="SampleMSBuild.cs" />**
<DeleteFiles Include="SampleMSBuild.exe;SampleMSBuild.pdb" />
</ItemGroup>
<Target Name="Clean">
...
</Target>
<Target Name="Build" DependsOnTarget="Clean">
**<Csc Sources="#(CompileFiles)"**
OutputAssembly="$(OutputFile)"
EmitDebugInformation="$(Debug)" />
<Target Name="Deploy">
...
</Target>
<Target Name="Execute">
...
</Target>
</Project>
My confusion arises from the two lines of code I've surrounded in asterisks. Although I now know how to build a project with a single source file, I am unsure how to scale that up to a WPF project where there is a predefined template with many source files that are placed in different directories. Is it simply a matter of including every source file in the project like so
...
<CompileFile Include="source1.cs;source2.cs;source3.cs;...;sourceN.cs"
...
What about files in a project that are NOT source code? For example, files found in the References folder of a WPF project. I can't imagine all these are to be compiled as well. Does the complied source code communicate with the rest of the uncompiled files in the project? What exactly is the relationship between source files and other non-source files when it comes to build automation in MSBuild?

dotnet publish profile ignores pubxml file

I have the following pubxml file which I created via Visual Studio 2019:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>FileSystem</WebPublishMethod>
<PublishProvider>FileSystem</PublishProvider>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ProjectGuid>143a6329-27d9-474e-9521-835be634c293</ProjectGuid>
<SelfContained>true</SelfContained>
<publishUrl>bin\Release\netcoreapp3.1\publish\</publishUrl>
<DeleteExistingFiles>True</DeleteExistingFiles>
</PropertyGroup>
</Project>
When I run dotnet.exe publish src\MyProject.Web.sln -p:PublishProfile=Properties\PublishProfiles\ProductionPublish.pubxml Release does not contain anything and publish happens on Debug folder (debug build). Whys does this happens and pubxml is ignored?
Update #1
Structure
src\MyProject\MyProject.csproj
src\MyProject.Utils\ect.Utils.csproj
src\MyProject.Web\MyProject.Web.csproj
src\MyProject.Web.sln
and the path of the pubxml
src\MyProject.Web\Properties\PublishProfiles\ProductionPublish.pubxml
You need the use following command:
dotnet build -c Release /p:DeployOnBuild=true /p:PublishProfile=FolderProfile
It's build, not publish.
Even if my FolderProfile's configuration is set to Release, I had to
include -c Release because otherwise dependent projects were built
with debug configuration.
Files not copied to target location if called without /p:DeployOnBuild=true.
Just the name FolderProfile -without extension- is enough for the
profile file. Or you can give the path
/p:PublishProfile=Properties\PublishProfiles\FolderProfile.pubxml
See Folder publish example from Microsoft Docs.
Found a solution on VS2022 and Core 6 to publish to an specific folder without indicating the output path on the CLI.
I created a profile called IISC
If you open that publish profile, you will see the PublishUrl property as follows
<PublishUrl>bin\Release\net6.0\publish\IISC</PublishUrl>
In My case I'm publishing to the solution folder bin\releas....\IISC
The trick is to add another propery called PublishDir
<PublishDir>bin\Release\net6.0\publish\IISC</PublishDir>
Now you can publish with this:
dotnet publish -c Release /p:PublishProfile=IISC
Find Bellow My complete Profile with and addition of an environment variable specific for this profile and and item group to exclude all the appsettings except for appsettings.json and appsettings.IISC.json
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<ASPNETCORE_ENVIRONMENT>iisc</ASPNETCORE_ENVIRONMENT>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\net6.0\publish\IISC</PublishUrl>
<PublishDir>bin\Release\net6.0\publish\IISC</PublishDir>
<WebPublishMethod>FileSystem</WebPublishMethod>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net6.0</TargetFramework>
<ProjectGuid>3e4c25a6-2051-4ccc-a518-645d46d120dd</ProjectGuid>
<SelfContained>false</SelfContained>
</PropertyGroup>
<ItemGroup>
<Content Update="appsettings.*.json">
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</Content>
<Content Update="appsettings.$(ASPNETCORE_ENVIRONMENT).json">
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\PublishProfiles\" />
</ItemGroup>
</Project>
I'm gonna answer for those who, like me, do want to use the publish command, because it's been designed to do so.
According to Options section on publish command, you can use the options configuration and output to solve your problem:
dotnet publish -c Release -o "<where you want>" -p:PublishProfile=<your profile name>
Note that where you want can be an absolute path and your profile name is only the name of profile, without "pubxml" and without the relative path (IF AND ONLY IF the profile is in "<project_folder>/Properties/PublishProfiles").

Importing the file 'xxx.targets' results in a circular dependency

I have a NuGet package called "Contoso.Library" with a targets file: "/build/Contoso.Library.targets"
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0" />
</ItemGroup>
</Project>
However, when I try and build a project containing this I get the following error:
Importing the file "C:\Program Files\dotnet\sdk\2.1.2\Sdks\Microsoft.NET.Sdk\Sdk\Sdk.targets" into the file "C:\Users\rb.nuget\packages\contoso.library\1.0.0\build\contoso.library.targets" results in a circular dependency. C:\Users\rb.nuget\packages\contoso.library\1.0.0\build\contoso.library.targets
I have confirmed that if I rename the targets file to "contoso.library.targets.xxx" this error goes away, demonstrating that the targets file is where the problem lies.
For reference, here is the project file of the project consuming Contoso.Library:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net46</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Contoso.Library" Version="1.0" />
</ItemGroup>
</Project>
Turns out the answer is actually really simple - just drop the "Sdk" attribute from the Project element in the targets file:
<Project Sdk="Microsoft.NET.Sdk">
becomes
<Project>
The same error and the same solution (thanks #RB. !), but I was using Directory.Build.props file instead of a targets file.
My error:
Importing the file "C:\Program
Files\dotnet\sdk\3.1.401\Sdks\Microsoft.NET.Sdk\Sdk\Sdk.props" into
the file "<snip>\Directory.Build.props" results in a circular
dependency
Exact solution:
I removed the Sdk="Microsoft.NET.Sdk" attribute from the Directory.Build.props and the projects rebuild correctly.
HTH!

MSbuild and multiple projects with same class library references

I have a solution file with a class library and a couple of windows services. All the services have a project reference to the class library.
In my build file I'm building each service in release mode, zipping the files and copying the zip files to a webserver where our production servers can download the zip files from.
The problem is that only the first services is built and deployed. All others fail with a CSC : error CS0006: Metadata file "classlibrary.dll" could not be found.
I've made a test solution that reproduces the problem. One empty class library, and two empty console applications, both with references to the class library.
Is it because the temp directory is the same? It works fine with web projects and the same temp directory.
And then this build file.
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildCommunityTasksPath>$(MSBuildProjectDirectory)\Tools\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
</PropertyGroup>
<Import Project="Tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<PropertyGroup>
<ExtensionTasksPath>$(MSBuildProjectDirectory)\Tools\MSBuild.ExtensionPack\</ExtensionTasksPath>
</PropertyGroup>
<Import Project="Tools\MSBuild.ExtensionPack\MSBuild.ExtensionPack.tasks" />
<PropertyGroup>
<ProjectName>MSbuild test</ProjectName>
</PropertyGroup>
<Target Name="DeployAll" >
<Message Text="DeploymentPackage $(ProjectName)" />
<PropertyGroup>
<TempDeploymentDirectory>$(MSBuildProjectDirectory)\DeploymentPackage\</TempDeploymentDirectory>
<ProjectFile1>ConsoleApplication1\ConsoleApplication1.csproj</ProjectFile1>
<ProjectFile2>ConsoleApplication2\ConsoleApplication2.csproj</ProjectFile2>
</PropertyGroup>
<RemoveDir Directories="$(TempDeploymentDirectory)" />
<MSBuild Projects="$(ProjectFile1)" Properties="Configuration=Release;OutDir=$(TempDeploymentDirectory)" Targets="Clean;Build"/>
<!-- Zipping copying files removed for readability -->
<RemoveDir Directories="$(TempDeploymentDirectory)" />
<MSBuild Projects="$(ProjectFile2)" Properties="Configuration=Release;OutDir=$(TempDeploymentDirectory)" Targets="Clean;Build"/>
</Target>
</Project>
Building the classLibrary before each application worked for the demo project, but not for the real project.
The solution in my project, was to use a different output directory for each service.

Categories

Resources