Почему ClickOnce в Visual Studio не развертывает файлы содержимого из зависимых сборок?

У меня есть умное клиентское приложение, которое развертывается одним щелчком мыши. Проблема в том, что у меня есть файлы содержимого в зависимых сборках, которые просто не отображаются в диалоговом окне опубликованных файлов приложения в Visual Studio.

Это означает, что каждый раз при развертывании мне приходится копировать все файлы содержимого из выходного каталога сборки приложения в опубликованный каталог и перестраивать манифесты, что является настоящей проблемой.

Почему эти файлы не видны издателю в Visual Studio?

Ответов (5)

Решение

Мне показалось, что я нашел эволюцию ответа от @John Hunter, которая намного проще, добавьте это в csproj.

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

Это заставит Visual Studio автоматически просматривать все файлы * .rpt в этой папке как часть решения. Вы могли *.* бы собрать все. Это имеет больше смысла, если у вас есть папка-контейнер, например bin\MyDeployables\**\*.*

Мы следовали аналогичному использованию Cassette MSBuild для объединения и минификации нашего JS во время публикации, а также для публикации созданных файлов с помощью встроенных инструментов публикации VS.

Добавление этого файла в конец файла .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, чтобы упростить установку этого скрипта. Я отправлю ссылку, когда она у меня будет.

Думаю, мой ответ из этого поста отвечает на ваш вопрос.

Резюме
Либо ...
Добавьте файлы содержимого в проект, используя функцию «Добавить как ссылку».
Или ...
Создайте событие после сборки, чтобы скопировать файлы содержимого в основную папку вывода.

Хорошо, я все еще не знаю, почему Visual Studio не может отображать файлы содержимого, на которые есть ссылки, с помощью пользовательского интерфейса публикации, но я нашел способ заставить публикацию включать эти файлы.

Как предлагается в этой статье MSDN , поместите это в файл проекта.

<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 (а не просто перезагрузка проекта), чтобы эти изменения вступили в силу.

Я предполагаю, что это решение было основано на: http://blogs.msdn.com/mwade/archive/2008/06/29/how-to-publish-files-which-are-not-in-the-project.aspx

Согласно моему недавнему комментарию к сообщению:

В какой момент мы должны ожидать, что они появятся в списках «Файлы приложения» (если вообще)?

Или можно с уверенностью предположить, что они попадут в наш список развернутых файлов данных?

В моем случае я надеюсь использовать:

Ложь

Чтобы включить все файлы содержимого из зависимых сборок, которые находятся в подпапке «Ресурсы» каталога сборки.

Эндрю.