【问题标题】:How does VS 2017 build and test a mixed solution containing .Net CoreVS 2017如何构建和测试包含.Net Core的混合解决方案
【发布时间】:2017-08-03 22:55:40
【问题描述】:

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

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

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

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

MySolution.sln

  • FoundationClasses(x86、.Net Framework 4.5、csproj(旧版)
  • BusinessLogic (x86, .Net Framework 4.5, csproj (legcay)
    • 参考基础类
  • WebApi(Dotnet Core WebApi、net451、x86(运行时(win8-x86、win10-x86)
  • TestProject(Dotnet 核心、net451、x86)
    • 参考 WebApi

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

升级到 VS 2017 后,当我从 Visual Studio 构建和运行时,一切正常。 (Migrate 在引用基础项目时遇到了一些问题 - 但删除了这些,并在迁移后重新读取,然后一切都很好)

'dotnet restore mySolution.sln' 工作正常。它正确地恢复了 WebApi 和 TestProject 的包 - 与预览位相反,它是开箱即用的。我不得不摆弄恢复和片段文件。

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

如果我运行“dotnet msbuild MySolution.sln -f net452 -r win10-x86”,它就可以工作。

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

因此,对于构建和恢复,我可以在 CLI 和 VS 2017 中使用它。并且结果相同。

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

我可以很好地在 Visual Studio 测试资源管理器中运行测试。单元测试运行良好并且是绿色的。但是我启动 TestServer 的集成测试因 Microsoft.Extensions.DependencyInjection.Abstractions 1.0.0 和 1.1.0 的引用不匹配而失败。

因此,测试链中的某些内容需要 1.0.0 的程序集,但在调试目录中仅找到 1.1.0。

这可以通过程序集重定向来解决 - 但相当多的程序集似乎是错误/不匹配的。

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

如此突出的问题:

  • “dotnet msbuild”是构建混合解决方案的正确方法吗?
  • 如果我在不使用 --no-build 的情况下运行“dotnet test”,则编译失败 - 出现与“dotnet build”类似的错误(不是 msbuild)
  • 我的测试中存在哪些不一致之处 - 如何在 VS 中执行与 CLI 相同的操作(最好弄清楚 VS 2017 中需要 1.0.0 范围内的程序集的内容)

我希望我能够彻底解释(但又足够简单易懂)。

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

最好的问候 安德斯

【问题讨论】:

    标签: .net-core visual-studio-2017 xunit.net asp.net-core-webapi


    【解决方案1】:

    好的,经过几个小时的努力思考/挖掘,我想我找到了正确的解决方案。

    将在此处发布以供参考。

    对 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 Studio 2017 使用安装文件夹中的 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\15.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 核心程序集的测试都失败了,因为“某些东西”引用了 v 1.0.0 版本的程序集 - 而我的项目引用了 v 1.1。 X。

    我已通过在 app.config 文件中为所有失败的程序集进行程序集重定向来解决此问题。无法弄清楚谁/什么使用了旧的 1.0.0 程序集 - 但 VS 2017 构建链中的某些东西似乎可以做到这一点 - 因为它适用于 dotnet 测试

    但是,这是我的 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 解决方案中运行的组合解决方案有效 - 我很高兴.. :-)

    【讨论】:

      猜你喜欢
      • 2018-12-18
      • 2022-07-14
      • 2019-04-22
      • 1970-01-01
      • 2016-10-24
      • 1970-01-01
      • 2019-06-23
      • 1970-01-01
      • 2018-06-22
      相关资源
      最近更新 更多