【问题标题】:Why doesn't ClickOnce in Visual Studio deploy content files from dependent assemblies?为什么 Visual Studio 中的 ClickOnce 不从依赖程序集中部署内容文件?
【发布时间】:2009-02-26 11:55:19
【问题描述】:

我有一个通过单击部署的智能客户端应用程序。问题是我在依赖程序集中的内容文件只是没有显示在 Visual Studio 的已发布应用程序文件对话框中。

这意味着每次部署时,我都必须将应用程序构建输出目录中的所有内容文件复制到已发布目录中并重建清单,这真的很痛苦。

为什么发布者在 Visual Studio 中看不到这些文件?

【问题讨论】:

  • 相当烦人,在 VS 2012 中仍然是一个问题。
  • 在 VS 2013 中仍然是一个问题,他们破坏了以下解决方案。
  • 在 VS 2015 中也是一个问题。将它们作为 linked content 包含在依赖项目的 csproj 文件中效果很好。如果您不想在解决方案资源管理器中看到它,请使用 <visible>false</visible> 标签。
  • 在最新版本中仍然存在问题...链接内容解决方案在某些情况下根本不起作用。
  • 添加为链接,就像@kdbanman 说的那样,将“复制到输出目录”参数更改为“始终复制”,并将“构建操作”参数更改为“内容”为我工作。谢谢

标签: .net clickonce


【解决方案1】:

我似乎从@John Hunter 那里找到了一个更简单的答案演变,将其添加到 csproj。

<ItemGroup>
    <Content Include="Bin\**\*.rpt" />
</ItemGroup>

这将使 Visual Studio 自动查看该文件夹中的所有 *.rpt 文件作为解决方案的一部分。你可以和*.*一起去积累一切。如果您有像 bin\MyDeployables\**\*.* 这样的容器文件夹,这更有意义

我们遵循类似的用法,使用 Cassette MSBuild 在发布时合并和缩小我们的 JS,并能够通过内置的 VS 发布工具发布创建的文件。

【讨论】:

  • 请注意,您可能必须为项目文件中生成的 PublishFile 元素设置 TargetPath-s,否则它们将被放在“Bin”子目录中。
  • 在 Visual Studio 2013 中,这会将文件复制到 app.publish\Bin\Release\My Deployables\filename.ext,而您真正想要的是将它们复制到 app.publish\My Deployables\filename.ext
  • 大家好,您找到解决“app.publish\My Deployables\filename.ext”问题的方法了吗?有没有办法捏造最终的输出文件夹?如果没有,我只需要更改我的代码来搜索 bin\release.. 中的文件。混乱且不理想,但 ATM 进行了 3 小时的搜索,我无法让它工作。
  • 虽然这可能有效,但在项目中引用构建输出 (bin) 似乎是一个非常糟糕的主意。
【解决方案2】:

我想我来自this post 的回答回答了你的问题。

总结
要么...
使用“添加为链接”功能将您的内容文件添加到您的项目中。
或者...
创建构建后事件以将内容文件复制到主输出文件夹。

【讨论】:

  • 我尝试了所有这些,但它对我不起作用。依赖程序集的内容文件已经在输出文件夹中,但即使我选择显示所有文件,它们也不会显示在应用程序文件对话框中。我这里还有什么遗漏的吗?
  • 您的“内容文件”具体是什么?他们有什么文件扩展名?
  • .rpt 主要用于水晶报表文件。
  • 需要添加一个文件作为链接并将其类型设置为“内容”。
【解决方案3】:

好吧,我仍然不知道为什么 Visual Studio 无法使用其发布 ui 显示引用的内容文件,但我找到了一种解决方法来强制发布包含这些文件。

按照this MSDN article 的建议,将其放入项目文件中。

<ItemGroup>
<AdditionalPublishFile Include="$(OutputPath)\**\*.rpt">
  <Visible>False</Visible>
</AdditionalPublishFile>
</ItemGroup>
<Target Name="BeforePublish">
  <Touch Files="@(IntermediateAssembly)" />
  <CreateItem Include="@(AdditionalPublishFile)" AdditionalMetadata="TargetPath=%(RecursiveDir)%(Filename)%(extension);IsDataFile=false">
    <Output TaskParameter="Include" ItemName="_DeploymentManifestFiles" />
  </CreateItem>
</Target>

请注意,在某些情况下,可能需要重新启动 Visual Studio(而不仅仅是重新加载项目)才能使这些更改生效。

【讨论】:

  • 希望有一种方法可以使用 UI 来做到这一点。
  • 我已经尝试过这个解决方案,但对我来说不可行,我使用的是 vs2013 sp1。
  • 这也不再适用于 VS 2015。这些文件被上传/发布,但它们没有在任何部署清单上声明,因此它们不会被客户端下载。我猜_DeploymentManifestFiles 是一个内部项目,不是官方支持的输出目标。
【解决方案4】:

我假设此解决方案基于:http://blogs.msdn.com/mwade/archive/2008/06/29/how-to-publish-files-which-are-not-in-the-project.aspx

根据我最近对该帖子的评论:

我们应该在什么时候期待这些 出现在“应用程序文件”中 列表(如果有的话)?

或者可以安全地假设他们最终会在 我们部署的数据文件列表?

就我而言,我希望使用:

错误

包括所有内容文件 内的依赖程序集 构建的“资源”子文件夹 目录。

安德鲁。

【讨论】:

  • 感谢这个链接,这正是我想要的。
【解决方案5】:

将此添加到 .csproj / .vbproj 的底部可解决此问题。它获取依赖项目的已经缓存的目标项,并将它们显式添加到应用程序清单中,然后也将其发布到分发清单中

<Target Name="MyAddAdditionalPublishItemsFromDependencies"    BeforeTargets="GenerateApplicationManifest">

  <!-- Get items from child projects first. This just fetches data cached by MSBuild -->
  <MSBuild
      Projects="@(_MSBuildProjectReferenceExistent)"
      Targets="GetCopyToOutputDirectoryItems"
      BuildInParallel="$(BuildInParallel)"
      Properties="%(_MSBuildProjectReferenceExistent.SetConfiguration); %(_MSBuildProjectReferenceExistent.SetPlatform); %(_MSBuildProjectReferenceExistent.SetTargetFramework)"
      Condition="'@(_MSBuildProjectReferenceExistent)' != '' and '$(_GetChildProjectCopyToOutputDirectoryItems)' == 'true' and '%(_MSBuildProjectReferenceExistent.Private)' != 'false' and '$(UseCommonOutputDirectory)' != 'true'"
      ContinueOnError="$(ContinueOnError)"
      SkipNonexistentTargets="true"
      RemoveProperties="%(_MSBuildProjectReferenceExistent.GlobalPropertiesToRemove)">

    <Output TaskParameter="TargetOutputs" ItemName="_AllChildProjectItemsWithTargetPath"/>
  </MSBuild>

  <ItemGroup>
    <!-- Filter out the interesting files from MSBuild -->
    <_AllImportedCopyItems KeepDuplicates="false" KeepMetadata="CopyToOutputDirectory;TargetPath" Include="@(_AllChildProjectItemsWithTargetPath->'%(FullPath)')" Condition="'%(_AllChildProjectItemsWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_AllChildProjectItemsWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'" />

    <!-- Get auto copied DLLs with these references -->
    <_AllReferenceAutoCopyItems KeepDuplicates="false" KeepMetadata="CopyToOutputDirectory;TargetPath" Include="@(ReferenceCopyLocalPaths)"/>
  </ItemGroup>
  <ItemGroup>
    <!-- Release memory for huge list -->
    <_AllChildProjectItemsWithTargetPath Remove="@(_AllChildProjectItemsWithTargetPath)"/>
  </ItemGroup>
  <ItemGroup>
    <!-- Filter non-dll -->
    <_AllReferenceAutoCopyItems Remove="%(_AllReferenceAutoCopyItems.Identity)" Condition="'%(_AllReferenceAutoCopyItems.Extension)' != '.dll'" />

    <!-- Remove items which we already have in the deployment manifest -->
    <_AllReferenceAutoCopyItems Remove="@(_DeploymentManifestFiles);@(_DeploymentManifestDependencies)" />
  </ItemGroup>

  <!-- Replace items in _AllReferenceAutoCopyItems with the items emitted by the AssignTargetPath task that have the TargetPath metadata -->
  <AssignTargetPath Files="@(_AllReferenceAutoCopyItems)" RootFolder="$(MSBuildProjectDirectory)">
    <Output TaskParameter="AssignedFiles" ItemName="_Temporary" />
  </AssignTargetPath>
  <ItemGroup>
    <_AllReferenceAutoCopyItems Remove="@(_Temporary)" />
    <_AllReferenceAutoCopyItems Include="@(_Temporary)" />
    <_Temporary Remove="@(_Temporary)" />     
  </ItemGroup>

  <!-- And now declare these items as files for deployment -->
  <ItemGroup>
    <_DeploymentManifestFiles Include="@(_AllImportedCopyItems)">
      <IncludeHash Condition="'%(Extension)' == '.dll' or '%(Extension)' == '.exe'">True</IncludeHash>
      <IsDataFile>false</IsDataFile>
    </_DeploymentManifestFiles>
    <_DeploymentManifestFiles Include="@(_AllReferenceAutoCopyItems)">
      <IncludeHash Condition="'%(Extension)' == '.dll' or '%(Extension)' == '.exe'">True</IncludeHash>
      <IsDataFile>false</IsDataFile>
    </_DeploymentManifestFiles>
  </ItemGroup>    
  <!-- Remove items which we will never again use - they just sit around taking up memory otherwise -->
  <ItemGroup>
    <_AllImportedCopyItems Remove="@(_AllImportedCopyItems)" />
    <_AllReferenceAutoCopyItems Remove="@(_AllReferenceAutoCopyItems)" />
  </ItemGroup>
</Target>

我正在考虑在 .NuGet 包中发布此功能,以便更轻松地安装此脚本。有链接我会发。

【讨论】:

    猜你喜欢
    • 2010-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-30
    • 2020-09-27
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多