.netazure-devopsmultitargeting

Can't multi-target projects in azure pipeline build


I have a project which is targeting both net472 and netstandard2.0 and this has conditional package references and conditional code.

If I compile this locally completes with no errors and also if I compile the solution via msbuild. However when I compile with msbuild task in azure build pipeline it throw errors like:

##[error]tests\Project.Tests\RiskUi\RiskUiProviderTests.cs(21,17): Error CS0246: The type or namespace name 'RiskUiProvider' could not be found (are you missing a using directive or an assembly reference?) My problem is like this link: https://github.com/dotnet/msbuild/issues/4435 The class RiskUiProvider is under a directive #if NET472 public class RiskUiProvider {} #endif it belongs to a project that is multitargeting <TargetFrameworks>net472;netstandard2.0</TargetFrameworks> and the unit test which is net472 is throwing this error as if he doesn't read under the directive.

Has anyone else had/solved this same issue?

I added the reference of the multitargeting project like this:

<ProjectReference Include="..\Project.Standard\Project.Standard.csproj">
    <AdditionalProperties>TargetFramework=net472</AdditionalProperties>
    <Name>Project.Standard</Name>
</ProjectReference>

but it is like in azure pipeline he can"t read directives (#if NET472) and the strange that in local it all works and it is running

yaml file

- task: MSBuild@1
  displayName: 'Build solution All.sln'
  inputs:
    solution: All.sln
    msbuildArchitecture: x64
    platform: '$(BuildPlatform)'
    configuration: '$(BuildConfiguration)'
    msbuildArguments: '/p:OutDir=$(Build.ArtifactStagingDirectory) /p:AutoGenerateBindingRedirects=true /p:GeneratePackageOnBuild=True /p:GenerateProjectSpecificOutputFolder=True /p:PackageOutputPath=$(Build.ArtifactStagingDirectory)\NuGet /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg /target:Build '
    clean: true

- task: VSTest@3
  displayName: 'Test Assemblies'
  inputs:
    testAssemblyVer2: |
     **\Project.UnitTests\Project.UnitTests.dll
    
    searchFolder: '$(Build.ArtifactStagingDirectory)\TU'
    testFiltercriteria: 'TestCategory=UnitTest & TestCategory!=Slow & TestCategory!=PerfNonRegTest'
    runInParallel: false
    codeCoverageEnabled: false
    otherConsoleOptions: '/Platform:$(BuildPlatform) /Framework:.NETFramework,Version=v4.7.2'
    platform: '$(BuildPlatform)'
    configuration: '$(BuildConfiguration)'
  condition: and(succeeded(), eq(variables['DisableUnitTests'], 'false'))
  timeoutInMinutes: 30```

The csproj of test

<Project Sdk="Microsoft.NET.Sdk">   <PropertyGroup>
    <ProjectGuid>{48F901E6-F500-477A-B03C-4B6B2E8E362C}</ProjectGuid>
    <TargetFramework>net472</TargetFramework>
    <SccProjectName></SccProjectName>
    <SccLocalPath></SccLocalPath>
    <SccAuxPath></SccAuxPath>
    <SccProvider></SccProvider>
    <AssemblyTitle>LtCore.Tests</AssemblyTitle>
    <Product>LtCore.Tests</Product>
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
    <ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType> </PropertyGroup>   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugType>full</DebugType>   </PropertyGroup>   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>   </PropertyGroup>   <ItemGroup>
    <PackageReference Include="log4net" Version="2.0.15" />
    <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.8" />
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageReference Include="NFluent" Version="2.8.0" />
    <PackageReference Include="NSubstitute" Version="4.4.0" />
    <PackageReference Include="NUnit" Version="3.13.3" />
    <PackageReference Include="System.Text.Json" Version="8.0.5" />   </ItemGroup>   <ItemGroup>
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Net.Http" />   </ItemGroup>   <ItemGroup>
  
    <ProjectReference Include="..\..\src\Project.Standard\Project.Standard.csproj">
      <AdditionalProperties>TargetFramework=net472</AdditionalProperties>
    </ProjectReference>   </ItemGroup>   <ItemGroup>

    <Content Include="log4net.config">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>   </ItemGroup> </Project>


Solution

  • Testing from my side, the pipeline works as expected. Share the projects and yaml file for your reference.

    1. My MultiTargetingLibrary.csproj
    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
      </PropertyGroup>
    
      <PropertyGroup Condition="'$(TargetFramework)' == 'net472'">
        <DefineConstants>NET472</DefineConstants>
      </PropertyGroup>
    
    </Project>
    
    1. RiskUiProvider.cs in project MultiTargetingLibrary
    #if NET472
    public class RiskUiProvider
    {
        ...
    }
    #endif
    
    
    1. My MultiTargetingLibrary.Tests.csproj
    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>net472</TargetFramework>
    
        <IsPackable>false</IsPackable>
        <IsTestProject>true</IsTestProject>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="coverlet.collector" Version="6.0.0" />
        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
        <PackageReference Include="xunit" Version="2.5.3" />
        <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
      </ItemGroup>
    
      <ItemGroup>
        <ProjectReference Include="..\MultiTargetingLibrary\MultiTargetingLibrary.csproj" />
      </ItemGroup>
    
      <ItemGroup>
        <Using Include="Xunit" />
      </ItemGroup>
    
    </Project>
    
    1. My YAML file of the build pipeline
    pool:
      vmImage: 'windows-latest'
    
    variables:
      buildConfiguration: 'Release'
      solution: '**/*.sln'
      buildPlatform: 'Any CPU'
    
    steps:
    - task: UseDotNet@2
      inputs:
        packageType: 'sdk'
        version: '5.x' # Adjust based on your .NET SDK version
    
    - task: NuGetToolInstaller@1
    
    - task: NuGetCommand@2
      inputs:
        restoreSolution: '$(solution)'
    - task: MSBuild@1
      inputs:
        solution: '$(solution)'
        platform: '$(buildPlatform)'
        configuration: '$(buildConfiguration)'
    
    - task: VSTest@2
      inputs:
        platform: '$(buildPlatform)'
        configuration: '$(buildConfiguration)'
    

    Update:

    Root cause:

    When you use /p:OutDir=$(Build.ArtifactStagingDirectory) in msbuildArguments, the subfolder obj\Release\netstandard2.0 and obj\Release\net472 will not be created in the artifact directory, so that the dll for net472 is override by netstandard2.0.

    Solution:

    Add the following to test project.

    <ProjectName>$(AssemblyName).$(TargetFramework)</ProjectName> 
    <PackageOutputPath>$(OutDir)</PackageOutputPath>