只需添加有关I want the heuristic back
的一些详细信息即可。
1.Hmm,刚刚进行了一些测试,并确认您的Edit1
是正确的。
我们可以简单地在本地计算机上重现相同的问题,而无需使用共享文件夹。如果我们在导入的目标中使用$(OutDir)
,则由于VS始终会寻找$(OutputPath)
,因此会影响正常的构建行为。 (同意您的Edit1,这应该是一个很好的答案!)
2。要解决此问题,我们必须避免使用$(OutDir)
指定最终输出路径。因此,我们可以使用$(OutputPath)
吗,很遗憾否!
项目文件中的$(OutputPath)
将始终覆盖导入的$(OutputPath)
文件中定义的同名xx.targets
。请参见this:如果项目包含与环境属性同名的属性定义,则项目中的属性将覆盖环境变量的值。。
我能想象的唯一可能的方法是在$(CustomPath)
文件中定义xx.targets
(代表共享文件夹),然后将OutputPath
中的所有xx.csproj
属性修改为<OutputPath>$(CustomPath)\$(Configuration)</OutputPath>
。那可能是一件无聊的工作,因为您有将近100个项目文件:(
我认为除非我们放弃共享文件夹方式,否则很难避免无聊的工作。这个答案有点否定,但希望能对您有所帮助...
,
这是二进制日志无用的罕见情况之一,因为它是由msbuild生成的,即为时已晚。必须先在Visual Studio中打开诊断构建,因为诊断的第一行来自启发式。它指定了构建项目的原因。所有其他诊断日志都可以丢弃,但是第一行是无价的。它已将我引导至以下解决方案:
启用启发式
我在从每个项目导入的目标文件中添加了以下目标。那些不关心与MSBuild 14向后兼容的人可以将其添加到Directory.Build.Targets:
*我们最终选择了另一种方式-请参阅编辑2 *
<Target Name="SatisfyVisualStudioFastUpToDateCheckHeuristic" AfterTargets="AfterBuild" Condition="'$(OutDir)' != '' And '$(GatedCheckIn)' != True">
<ItemGroup>
<Files Include="$(TargetFileName).config" Condition="'$(AppConfig)' != '' And Exists('$(AppConfig)')" />
<Files Include="$(TargetName).pdb" />
<Files Include="$(TargetName)$(TargetExt)" />
<Files Include="@(IntermediateAssembly->'%(Filename)%(Extension)')" />
<Files Include="$(_SGenDllName)" Condition="'$(_SGenDllCreated)'=='true'" />
<Files Include="@(ReferenceCopyLocalPaths->'%(DestinationSubDirectory)%(Filename)%(Extension)')" />
<Files Include="@(_SourceItemsToCopyToOutputDirectory->'%(TargetPath)')" />
</ItemGroup>
<MakeDir Directories="$(OutputPath)\%(Files.RelativeDir)" />
<Touch Files="@(Files->'$(OutputPath)%(Identity)')" AlwaysCreate="true" ContinueOnError="true"/>
</Target>
<Target Name="CleanFakeOutputFiles" AfterTargets="AfterClean" Condition="'$(OutDir)' != '' And '$(GatedCheckIn)' != True">
<RemoveDir Directories="$(OutputPath)" />
</Target>
此目标在启发式程序预期的位置创建零长度的伪代理输出文件。
后续操作1
如果某人的某个项目将其他项目引用为DLL而不是项目引用,则这样做实际上可能会使构建失败。例如,如果项目Alice像这样引用项目Bob:
<Reference Include="Bob,Version=1.0.0.0,Culture=neutral,PublicKeyToken=...,processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Bob\bin\$(Configuration)\Bob.dll</HintPath>
</Reference>
问题出在HintPath
上。当我们使用共享的bin进行构建且没有伪造的代理输出时,HintPath
将被忽略,因为它不会导致任何现有文件。因此,将在共享bin目录中找到Bob.dll并从那里加载它。但是,当bin\$(Configuration)
中存在伪造文件以满足启发式要求时,HintPath
返回一个现有文件,因此对Bob.dll的搜索以零长度伪造结束。显然,编译将失败。解决方法是将其更改为相应的项目参考,或者消除所有元数据的HintPath
:
<Reference Include="Bob" />
必须引用Bob.dll,就像我们引用GAC中的系统依赖项一样。
后续操作2
在这一点上,代码应该构建并且启发式工作。除非有时会告诉它找不到某种依赖性,例如System.IO.dll
。在这种情况下,必须检查以下两个条件是否成立:
- 项目从某个目录(例如NuGet包)引用
System.IO.dll
。
-
System.IO.dll
在GAC中找到,更适合目标框架。
在我的情况下,我有多个项目引用了NuGet的System.IO*
,System.Runtime*
,System.Security*
和System.ValueTuple
,而这些dll由于具有.NET 4.7而存在于GAC中.2系统上的运行时。启发式方法会在HintPath
中查找这些引用,并期望在bin\$(Configuration)
文件夹中找到它们。
但是,该构建实际上是从GAC中获取它们的,并且从GAC引用的dll默认情况下不会复制到目标bin。因此,没有伪造的替代品可以满足启发式方法。
我的解决方案是用GAC的相应引用替换所有这些NuGet引用。
编辑1
问题1
后续操作1 的副作用是,不再容易返回本地bin文件夹,因为对项目dll引用的更改不向后兼容。
可以保留HintPath
元数据,但是所有元数据都必须指向共享bin目录,在这种情况下,它仍然与旧方法不兼容。
问题2
每次加载Web应用程序项目时,Visual Studio都会覆盖.vs\config\applicationhost.config
。意思是:
这是一个大麻烦,因为共享bin方法的一部分是通过脚本更新.vs\config\applicationhost.config
中的路径。但是VS的这种行为使其成为一个主要的麻烦。
编辑2
我们已经更改了启用启发式的方式。我们不会执行VS期望的伪造文件,而是执行以下操作:
- 在构建的早期生成一个结点 bin.link-> bin
- 在启发式隐藏的目标文件中设置 OutDir = bin.link
- 使用 OutputPath = bin
修改了所有项目
通过这种方式,启发式方法可以看到正确的位置(OutputPath),但同时 OutputPath!= OutDir ,因此发布代码可以正常工作。
因此,不再需要零长度的垃圾文件。
对于VS覆盖.vs \ config \ applicationhost.config的情况-我们为此创建了一个自定义VS扩展名。
本文链接:https://www.f2er.com/3154699.html