VS 2017如何构建和测试包含.Net Core的混合解决方案

How does VS 2017 build and test a mixed solution containing .Net Core

我有一个超过平均水平的复杂(我怀疑)解决方案,在升级到 dotnet sdk 1.1 和 Visual Studio 2017 后,我无法从命令行构建和测试它。

它一直在 VS 2015 中使用 dotnet sdk 1.0.0-preview2-003131,因此它在 VS 2015 和我们的构建服务器上的命令行中构建和运行。

但是我升级到VS 2017后遇到了一些问题。

概述设置。 我有一个大致如下所示的解决方案(现实生活中的更多项目)

MySolution.sln

在 VS 2015 中,这是通过在 Git 中存储 restore.dg 和 project.fragment.lock.json 来实现的,然后我可以 运行 dotnet restore,随后是 dotnet build,以及点网测试。

升级到 VS 2017 后,我从 Visual Studio 构建 运行 时一切正常。 (迁移对基础项目的引用有一些问题 - 但删除了那些,并在迁移后重新添加,然后一切都很好)

'dotnet restore mySolution.sln' 工作正常。它正确地恢复了 WebApi 和 TestProject 的包 - 与预览位相反,开箱即用。我必须 fiddle 恢复和分段文件。

但是,如果我 运行 'dotnet build MySolution.sln -f net452 -r win10-x86' 我会遇到一堆构建错误。

如果我 运行 'dotnet msbuild MySolution.sln -f net452 -r win10-x86' 它有效。

这是在概述的解决方案中从 CLI 工具构建的正确方法吗?

所以对于构建和恢复,我可以让它在 CLI 和 VS 2017 中工作。并且结果相同。

但是为了测试,一致性停止了。

我可以 运行 Visual Studio Test Explorer 中的测试就好了。单元测试 运行 很好并且是绿色的。但是我启动 TestServer 的集成测试因 Microsoft.Extensions.DependencyInjection.Abstractions 1.0.0 和 1.1.0 的引用不匹配而失败。

所以测试链中的某些东西需要程序集的 1.0.0,但在调试目录中只找到 1.1.0。

这可以通过程序集重定向来解决 - 但相当多的程序集似乎是 wrong/mismatched。

如果我 运行 'dotnet test --no-build TestProject/TestProject.csproj' 测试都是绿色的 - 没有问题。

所以悬而未决的问题:

我希望我能解释清楚(但足够简单易懂)。

如果需要更多信息来了解场景,请告诉我。

最好的问候 安德斯

好的,经过一些艰难的 thinking/digging 小时后,我想我找到了正确的解决方案。

将post这里供参考。

对 dotnet cli 问题的交叉引用:https://github.com/dotnet/cli/issues/6032

我有一个构建到 .Net 4.5 x86 的现有遗留解决方案,我们称之为 oldsolution.sln

我有一个新的解决方案,其中包含来自 oldsolution.sln 的一些项目,以及一些新的 dotnet 核心项目,我们称之为 mySolution.sln

新的解决方案还需要为 .Net 4.5 构建 x86

建筑

这里要把握的关键是Visual Studio2017是用安装文件夹里的一个msbuild.exe来搭建的。 dotnet msbuild 使用 dotnet sdk 文件夹中的程序集。而这些并不完全相同。

所以要像 Visual Studio 一样构建,我必须找到正确的 msbuild 可执行文件才能使用。

Visual Studio 团队为此开发了一个工具 (https://www.nuget.org/packages/vswhere),我在构建脚本中使用了该工具。

一切就绪。 (构建明智)

下面是我的 PSake 脚本,用于构建和测试解决方案。

Task BuildApi {
    exec { msbuild ./oldSolution.sln /t:Rebuild /p:Configuration="Release" /p:Platform=x86 /m /verbosity:minimal /nr:false }

    exec { dotnet restore .\mySolution.sln }

    #Find location of VS2017
    $VsPath = .\packages\vswhere.1.0.50\tools\vswhere.exe -latest -property installationPath
    $msBuild17 = "$vsPath\MSBuild.0\Bin\MSBuild.exe"

    exec { &$msbuild17 ./mySolution.sln /t:Build /p:Configuration=Release /p:Platform=x86 /m /verbosity:minimal /nr:false }
}

Task TestApi -depends BuildApi{
    if(!(Test-Path TestResults))
    {
    mkdir TestResults
    }
    if(!(Test-Path TestResults/coverage))
    {
    mkdir TestResults/coverage
    }

    $coverage = './packages/OpenCover.4.6.519/tools/OpenCover.Console.exe'
    $target = "`"C:\Program Files (x86)\dotnet\dotnet.exe`""
    $filter = "`"+[WebApi]*`""

    #UnitTests
    $targetargs = "`"test --no-build .\WebApi\test\WebApi.UnitTests\WebApi.UnitTests.csproj -c Release  --logger `"trx;LogFileName=UnitTests.trx`"`""
    $output = 'TestResults/coverage/WebApi.UnitTests.Coverage.xml'
    &$coverage -register:user -oldstyle -target:$target -targetargs:$targetargs -output:$output -filter:$filter

    # IntegrationTests
    $targetargs = "`"test --no-build .\Web\test\WebApi.IntegrationTests\WebApi.IntegrationTests.csproj c Release --logger `"trx;LogFileName=IntegrationTests.trx`"`""
    $output = 'TestResults/coverage/WebApi.IntegrationTests.Coverage.xml'
    &$coverage -register:user -oldstyle -target:$target -targetargs:$targetargs -output:$output -filter:$filter

    #Generate HTML report
    $reportGenerator = "./packages/ReportGenerator.2.4.5.0/tools/ReportGenerator.exe"
    $reportFiles = "TestResults/coverage/WebApi.UnitTests.Coverage.xml;TestResults/coverage/WebApi.IntegrationTests.Coverage.xml"
    $targetDir = "./TestResults/coverage/WebApi"
    &$reportGenerator -reports:$reportFiles -targetdir:$targetDir
}

到目前为止一切顺利。

测试

然后我在让 OpenCover 获取覆盖率结果时遇到了麻烦。

发现 XUnit 执行 shadowCopy - 修复是在每个测试项目中放置一个 xunit.runner.json (https://xunit.github.io/docs/configuring-with-json.html)

{
  "shadowCopy": false
}

告诉 XUnit 不要进行影子复制,这样 OpenCover 就可以找到与被测可执行文件匹配的 PDB 文件。

终于……

运行 在 Visual Studio 中进行测试,所有使用 Microsoft.AspNetCore.TestHost.TestServer 引用一些 dotnet 核心程序集的测试都失败了,因为 "something" 引用了 v 1.0.0 版本的程序集 - 我的项目引用了 v 1.1.x。

我已通过在 app.config 文件中为所有失败的程序集进行程序集重定向来解决此问题。没能弄清楚 who/what 使用了旧的 1.0.0 程序集 - 但 VS 2017 构建链中的某些东西似乎可以做到这一点 - 因为它与 dotnet test 一起工作。

但是,这是我的 app.config 的副本,在我的集成测试项目中放置了重定向。

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">"
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.AspNetCore.Mvc.Core" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.2.0" newVersion="1.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.Options" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.1.0" newVersion="1.1.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.AspNetCore.Http.Abstractions" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.1.0" newVersion="1.1.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.AspNetCore.StaticFiles" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.1.0" newVersion="1.1.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.FileProviders.Abstractions" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Extensions.Primitives" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.AspNetCore.Routing" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.1.0" newVersion="1.1.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.AspNetCore.Routing.Abstractions" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.1.0" newVersion="1.1.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.AspNetCore.Mvc.Formatters.Json" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.2.0" newVersion="1.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.AspNetCore.Mvc.ApiExplorer" culture="neutral" publicKeyToken="adb9793829ddae60" />
        <bindingRedirect oldVersion="0.0.0.0-1.1.2.0" newVersion="1.1.2.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

呼...那是一场激烈的战斗。

但物有所值。

与遗留 x86、net 4,5 程序集的组合解决方案,运行 在全新的 .Net Core Web Api 解决方案中工作 - 我很高兴.. :-)