C#增量发电机 - 如何读取其他文件?额外的textsProvider无法正常工作

发布于 2025-01-25 20:44:03 字数 4184 浏览 5 评论 0原文

我正在尝试从appsettings.json获得一些值。但是,无论我尝试使用额外的textSprovider,无论如何。这是我的代码

IncrementalValuesProvider<AdditionalText> textFiles = context.AdditionalTextsProvider.Where(static file => file.Path.Contains("appsettings.json")); // tried many things here, like EndsWith(".json") etc..
IncrementalValuesProvider<(string name, string content)> namesAndContents = textFiles.Select((text, cancellationToken) => (name: Path.GetFileNameWithoutExtension(text.Path), content: text.GetText(cancellationToken)!.ToString()));

context.RegisterSourceOutput(namesAndContents, (spc, nameAndContent) =>
    {
         nameAndContent.content; //always empty 
         nameAndContent.name; //always empty 
    });

,当我实现ISOURCEGENERATOR(相同的解决方案,相同项目)时,这一行代码就可以了!

var file = context.AdditionalFiles.FirstOrDefault(x => x.Path.Contains("appsettings.json"));

引用代码生成器的项目:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Dapper" Version="2.0.123" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.4" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.3">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Scrutor" Version="4.1.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
  </ItemGroup>
  <ItemGroup>
        <ProjectReference Include="..\myproject\myproject.csproj" />
    <ProjectReference Include="..\myproject.EFCore\myproject.EFCore.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
  </ItemGroup>

  <ItemGroup>
    <AdditionalFiles Include="appsettings.json" />
  </ItemGroup>

</Project>

代码生成器项目:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>latest</LangVersion>    
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- Generates a package at build -->
    <IncludeBuildOutput>false</IncludeBuildOutput> <!-- Do not include the generator as a lib dependency -->
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
  </ItemGroup>
  <ItemGroup>
    <!-- Generator dependencies -->
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" GeneratePathProperty="true" PrivateAssets="all" />
  </ItemGroup>
 <PropertyGroup>   <GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
  </PropertyGroup>
  <Target Name="GetDependencyTargetPaths">
    <ItemGroup>
      <TargetPathWithTargetPlatformMoniker Include="$(PKGNewtonsoft_Json)\lib\netstandard2.0\Newtonsoft.Json.dll" IncludeRuntimeDependency="false" />
    </ItemGroup>
  </Target>
    <ItemGroup>
    <!-- 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 props file -->
  </ItemGroup>
</Project>

I am trying to get some values from the appsettings.json. But whatever I try with the AdditionalTextsProvider doesn't work. Here is my code

IncrementalValuesProvider<AdditionalText> textFiles = context.AdditionalTextsProvider.Where(static file => file.Path.Contains("appsettings.json")); // tried many things here, like EndsWith(".json") etc..
IncrementalValuesProvider<(string name, string content)> namesAndContents = textFiles.Select((text, cancellationToken) => (name: Path.GetFileNameWithoutExtension(text.Path), content: text.GetText(cancellationToken)!.ToString()));

context.RegisterSourceOutput(namesAndContents, (spc, nameAndContent) =>
    {
         nameAndContent.content; //always empty 
         nameAndContent.name; //always empty 
    });

From the other hand, when I implement the ISourceGenerator (same solution, same projects) this line of code just works!

var file = context.AdditionalFiles.FirstOrDefault(x => x.Path.Contains("appsettings.json"));

The project which is referencing the code generator:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Dapper" Version="2.0.123" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.4" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.3">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Scrutor" Version="4.1.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
  </ItemGroup>
  <ItemGroup>
        <ProjectReference Include="..\myproject\myproject.csproj" />
    <ProjectReference Include="..\myproject.EFCore\myproject.EFCore.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
  </ItemGroup>

  <ItemGroup>
    <AdditionalFiles Include="appsettings.json" />
  </ItemGroup>

</Project>

Code generator project :

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>latest</LangVersion>    
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- Generates a package at build -->
    <IncludeBuildOutput>false</IncludeBuildOutput> <!-- Do not include the generator as a lib dependency -->
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
  </ItemGroup>
  <ItemGroup>
    <!-- Generator dependencies -->
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" GeneratePathProperty="true" PrivateAssets="all" />
  </ItemGroup>
 <PropertyGroup>   <GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
  </PropertyGroup>
  <Target Name="GetDependencyTargetPaths">
    <ItemGroup>
      <TargetPathWithTargetPlatformMoniker Include="$(PKGNewtonsoft_Json)\lib\netstandard2.0\Newtonsoft.Json.dll" IncludeRuntimeDependency="false" />
    </ItemGroup>
  </Target>
    <ItemGroup>
    <!-- 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 props file -->
  </ItemGroup>
</Project>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风筝有风,海豚有海 2025-02-01 20:44:03

如果将其他文本提供商与汇编相结合,它对我有用(灵感来自此出色的文章):

public void Initialize(IncrementalGeneratorInitializationContext context)
{
    var files = context.AdditionalTextsProvider
        .Where(a => a.Path.EndsWith("appsettings.json"))
        .Select((a, c) => (Path.GetFileNameWithoutExtension(a.Path), a.GetText(c)!.ToString()));

    var compilationAndFiles = context.CompilationProvider.Combine(files.Collect());
            
    context.RegisterSourceOutput(compilationAndFiles, (productionContext, sourceContext) => Generate(productionContext, sourceContext));
}

void Generate(SourceProductionContext context, (Compilation compilation, ImmutableArray<(string, string)> files) compilationAndFiles)
{
    //emit generated files...
}

更新:

再次通过Visual Studio 17.4进行了测试。与汇编的结合似乎不再是必要的。当AppSettings.json仅使用afrefextsprovider注册时,将以预期的方式调用发电机。

If you combine the additional text provider with the compilation it works for me (inspired by this great post):

public void Initialize(IncrementalGeneratorInitializationContext context)
{
    var files = context.AdditionalTextsProvider
        .Where(a => a.Path.EndsWith("appsettings.json"))
        .Select((a, c) => (Path.GetFileNameWithoutExtension(a.Path), a.GetText(c)!.ToString()));

    var compilationAndFiles = context.CompilationProvider.Combine(files.Collect());
            
    context.RegisterSourceOutput(compilationAndFiles, (productionContext, sourceContext) => Generate(productionContext, sourceContext));
}

void Generate(SourceProductionContext context, (Compilation compilation, ImmutableArray<(string, string)> files) compilationAndFiles)
{
    //emit generated files...
}

Update:

Tested again with Visual Studio 17.4. and combination with compilation seems not to be necessary anymore. Generator is called as expected when appsettings.json changes with only AdditionalTextsProvider registered.

苏大泽ㄣ 2025-02-01 20:44:03

我尝试了复制,但一切都对我有用。

我将源生成器定义为此

namespace ConsoleAppSourceGenerator
{
    [Generator]
    public class TxtGenerator : IIncrementalGenerator
    {
        private static int counter;

        public void Initialize(IncrementalGeneratorInitializationContext initContext)
        {
            IncrementalValuesProvider<AdditionalText> textFiles = initContext.AdditionalTextsProvider
                .Where(static file => file.Path.EndsWith(".txt"));

            IncrementalValuesProvider<(string name, string content)> namesAndContents = textFiles
                .Select((text, cancellationToken) => (name: Path.GetFileNameWithoutExtension(text.Path), content: text.GetText(cancellationToken)!.ToString()));

            initContext.RegisterSourceOutput(namesAndContents, (spc, nameAndContent) =>
            {
                spc.AddSource($"TxtFile.{nameAndContent.name}.g.cs", $@"
// Counter {Interlocked.Increment(ref counter)}
public static partial class TxtFile
{{
    public const string {nameAndContent.name} = ""{nameAndContent.content}"";
}}");
            });
        }
    }
}

和源生成器项目

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

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
      <Nullable>enable</Nullable>
      <LangVersion>Latest</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" />
  </ItemGroup>
</Project>

,然后在另一个项目中将其定义为foo.txt文件,

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
      <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
      <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
  </PropertyGroup>

    <ItemGroup>
        <Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
    </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\ConsoleAppSourceGenerator\ConsoleAppSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
  </ItemGroup>
    
    <ItemGroup>
        <AdditionalFiles Include="foo.txt"/>
    </ItemGroup>

</Project>

如果我通过Visual Studio查看依赖项 - &gt; Analyzers-- &gt; consoleappsourcegenerator&gt; txtfile.foo.g.cs然后,它正确地增加了我在文件中的每一个更改的计数器(请参见步骤9 )。

我将生成的文件存储在路径consoleapp/oferated/consoleappsourcegenerator/consoleappsourcegenerator.txtgenerator

您是否记得将[Generator]属性添加到iincrementalgenerator

您能测试一下并验证这对您不起作用吗?

I have tried replicate but everything works for me.

I define my source generator as this

namespace ConsoleAppSourceGenerator
{
    [Generator]
    public class TxtGenerator : IIncrementalGenerator
    {
        private static int counter;

        public void Initialize(IncrementalGeneratorInitializationContext initContext)
        {
            IncrementalValuesProvider<AdditionalText> textFiles = initContext.AdditionalTextsProvider
                .Where(static file => file.Path.EndsWith(".txt"));

            IncrementalValuesProvider<(string name, string content)> namesAndContents = textFiles
                .Select((text, cancellationToken) => (name: Path.GetFileNameWithoutExtension(text.Path), content: text.GetText(cancellationToken)!.ToString()));

            initContext.RegisterSourceOutput(namesAndContents, (spc, nameAndContent) =>
            {
                spc.AddSource(
quot;TxtFile.{nameAndContent.name}.g.cs", $@"
// Counter {Interlocked.Increment(ref counter)}
public static partial class TxtFile
{{
    public const string {nameAndContent.name} = ""{nameAndContent.content}"";
}}");
            });
        }
    }
}

and source generator project as this

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

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
      <Nullable>enable</Nullable>
      <LangVersion>Latest</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" />
  </ItemGroup>
</Project>

Then in another project, where I have made a dummy foo.txt file I have

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
      <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
      <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
  </PropertyGroup>

    <ItemGroup>
        <Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
    </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\ConsoleAppSourceGenerator\ConsoleAppSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
  </ItemGroup>
    
    <ItemGroup>
        <AdditionalFiles Include="foo.txt"/>
    </ItemGroup>

</Project>

If I through Visual Studio look at Dependencies->Analyzers->ConsoleAppSourceGenerator>TxtFile.foo.g.cs then it correctly increase the counter on every change I to in the file (see step 9).

I store generated files in path ConsoleApp/Generated/ConsoleAppSourceGenerator/ConsoleAppSourceGenerator.TxtGenerator and whenever I rebuild the project it correctly updates the files.

Have you remembered to add the [Generator] attribute to the IIncrementalGenerator?

Could you test this out and validates this doesn't either work for you?

篱下浅笙歌 2025-02-01 20:44:03

您的消费项目文件中的“额外文件”是确保这些文件由您的源/增量发电机捕获的关键。

发现使用“&lt;其他files inculce ='...' /&gt;”在某些项目中没有必要的源/源/增量加生器的ASPNET核心项目。默认情况下,将.cshtml文件作为其他文件包含。

此外,文件球模式与“ Include”参数一起使用。

"AdditionalFiles" in your consuming project file is the key to ensuring these files are captured by your source/incremental generator.

Found out that using a "<AdditionalFiles Include='...' />" is not necessary in some projects such as ASPNET Core projects for Source/IncrementalGenerators. The .cshtml files are included as additional files by default.

Also, file globbing patterns work with the "Include" parameter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文