如何使用VS2010 Web部署包包含其他文件?

130

我正在测试使用Visual Studio 2010中的新Web打包功能,并遇到这样一种情况:我使用预构建事件将需要的.dll文件复制到我的bin文件夹中,以便我的应用程序可以调用API。由于它们不是可以与互操作使用的COM dll,因此不能作为引用包含。

当我构建我的部署包时,如果我选择仅包括运行应用所需的文件选项,这些文件将被排除在外。是否有一种方法来配置部署设置以包括这些文件?我尝试寻找相关文档,但没有找到任何有用的资料。

7个回答

177

很好的问题。我刚刚在Web部署工具(MSDeploy):构建包,包括额外文件或排除特定文件发布了一篇非常详细的博客文章。

以下是概要。在包含文件后,我还展示了如何排除文件。

包含额外文件

将额外文件包含进包中有点难,但如果您熟悉MSBuild并且不介意阅读本文,那么也没什么大不了的。为此,我们需要接入收集打包文件的过程的部分。我们需要扩展的目标称为CopyAllFilesToSingleFolder。该目标具有一个依赖属性PipelinePreDeployCopyAllFilesToOneFolderDependsOn,我们可以针对该属性进行注入并注入自己的目标。因此,我们创建一个名为CustomCollectFiles的目标并将其注入到该过程中。我们使用以下代码来实现这一目标(请记住在导入语句之后)。

<PropertyGroup>
  <CopyAllFilesToSingleFolderForPackageDependsOn>
    CustomCollectFiles;
    $(CopyAllFilesToSingleFolderForPackageDependsOn);
  </CopyAllFilesToSingleFolderForPackageDependsOn>

  <CopyAllFilesToSingleFolderForMsdeployDependsOn>
    CustomCollectFiles;
    $(CopyAllFilesToSingleFolderForMsdeployDependsOn);
  </CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>

这将把我们的目标添加到进程中,现在我们需要定义目标本身。假设您有一个名为Extra Files的文件夹,它位于您的Web项目的上一级。您想包含所有这些文件。这是CustomCollectFiles目标,我们在此之后进行讨论。

<Target Name="CustomCollectFiles">
  <ItemGroup>
    <_CustomFiles Include="..\Extra Files\**\*" />

    <FilesForPackagingFromProject  Include="%(_CustomFiles.Identity)">
      <DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
    </FilesForPackagingFromProject>
  </ItemGroup>
</Target>

这里我创建了一个名为_CustomFiles的项,并在Include属性中告诉它选择该文件夹及其下面的所有文件夹中的所有文件。如果您需要从该列表中排除某些内容,则可以向_CustomFiles添加一个Exclude属性。

然后,我使用此项来填充FilesForPackagingFromProject项。这是MSDeploy实际用于添加额外文件的项。还要注意我声明了DestintationRelativePath值的元数据。这将决定将其放置在包中的相对路径。我在这里使用了语句Extra Files%(RecursiveDir)%(Filename)%(Extension)。它表示将其放置在与Extra Files文件夹下相同的相对位置中。

排除文件

如果打开使用VS 2010创建的Web应用程序的项目文件,您会在底部找到一行代码。

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

顺便提一下,你可以在VS中打开项目文件。右键单击项目选择卸载项目。然后右键单击已卸载的项目并选择编辑项目。

这个语句将包括我们需要的所有目标和任务。大多数自定义应该在导入之后进行,如果不确定,请在之后再进行!因此,如果您有要排除的文件,则可以使用ExcludeFromPackageFiles项目名称来排除它们。例如,假设您有一个名为Sample.Debug.xml的文件包含在您的Web应用程序中,但是您希望将该文件从创建的包中排除。您可以在导入语句之后放置下面的代码段。

<ItemGroup>
  <ExcludeFromPackageFiles Include="Sample.Debug.xml">
    <FromTarget>Project</FromTarget>
  </ExcludeFromPackageFiles>
</ItemGroup>

通过声明填充此项,文件将自动被排除。请注意此处使用了FromTarget元数据的用法。我不会在这里深入讨论,但您应该知道始终要指定它。


3
请问您能否举一个更加详细的例子,以便将其他项目产出物纳入发布范围? - Anthony Serdyukov
7
我安装了VS2012(RC),对我来说有一个不同的DependencyProperty。为了支持混合团队(和我们的构建服务器),我有原始的CopyAllFilesToSingleFolderForPackageDependsOn配置以及一个使用DependencyProperty CopyAllFilesToSingleFolderForMsdeployDependsOn的副本。 - Emil Lerch
2
这太棒了。可以使用它来部署存储在txt文件中的某些版本信息。 - lamarant
5
这对我似乎没有用。我正在使用VStudio 2013。:( 上面的msbuild设置适用于2013吗? - irperez
8
@SayedIbrahimHashimi 和他的团队在 asp.net 网站上创建了一份更加更新的指南,详细介绍了如何部署额外的文件。我强烈推荐这个链接,因为这是让我避免修改 csproj 文件而使用 pubxml 文件的关键所在。 - Adam Venezia
显示剩余13条评论

22

一种更简单的解决方案是编辑csproj文件,将所需的dll包含在bin文件夹中,然后创建一个beforebuild目标,从我们存储第三方dll的公共库文件夹中将该项目复制到bin文件夹中。因为该项目存在于解决方案文件中,所以它将被msbuild/msdeploy部署,并且不需要任何复杂操作。

用于包含文件而无需通过VS添加(通常会将其添加到您的版本控制系统中)的标记。

<Content Include="Bin\3rdPartyNative.dll" ><Visible>false</Visible></Content>

这是我使用的BeforeBuild目标:

<Target Name="BeforeBuild">
    <Message Text="Copy $(SolutionDir)Library\3rdPartyNative.dll to '$(TargetDir)'3rdPartyNative.dll" Importance="high" />
    <Copy SourceFiles="$(SolutionDir)Library\3rdPartyNative.dll" DestinationFiles="$(TargetDir)3rdPartyNative.dll" />
</Target>

编辑后包括 @tuespetre 的建议,隐藏条目,从而消除先前可见的 bin 文件夹的缺点。未经我验证。


3
简洁是至臻的优雅。 - BornToCode
1
这在许多情况下都有效,但如果您有需要包含在 bin 文件夹之外的文件,则无法正常工作。 - Nathan
@Nathan 这是一个复制品,你可以从任何你有读写权限的地方包含它。 - toxaq
5
@toxaq,我可能漏掉了一些东西,但我遇到的问题是,我实际上需要文件位于部署包中不在 bin 文件夹中的位置。 因此,是的,您可以将文件从任何地方复制到bin文件夹中,但在这种情况下,它们不会包含在部署包的正确位置。 就我所知,我遇到的情况是与ClearScript.V8项目有关 - 本机.dll文件不得出现在bin目录中,而必须出现在其父目录中 - 请参见http://clearscript.codeplex.com/discussions/438696进行讨论。 - Nathan
1
@Tohid 谢谢,我已经进行了编辑。由于我没有任何微软的东西可以测试,所以我还没有验证它。 - toxaq
显示剩余2条评论

8

所以Sayed的实现对我不起作用。我正在使用VS2013并使用Web Deploy包,并需要将另一个文件夹中的一些插件DLL添加到部署包的bin中。以下是我成功实现的方法(更简单):

在csproj文件底部添加:

<Target Name="AdditionalFilesForPackage" AfterTargets="CopyAllFilesToSingleFolderForMsdeploy">
    <ItemGroup> 
        <Files Include="..\SomeOtherProject\bin\$(Configuration)\*.*"/>
    </ItemGroup>
    <Copy SourceFiles="@(Files)" DestinationFolder="$(_PackageTempDir)\bin\" />  
</Target>

csproj文件中的其他值得注意的内容:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <DeployOnBuild>true</DeployOnBuild>
    <DeployTarget>Package</DeployTarget>
    <DeployIisAppPath>Default Web Site/MyWebsite</DeployIisAppPath>
    <DesktopBuildPackageLocation>..\output\Service\Service\Service.Release.zip</DesktopBuildPackageLocation>
    <FilesToIncludeForPublish>OnlyFilesToRunTheApp</FilesToIncludeForPublish>
    <ExcludeGeneratedDebugSymbol>true</ExcludeGeneratedDebugSymbol>
    <PublishDatabases>false</PublishDatabases>
</PropertyGroup>

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0\WebApplications\Microsoft.WebApplication.targets" />

谢谢。我正在使用VS2015,我还需要添加另一个项目bin文件夹中的DLLS。您的解决方案是最简单的,并且完美地工作。 - Rafael

7
与@toxaq类似的方法,但更简单的解决方案是:
在解决方案资源管理器中将该文件作为链接添加到库/引用文件夹中,然后在属性中设置它在构建输出时被复制。

4
这意味着该项目希望在链接时明确确定关系。对于插件类型的系统不适用。 - user585968

5

想要评论以强调Emil Lerch上面的评论。如果您已安装Azure SDK,则需要查找不同的DependencyProperty。

基本上,您可能需要使用“CopyAllFilesToSingleFolderForMsdeployDependsOn”而不是“CopyAllFilesToSingleFolderForPackageDependsOn”。我不是一个高级的MsBuild人员,我浪费了几个小时的时间,试图确定为什么我的目标没有被调用。

如果这对您不起作用并且您已安装Azure SDK,则这是另一个链接: http://forums.iis.net/t/1190714.aspx


3
作为Sayed答案的补充,我发现在我的项目中静态声明ExcludeFromPackageFiles项是不够的。我需要排除某些DLL,这些DLL只有在编译后才可用(Azure特定的Ninject模块,在部署到IIS时不需要)。因此,我尝试使用Sayed上面发布的CopyAllFilesToSingleFolderForPackageDependsOn技巧来生成我的ExcludeFromPackageFiles列表。然而,这太晚了,因为打包过程已经移除了ExcludeFromPackageFiles项。所以,我使用了同样的技术,但稍早一点:
<PropertyGroup>
    <ExcludeFilesFromPackageDependsOn>
        $(ExcludeFilesFromPackageDependsOn);
        _ExcludeAzureDlls
    </ExcludeFilesFromPackageDependsOn>
</PropertyGroup>

<Target Name="_ExcludeAzureDlls">
    <ItemGroup>
        <FilesForPackagingFromProjectWithNoAzure Include="@(FilesForPackagingFromProject)"
                               Exclude="%(RootDir)%(Directory)*Azure*.dll" />
        <AzureFiles Include="@(FilesForPackagingFromProject)"
                    Exclude="@(FilesForPackagingFromProjectWithNoAzure)" />
        <ExcludeFromPackageFiles Include="@(AzureFiles)">
            <FromTarget>_ExcludeAzureEnvironmentDlls</FromTarget>
        </ExcludeFromPackageFiles>
    </ItemGroup>
</Target>

希望这对某些人有所帮助...

1
此外,可以将文件设置为“内容|始终复制”。

Also, it is possible to set the file as Content | Copy always


1
似乎这应该是最容易和最明显的答案,因此应该是最佳答案。 - J Miglietta
但仅当它是项目的一部分时才可用。否则此选项不可用。 - General Grievance

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接