【问题标题】:Build configuration for dynamically referenced projects为动态引用的项目构建配置
【发布时间】:2016-09-23 17:31:30
【问题描述】:

我有一个包含在多个解决方案中的 ASP.NET 项目。在每个解决方案中,我希望在 ASP.NET 项目的构建输出中包含一个不同的 unreferenced 项目。解决方案如下所示:

  • Foo.sln

    • WebApp.csproj
    • Foo.csproj
  • Bar.sln

    • WebApp.csproj
    • Bar.csproj

理想情况下,即使在使用 F5 进行调试时也能正常工作。我尝试使用构建配置来执行此操作,但在 Visual Studio 中工作时,偏离典型的“调试”和“发布”似乎很脆弱。有没有这样做的典型方法?

【问题讨论】:

    标签: c# visual-studio visual-studio-2015 msbuild


    【解决方案1】:

    免责声明:我认为这不是一个好主意,但似乎可以做到。

    为了测试这个解决方案,我创建了两个项目。 ConsoleApplication1 和 ClassLibrary1。 ConsoleApplication1 没有对 ClassLibary1 的引用(在 Visual Studio 中可见),但是当从 Visual Studio 构建 ConsoleApplication1 时,它将构建然后将 ClassLibary1.dll 复制到 ConsoleApplication1 的 bin 文件夹中。

    要导入目标文件,您将继续将此行添加到要构建未引用项目的项目中。此路径将相对于当前项目,因此在我的情况下,目标文件位于我的解决方案的根目录。确保在 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 行之后添加它,因为 unreferenced.target 依赖于在 Microsoft.CSharp.targets 中设置的目标。

    <Import Project="..\unreferenced.target" />
    

    然后您将继续创建一个文件名 unreferenced.target 并将以下内容添加到文件中。

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     <!-- Start another msbuild task to build your unreferenced project -->
     <Target Name="BuildBeforeResolveReferences" BeforeTargets="BeforeResolveReferences">
        <MSBuild
          BuildInParallel="False"
          Projects="$(SolutionDir)ClassLibrary1\ClassLibrary1.csproj"
          RunEachTargetSeparately="True"
          StopOnFirstFailure="False"
          UnloadProjectsOnCompletion="False">
        </MSBuild>
      </Target>
    
      <Target Name="CopyUnreferencedProjectOutput" AfterTargets="Build">
        <!-- This item group is here because we do not want it evaluated by msbuild until the ClassLibrary1.csproj has been compiled and its output is in its output directory -->
        <ItemGroup>
          <!-- Gets a list of all files at the OutputPath that end in .dll if you need the pdbs remove the .dll -->
          <!-- To maintain folder structure in the bin folder use <SourceFiles Include="..\ClassLibary1\@(OutputPath)**\*.dll" /> the double ** is a recursive wild card and will look through all directorys -->
          <SourceFiles Include="$(MSBuildProjectDirectory)\..\ClassLibrary1\$(OutputPath)*.dll" />
        </ItemGroup>
    
        <!-- To make sure the copy maintains folder structure switch it to this copy -->
        <!-- <Copy SourceFiles="@(SourceFiles)" DestinationFiles="@(SourceFiles -> '$(MSBuildProjectDirectory)$(OutputPath)%(RecursiveDir)%(Filename)%(Extension)')" /> -->
        <Copy SourceFiles="@(SourceFiles)" DestinationFolder="$(MSBuildProjectDirectory)\$(OutputPath)" />
      </Target>
    
      <!-- Cleans up all the files when clean is called -->
      <Target Name="CleanUnreferenceProjectOutput" BeforeTargets="Clean">
        <ItemGroup>
        <!-- Removed the .dll from the end of this to clean up the pdbs  as well -->
          <SourceFiles Include="$(SolutionDir)\ClassLibrary1\$(OutputPath)*" />
          <SourceFiles Include="$(SolutionDir)\ConsoleApplication1\$(OutputPath)*.dll" />
        </ItemGroup>
    
        <Delete Files="@(SourceFiles)" />
      </Target>
    </Project>
    

    我认为这是可以做到的最好的。您可以将其扩展为包含未引用但您想要构建的项目列表,但对于此示例,我只是将其保留在一个列表中。

    编辑 2:在获得当前解决方案之前,我对在解决程序集之前将引用注入 ProjectReference 项目组进行了广泛的研究。可以这样做,但您必须将属性 BuildInVisualStudio 设置为 false,否则当在 Microsoft.Common.Current.targets 的 ResolveProjectReferences 目标中评估 msbuild 条件时,您将选择仅运行 GetManifest 目标的 MSBuild 任务。我能够构建解决方案,但由于我对将 BuildInVisualStudio 设置为 false 的内容缺乏了解,因此我选择了上述解决方案。我还添加了一个任务来清理移动到 bin 文件夹中的文件,因为 clean 只会清理项目 obj 文件夹中的 {ProjectName}{ProjectExtension}FileListAbsoluteText.txt。

    编辑:在对下面的解决方案进行更多研究之后,它只能从命令行工作。我目前正在调查为什么会发生这种情况。

    【讨论】:

      【解决方案2】:

      我不知道是否有一种典型的方式来满足您的要求(来自 IDE),但您可以选择通过编辑 *.*proj 文件手动完成此操作。

      每个项目都会发出输出(*.dll、*.exe、app.config 等),并将其复制到 $(OutputPath) 属性中指定的文件夹(在内部它将使用 OutDir 属性)。如果您要构建解决方案,您将拥有 $(SolutionDir) 属性以及 $(SolutionName)。因此,您可以定义新的 msbuild 项目,该项目将被其他项目引用,并且您可以设置属性 $(OutputPath) 以便每个输出都进入一个文件夹(我们称之为 Common.props):

      <Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <PropertyGroup>
          <SolutionDir Condition=" '$(SolutionDir)' == '' ">$(MSBuildThisFileDirectory)<SolutionDir>
          <SolutionName Condition=" '$(SolutionName)' == '' " >DefaultSlnName</SolutionName>
          <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
          <OutputPath>$(SolutionDir)$(SolutionName)\bin\$(Configuration)</OutputPath>
        </PropertyGroup>
      </Project>
      

      之后,您应该通过其他项目导入该项目 - *.*proj(您应该指定正确的项目路径):

      <Import Project="..\Common.props"  Condition="Exists('..\Common.props')" />
      

      使用通用 $(OutputPath) 属性会将您的所有二进制文件放在一个文件夹中 - 这应该有助于解决您的任务。

      【讨论】:

      • 你是说正在构建的项目必须引用这个新项目?这并不能解决问题,因为正在构建的项目与这些依赖项无关。
      • 这是msbuild项目,不是普通的csharp项目。您不会添加ProjectReference 的引用,或者只是二进制Reference。您将导入一些常用属性,这些属性将根据构建的解决方案进行评估。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-20
      • 2018-09-07
      • 2017-11-29
      • 2016-02-18
      • 1970-01-01
      • 1970-01-01
      • 2013-12-30
      相关资源
      最近更新 更多