有许多文章(如this和this)展示了如何添加要发布的文件,他们都说要将这样的内容添加到发布配置文件(.pubxml):< / p>
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="..\Extra Files\**\*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
为什么需要新的_CustomFiles
项目?为什么不简单<FilesForPackagingFromProject Include="..\Extra Files\**\*">
?我尝试过,由于某种原因,这会导致项目中的每个文件都在已部署的Extra Files
文件夹中。有人能解释一下这种行为吗?
答案 0 :(得分:3)
由于您询问为什么这是必需的,因此我将深入了解此代码的含义,以解释您所看到的内容。 <Message />
是我们的朋友!
%
让我们首先在<Message>
任务中使用它来表示%的含义:
<ItemGroup>
<_CustomFiles Include="..\Extra Files\**\*" />
</ItemGroup>
<Message Text="File: %(_CustomFiles.Identity)" />
运行此操作时,您将获得以下输出:
File: ..\Extra Files\file1.txt
File: ..\Extra Files\file2.txt
File: ..\Extra Files\file3.txt
...
File: ..\Extra Files\etc.txt
基本上,Message
任务对项目组中的每个项目运行一次,因为我们使用%。
在我们对其进行任何更改之前,让我们先看一下该项目组。当此任务开始时,FilesForPackagingFromProject
已包含其中的所有文件,并具有各种元数据属性,包括DestinationRelativePath
。让我们通过将此添加到我们的任务来看到它:
<Message Text="File: %(FilesForPackagingFromProject.Identity) -> %(FilesForPackagingFromProject.DestinationRelativePath)" />
输出:
File: ..\obj\TempBuildDir\PrecompiledApp.config -> PrecompiledApp.config
File: ..\obj\TempBuildDir\Web.config -> Web.config
File: ..\obj\TempBuildDir\App_Themes\theme.css -> App_Themes\theme.css
...
重要的是要意识到这个项目组一开始并不是空的。您正在尝试添加项目。
当元素中的子元素具有%时,它们会对每次迭代应用一次,所以现在让我们看一下工作代码:
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<Message Text="File: %(FilesForPackagingFromProject.Identity) -> %(FilesForPackagingFromProject.DestinationRelativePath)" />
对于_CustomFiles
中的每个项目,我们将其包含在FilesForPackagingFromProject
项目组中,并将DestinationRelativePath
元数据属性设置为相应的 RecursiveDir
/ Filename
值 - 基本上是那些适用于当前正在查看的元素的值。让我们来看看这会产生什么:
File: ..\obj\TempBuildDir\PrecompiledApp.config -> PrecompiledApp.config
File: ..\obj\TempBuildDir\Web.config -> Web.config
File: ..\obj\TempBuildDir\App_Themes\theme.css -> App_Themes\theme.css
...
File: ..\Extra Files\file1.txt -> Extra Files\file1.txt
File: ..\Extra Files\file2.txt -> Extra Files\file2.txt
File: ..\Extra Files\file3.txt -> Extra Files\file3.txt
...
File: ..\Extra Files\etc.txt -> Extra Files\etc.txt
如果您只想包含一个文件,可以按照以下步骤操作:
<FilesForPackagingFromProject Include="..\Extra Files\file1.txt">
<DestinationRelativePath>Extra Files\file1.txt</DestinationRelativePath>
</FilesForPackagingFromProject>
这在任何地方都没有%
扩展,所以它完全符合您的预期:它在输出中包含一个文件。
现在让我们尝试包含一个文件,但不要对路径进行硬编码,而是使用原始代码中的%表达式:
<FilesForPackagingFromProject Include="..\Extra Files\file1.txt">
<DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<Message Text="File: %(FilesForPackagingFromProject.Identity) -> %(FilesForPackagingFromProject.DestinationRelativePath)" />
这里有%
因此事情得到了扩展,但由于项目组元素中没有%
,因此扩展的工作方式不同而且事情变得梨形:
File: ..\obj\TempBuildDir\PrecompiledApp.config -> PrecompiledApp.config
File: ..\obj\TempBuildDir\Web.config -> Web.config
File: ..\obj\TempBuildDir\App_Themes\theme.css -> App_Themes\theme.css
...
File: ..\Extra Files\file1.txt -> Extra Files\PrecompiledApp.config
File: ..\Extra Files\file1.txt -> Extra Files\Web.config
File: ..\Extra Files\file1.txt -> Extra Files\theme.css
因此,不是将file1.txt
添加到项目组,而是迭代整个集合,并为其中已有的每个文件添加file1.txt
一次。在此上下文中未设置RecursiveDir
,而Filename/Extension
是组中每个文件的原始文件名。
希望您现在可以看到这将为整个部署中的每个文件创建一个文件,但是在平面树中,特别是,内容将是file1.txt
而不是原始文件的内容。
当您包含通配符而不是一个文件时,对于通配符匹配的每个文件都会发生相同的事情。
坚持%(_CustomFiles)
修正。希望您现在能够了解它为什么必要以及它如何做到这一点。我相信这就是你应该这样做的方式:这里another question关于它,并给出了推荐这种方法的答案。