.net Visual Studio中未加载源生成器依赖项

oewdyzsn  于 2023-02-10  发布在  .NET
关注(0)|答案(4)|浏览(158)

我正在源代码生成器上工作,我有依赖关系的问题:

It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'FileNotFoundException' with message 'Could not load file or assembly 'Flurl.Http, Version=3.0.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.'

有很多关于如何将依赖项打包到nuget中的信息,但我直接引用Analyzer项目,如下所示:

<ProjectReference Include="SG.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />

在分析器项目中,我添加了<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>,所有依赖项都在输出目录中可用,但VS没有使用该目录-它使用AppData\Local\Temp\VBCSCompiler\AnalyzerAssemblyLoader\[...],并且只在那里复制了一个DLL。
我们可以做些什么来实现这一目标?

3lxsmp7m

3lxsmp7m1#

现在对此有了明确的答案。Source Generator Samples包含一个示例.csproj,它具有所需的设置。
我用这个做了一个Sprache的源代码生成器,效果很好。
将示例.csproj粘贴到此处以供参考:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
</PropertyGroup>

<ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftNetCompilersToolsetVersion)" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.0.0" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
    <!-- Generator dependencies -->
    <PackageReference Include="CsvTextFieldParser" Version="1.2.2-preview" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="Handlebars.Net" Version="1.10.1" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.1" GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>

<PropertyGroup>
    <GetTargetPathDependsOn>$(GetTargetPathDependsOn)</GetTargetPathDependsOn>;GetDependencyTargetPaths
</PropertyGroup>

<Target Name="GetDependencyTargetPaths">
    <ItemGroup>
      <TargetPathWithTargetPlatformMoniker Include="$(PKGCsvTextFieldParser)\lib\netstandard2.0\CsvTextFieldParser.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGHandlebars_Net)\lib\netstandard2.0\Handlebars.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGNewtonsoft_Json)\lib\netstandard2.0\Newtonsoft.Json.dll" IncludeRuntimeDependency="false" />
    </ItemGroup>
</Target>
</Project>
goucqfw6

goucqfw62#

ProjectReferencePackageReference不相同!
GeneratePathProperty不会对ProjectReference执行任何操作,因为它不是包。
因此,您只需将指向本地DLL的TargetPathWithTargetPlatformMoniker添加到源代码生成器csproj中。
默认输出位置示例:

文件夹结构

- Solution Folder
| - MySolution.sln
| + MyProject
| | - MyProject.csproj
| | + bin
| | | + Debug
| | | | + netstandard2.0
| | | | | - MyProject.dll
| | | + Release
| | | | + netstandard2.0
| | | | | - MyProject.dll
| + MySourceGenerator
| | - MySourceGenerator.csproj

我的源生成器.csproj

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>

        <IsRoslynComponent>true</IsRoslynComponent>
        <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\MyProject\MyProject.csproj" PrivateAssets="all"/>
    </ItemGroup>

    <PropertyGroup>
        <GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
    </PropertyGroup>

    <Target Name="GetDependencyTargetPaths">
        <ItemGroup>
            <TargetPathWithTargetPlatformMoniker Include="..\MyProject\bin\$(Configuration)\netstandard2.0\MyProject.dll" IncludeRuntimeDependency="false"/>
        </ItemGroup>
    </Target>
    
</Project>
anauzrmj

anauzrmj3#

我找到了方法,使它的工作或多或少的可靠与一些黑客。
在此之前,我也尝试过ILMerge,但它不起作用(缺少方法异常)。

溶液:

首先,我在源代码生成器汇编中嵌入了依赖项,如下所示:

<ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
    <EmbeddedResource Include="$(PKGNewtonsoft_Json)\lib\netstandard2.0\Newtonsoft.Json.dll" Visible="false" />
</ItemGroup>

然后我为AppDomain(生成器类中的静态构造函数)创建了AssemblyResolve处理程序,如下所示:

AppDomain.CurrentDomain.AssemblyResolve += (_, args) =>
{
    AssemblyName name = new(args.Name);
    Assembly loadedAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().FullName == name.FullName);
    if (loadedAssembly != null)
    {
        return loadedAssembly;
    }

    string resourceName = $"Namespace.{name.Name}.dll";

    using Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
    if (resourceStream == null)
    {
        return null;
    }
    
    using MemoryStream memoryStream = new MemoryStream();
    resourceStream.CopyTo(memoryStream);

    return Assembly.Load(memoryStream.ToArray());
};
pcrecxhr

pcrecxhr4#

源代码生成器食谱中概述了这种 * 应该 * 工作的方式,其示例如下:

<Project>
  <PropertyGroup>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- Generates a package at build -->
    <IncludeBuildOutput>false</IncludeBuildOutput> <!-- Do not include the generator as a lib dependency -->
  </PropertyGroup>

  <ItemGroup>
    <!-- Take a private dependency on Newtonsoft.Json (PrivateAssets=all) Consumers of this generator will not reference it.
         Set GeneratePathProperty=true so we can reference the binaries via the PKGNewtonsoft_Json property -->
    <PackageReference Include="Newtonsoft.Json" Version="12.0.1" PrivateAssets="all" GeneratePathProperty="true" />

    <!-- Package the generator in the analyzer directory of the nuget package -->
    <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />

    <!-- Package the Newtonsoft.Json dependency alongside the generator assembly -->
    <None Include="$(PkgNewtonsoft_Json)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
  </ItemGroup>
</Project>

但是,根据我的经验,这仍然不可靠或不健壮;这是公认的,我得到的印象是,改善这种经验是未来规划的一部分,但:现在,老实说,最好不要使用核心框架和已经加载的Roslyn库之外的依赖项。2如果你的依赖项和分析器/生成器在同一个repo中,你可以在构建期间简单地吸入代码,例如从这里:

<ItemGroup>
    <!-- compile what we need from protobuf-net directly; package refs cause pure pain in anaylizers-->
    <Compile Include="../protobuf-net.Core/**/*.cs" Link="protobuf-net.Core"/>
    <Compile Remove="../protobuf-net.Core/obj/**/*.cs" />
    <Compile Include="../protobuf-net.Reflection/**/*.cs"  Link="protobuf-net.Reflection"/>
    <Compile Remove="../protobuf-net.Reflection/obj/**/*.cs" />
</ItemGroup>

相关问题