VSIX 扩展 - 如何确保引用的 dll 或程序集包含在 VSIX 文件中?

VSIX extension - How can I ensure a referenced dll or assembly is included in the VSIX file?

当用户安装我的扩展,但没有安装最新的 Visual Studio 更新时,扩展无法解析 Microsoft.CodeAnalysis.CSharp.dll 以及以下消息:

Could not load file or assembly 'Microsoft.CodeAnalysis.CSharp, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

我确定扩展确实引用了这个程序集,它确实引用了这个程序集,但是为什么这个程序集会被排除在 VSIX 文件之外?

我将 VSIX 文件重命名为 ZIP,查看了内容,但该程序集未发货,即使其他 "Microsoft.CodeAnalysis.*.dll" 程序集包含在 VSIX 文件中。

我还确认了参考文献中的“复制本地”属性是正确的。

我找到了这个问题的解决方案,我可以看到该 dll 现在包含在 VSIX 中,并且用户确认它适用于他。

  1. 在 Visual Studio 中,打开扩展解决方案,
  2. 双击 .vsixmanifest 文件
  3. 打开 "Assets" 选项卡
  4. 点击"New"
  5. 将类型设置为 "Microsoft.VisualStudio.Assembly"
  6. 将源设置为 "A File on FileSystem"
  7. 单击“浏览”为您的 dll 设置路径,(不用担心引用不会添加为绝对路径,而是添加为相对路径或只是一个强大的程序集名称)
  8. 您可以将 "Embed in this folder" 留空。
  9. 点击确定
  10. 重建解决方案,该文件现在应该在 VSIX 文件中。

然后将此行添加到 vsixmanifest 文件中:

<Asset Type="Microsoft.VisualStudio.Assembly" d:Source="File" Path="Microsoft.CodeAnalysis.CSharp.dll" AssemblyName="Microsoft.CodeAnalysis.CSharp, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

我找到了与 Martin 类似的解决方法,但没有要求 DLL 副本位于项目文件夹中的副作用。 (我还没有想出如何添加丢失的非英语资源程序集。)

第 0 步:如果您有间接依赖项 - vsix 依赖于使用 NuGet 包 C 的项目 B,而 C 依赖于包 D - 确保 C 和 D 的 DLL 包含在您的 vsix 的 bin\Debug 文件夹中.如果没有,为了安全起见,我建议将对包 C 和 D 的引用添加到 vsix 项目中。就我而言,VS 决定在 VSIX 中包含一些间接依赖项,例如 System.Numerics.Vectors.dllSystem.Threading.Tasks.Extensions.dll,但它决定省略四个间接依赖项:Microsoft.CodeAnalysis.dllMicrosoft.CodeAnalysis.CSharp.dllSystem.Reflection.Metadata.dllSystem.Collections.Immutable.dll.

第 1 步:重建并找出 VSIX 中丢失的文件。您可以将 .vsix 重命名为 .zip 以找出其中的内容,并将其与 vsix 项目文件夹中 bin\Debug 的内容进行比较以查找丢失的项目。

第 2 步:使用“添加 > 现有项目...”和“添加为 Link”将缺少的 DLL 添加到您的项目中(如果您不确定 DLL 的位置,请查找它在您的引用列表中并在“属性”面板中查看其路径 属性。)

第 3 步:对每个缺少的 DLL 重复第 2 步。

第 4 步:Select 新的 DLL,并在“属性”面板中设置“包含在 VSIX 中”标志。

在我的(旧式)csproj 中,我最终得到这样的 ItemGroup

  <ItemGroup>
    <Content Include="..\packages\Microsoft.CodeAnalysis.Common.3.6.0\lib\netstandard2.0\Microsoft.CodeAnalysis.dll">
      <Link>Microsoft.CodeAnalysis.dll</Link>
      <IncludeInVSIX>true</IncludeInVSIX>
    </Content>
    <Content Include="..\packages\Microsoft.CodeAnalysis.CSharp.3.6.0\lib\netstandard2.0\Microsoft.CodeAnalysis.CSharp.dll">
      <Link>Microsoft.CodeAnalysis.CSharp.dll</Link>
      <IncludeInVSIX>true</IncludeInVSIX>
    </Content>
    <Content Include="..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll">
      <Link>System.Collections.Immutable.dll</Link>
      <IncludeInVSIX>true</IncludeInVSIX>
    </Content>
    <Content Include="..\packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll">
      <Link>System.Reflection.Metadata.dll</Link>
      <IncludeInVSIX>true</IncludeInVSIX>
    </Content>
  </ItemGroup>

第 5 步:重建并验证文件现在是否包含在 vsix 中。您不需要将文件添加到资产列表中。然后在Visual Studio中进行测试。祝你好运!

P.S. 我突然想到,也许 VSIX 不包含这些文件的原因是因为 VS 知道 Visual Studio 已经有了这些文件安装的文件。但是这个解释并不令人满意,因为,例如,Visual Studio 有 System.Memory.dllSystem.Numerics.Vectors.dll 的副本,但是VS 仍然选择在我的 VSIX 中包含那些 DLL。

无论如何,我的扩展无法加载 Visual Studio 2019 年的文件副本。我注意到我的 Microsoft.CodeAnalysis.dll 版本是“3.6.0-4.20269.4+...”,而 C:\Program Files (x86)\Microsoft Visual Studio19\Community\Common7\IDE\CommonExtensions\Microsoft\ManagedLanguages\VBCSharp\LanguageServices 中的副本 是“3.5.0-beta4-20153-05+...”(假设这是重要的 - 我不知道,程序文件中还有 5 个其他副本)。通过将我的 VSIX 降级为使用 早于 3.5.0-beta4 的版本(假设 Beta 版本不在 NuGet 上),也许我的扩展可以使用 Visual Studio 的复制。但这是另一天的测试,即使它有效,如果我想同时针对 Visual Studio 2017 和 Visual Studio 2019,我怀疑如果我不这样做,我是否可以同时针对同一个 vsix 的两个版本vsix 中没有包含我需要的所有 DLL。

将此添加到 csproj:

  <Target Name="IncludePackageReferenceDependencies" AfterTargets="GetVsixSourceItems">
    <ItemGroup>
      <!-- <VSIXSourceItem Include="@(ReferencePath)" Condition="$([System.String]::new('%(ReferencePath.FusionName)').EndsWith('.dll'))" /> -->
      <VSIXSourceItem Include="@(ReferencePath)" />
    </ItemGroup>
  </Target>

对于那些不喜欢为丢失的 dll 添加引用的人,我发现以下内容非常有效

https://www.cazzulino.com/include-dlls-in-vsix.html

我在 .csproj 的末尾添加了以下内容,所有丢失的 dll 都在 .vsix

<PropertyGroup>
    <GetVsixSourceItemsDependsOn>$(GetVsixSourceItemsDependsOn);IncludeNuGetResolvedAssets</GetVsixSourceItemsDependsOn>
</PropertyGroup>
<Target Name="IncludeNuGetResolvedAssets" DependsOnTargets="ResolveNuGetPackageAssets">
    <ItemGroup>
        <VSIXCopyLocalReferenceSourceItem Include="@(ReferenceCopyLocalPaths)"  />
    </ItemGroup>
</Target>