Start Debugging

Lösung: The 'interceptors' feature is not enabled in this namespace

CS9137 stammt vom Source Generator in Microsoft.AspNetCore.OpenApi. Fügen Sie InterceptorsNamespaces in jedem Projekt hinzu, das AddOpenApi aufruft, nicht nur im Projekt mit der PackageReference.

Fügen Sie das in dem Projekt hinzu, das der Compiler in der Fehlermeldung nennt, nicht in dem Projekt mit der PackageReference:

<!-- .NET 10 / .NET 11, Microsoft.AspNetCore.OpenApi 10.0.x -->
<PropertyGroup>
  <InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>
</PropertyGroup>

Der Source Generator für XML-Kommentare in Microsoft.AspNetCore.OpenApi erzeugt Interceptors, und die MSBuild-Eigenschaft, die deren Namespace freigibt, liegt im Ordner build/ des Pakets. NuGet reicht build/ weder über eine ProjectReference noch über eine transitive Paketabhängigkeit weiter, Analyzer dagegen schon. Jedes Projekt, das den Generator erbt, aber die Eigenschaft nicht, scheitert also beim Kompilieren. Alles Folgende ist gegen SDK 10.0.201 und Microsoft.AspNetCore.OpenApi 10.0.10 verifiziert.

Der Fehler im Kontext

Der Compiler zeigt auf eine Datei, die Sie nie geschrieben haben, unterhalb von obj:

obj\Debug\net10.0\Microsoft.AspNetCore.OpenApi.SourceGenerators\Microsoft.AspNetCore.OpenApi.SourceGenerators.XmlCommentGenerator\OpenApiXmlCommentSupport.generated.cs(598,10):
error CS9137: The 'interceptors' feature is not enabled in this namespace. Add '<InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>' to your project.

CS9137 kommt immer mit einem Namespace, und dieser Namespace verrät, welcher Generator sich beschwert:

Namespace in der MeldungGenerator
Microsoft.AspNetCore.OpenApi.GeneratedXML-Dokumentationskommentare für OpenAPI
Microsoft.Extensions.Validation.GeneratedValidierung für Minimal APIs (ab .NET 10)
Microsoft.AspNetCore.Http.Validation.GeneratedDerselbe Generator, Name aus der .NET 10 Preview
Microsoft.AspNetCore.Http.GeneratedRequest Delegate Generator (Minimal APIs mit Native AOT)
Microsoft.Extensions.Configuration.Binder.SourceGenerationGenerator für das Konfigurations-Binding

Nur der erste ist auf einem veröffentlichten SDK Ihr Problem. Die anderen drei erledigt das .NET SDK selbst, in Microsoft.NET.Sdk.FrameworkReferenceResolution.targets:

<!-- SDK 10.0.201, Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets -->
<InterceptorsPreviewNamespaces Condition="'$(EnableRequestDelegateGenerator)' == 'true'">$(InterceptorsPreviewNamespaces);Microsoft.AspNetCore.Http.Generated</InterceptorsPreviewNamespaces>
<InterceptorsPreviewNamespaces Condition="'$(EnableConfigurationBindingGenerator)' == 'true'">$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration</InterceptorsPreviewNamespaces>
<InterceptorsPreviewNamespaces Condition="'$(_TargetFrameworkVersionWithoutV)' != '' and $([MSBuild]::VersionGreaterThanOrEquals('$(_TargetFrameworkVersionWithoutV)', '10.0'))">$(InterceptorsPreviewNamespaces);Microsoft.Extensions.Validation.Generated</InterceptorsPreviewNamespaces>

Wenn Sie noch die Schreibweise Microsoft.AspNetCore.Http.Validation.Generated sehen, arbeiten Sie mit einem Preview-SDK von .NET 10. Der Namespace wurde vor dem Release umbenannt, eine aus einem Artikel von 2025 kopierte Lösung ist heute also eine wirkungslose Zeichenkette.

Warum das passiert

Interceptors werden pro Namespace freigeschaltet. Roslyn akzeptiert ein [InterceptsLocation]-Attribut nur, wenn der umgebende Namespace über /features:InterceptorsNamespaces an den Compiler übergeben wurde, und MSBuild baut diesen Schalter aus zwei Eigenschaften zusammen, die beide in Microsoft.CSharp.Core.targets weitergereicht werden:

<!-- SDK 10.0.201, Roslyn/Microsoft.CSharp.Core.targets -->
InterceptorsNamespaces="$(InterceptorsNamespaces)"
InterceptorsPreviewNamespaces="$(InterceptorsPreviewNamespaces)"

Der OpenAPI-Generator für XML-Kommentare erzeugt seit .NET 10 Interceptors. Mit EmitCompilerGeneratedFiles lässt sich genau nachlesen, was dabei entsteht:

// Generated by Microsoft.AspNetCore.OpenApi.SourceGenerators 10.0.10
namespace Microsoft.AspNetCore.OpenApi.Generated
{
    file static class GeneratedServiceCollectionExtensions
    {
        [global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "iPD7FWRAJiLeb9V88cfKbz0BAABDbGFzczEuY3M=")]
        public static IServiceCollection AddOpenApi(this IServiceCollection services, string documentName)
        {
            return services.AddOpenApi(documentName, options =>
            {
                options.AddSchemaTransformer(new XmlCommentSchemaTransformer());
                options.AddOperationTransformer(new XmlCommentOperationTransformer());
            });
        }
    }
}

Das ist die ganze Funktion: Ihre Aufrufstelle von AddOpenApi() wird zur Kompilierzeit durch eine ersetzt, die zusätzlich die beiden Transformer mit Ihren XML-Kommentaren registriert. Nichts daran ist optional oder verzögert, und deshalb ist ein nicht freigegebener Namespace ein harter Build-Fehler und keine Warnung.

Das Paket schaltet den Namespace für Sie frei, in einer einzigen Datei:

<!-- microsoft.aspnetcore.openapi/10.0.10/build/Microsoft.AspNetCore.OpenApi.targets -->
<Project>
  <PropertyGroup>
    <InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>
  </PropertyGroup>
  <Target Name="GenerateAdditionalXmlFilesForOpenApi" AfterTargets="ResolveReferences">
    ...
  </Target>
</Project>

Beachten Sie den Ordner: build, nicht buildTransitive. Auf dieser Asymmetrie beruht der gesamte Fehler. In der Paketierung von ASP.NET Core steht es explizit:

<!-- dotnet/aspnetcore, src/OpenApi/src/Microsoft.AspNetCore.OpenApi.csproj -->
<None Include="..\build\Microsoft.AspNetCore.OpenApi.targets" Pack="true" PackagePath="build" Visible="false" />

NuGet reicht nur Assets aus buildTransitive/ an indirekte Konsumenten weiter. Analyzer dagegen werden weitergereicht. Ein Projekt, das Microsoft.AspNetCore.OpenApi über eine ProjectReference erhält, bekommt also den Source Generator und nichts von der MSBuild-Infrastruktur, die dessen Ausgabe zulässig macht. Ursache und Heilmittel liegen in verschiedenen Projekten, und deshalb wirkt der Fehler beim ersten Mal unsinnig: Sie haben die Eigenschaft bereits gesetzt, nur nicht in dem Projekt, über das sich der Compiler beschwert.

Ein Befehl zeigt, auf welcher Seite der Linie ein Projekt steht:

dotnet msbuild MyApi.csproj -getProperty:InterceptorsNamespaces

Ein leerer Wert bedeutet, dass die Eigenschaft nie angekommen ist. ;Microsoft.AspNetCore.OpenApi.Generated bedeutet, dass sie angekommen ist.

Minimale Reproduktion

Zwei Projekte. Das erste hat das Paket, das zweite referenziert nur das erste:

<!-- Defaults.csproj -- .NET 10, Microsoft.AspNetCore.OpenApi 10.0.10 -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" />
  </ItemGroup>
</Project>
<!-- Modules.csproj -- .NET 10, no PackageReference of its own -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\Defaults\Defaults.csproj" />
  </ItemGroup>
</Project>

Beide rufen AddOpenApi auf:

// Modules/Class1.cs -- .NET 10, C# 14
using Microsoft.Extensions.DependencyInjection;

namespace Modules;

/// <summary>Module registrations.</summary>
public static class ModuleExtensions
{
    /// <summary>Adds the module's OpenAPI document.</summary>
    public static IServiceCollection AddModule(this IServiceCollection services)
        => services.AddOpenApi("module");
}

dotnet build Defaults läuft durch. dotnet build Modules scheitert mit CS9137. Das Muster ist dasselbe, egal ob das konsumierende Projekt Microsoft.NET.Sdk oder Microsoft.NET.Sdk.Web verwendet: Ich habe es mit einer per dotnet new web erzeugten API reproduziert, deren einziger Weg zum Paket eine ProjectReference auf eine gemeinsame Defaults-Bibliothek war. Ein Webprojekt zu sein hilft hier überhaupt nicht.

Echte Codebasen treffen das in drei wiedererkennbaren Formen: eine ServiceDefaults-Bibliothek im Aspire-Stil, die AddOpenApi zentralisiert, ein modularer Monolith, in dem jedes Modul sein eigenes Dokument registriert, und ein Plugin- oder CMS-Host (Module von Umbraco und OrchardCore tauchen in den Issue-Berichten auf), bei dem das Paket eine Ebene höher in einem Basispaket liegt.

Die Lösung, nach Präferenz geordnet

1. Die Eigenschaft im scheiternden Projekt setzen

Kopieren Sie den Namespace aus der Fehlermeldung und fügen Sie die Eigenschaft in die .csproj ein, die der Fehler nennt:

<!-- .NET 10 / .NET 11, Microsoft.AspNetCore.OpenApi 10.0.x -->
<PropertyGroup>
  <InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.OpenApi.Generated</InterceptorsNamespaces>
</PropertyGroup>

Behalten Sie das führende $(InterceptorsNamespaces);. Andere Generatoren hängen an dieselbe Eigenschaft an, und eine nackte Zuweisung wirft deren Einträge weg. So läuft der Generator weiter, und die XML-Kommentare landen weiterhin im Dokument.

Registrieren mehrere Projekte einer Solution Dokumente, gehört die Zeile einmal in Directory.Build.props statt in jede Datei. Die Targets des Pakets werden nach dem Projektinhalt importiert und hängen an das an, was sie vorfinden, die beiden geraten sich also nie in die Quere.

2. Dem Projekt eine eigene PackageReference geben

Wenn das Projekt tatsächlich AddOpenApi aufruft, hat es einen legitimen Anspruch auf das Paket:

dotnet add Modules package Microsoft.AspNetCore.OpenApi

Damit kommt build/Microsoft.AspNetCore.OpenApi.targets mit, das die Eigenschaft für Sie setzt. Ich habe verifiziert, dass das den Fehler ohne weitere Änderung beseitigt. Es ist ehrlicher als die transitive Konstruktion und übersteht es, wenn jemand später die Projektreferenzen umbaut.

3. Den Generator in diesem Projekt abschalten

Wenn das Projekt kein Interesse an XML-Kommentaren hat, entfernen Sie den Analyzer, statt dessen Ausgabe freizugeben. Die offizielle Dokumentation zeigt das über die Paketpfad-Eigenschaft; die Item-basierte Form ist weniger fragil:

<!-- .NET 10, disables the OpenAPI XML comment generator for this project only -->
<Target Name="DisableOpenApiXmlGenerator" BeforeTargets="CoreCompile">
  <ItemGroup>
    <Analyzer Remove="@(Analyzer)"
              Condition="'%(Filename)' == 'Microsoft.AspNetCore.OpenApi.SourceGenerators'" />
  </ItemGroup>
</Target>

Der Build wird grün, und der Preis ist, dass der Text aus <summary> und <param> in der OpenAPI-Ausgabe dieses Projekts nicht mehr erscheint. Denselben Effekt vom anderen Ende erreicht PrivateAssets="analyzers" an der vorgelagerten PackageReference, das den Generator von allen Konsumenten dieser Bibliothek fernhält:

<!-- Defaults.csproj -- .NET 10, keeps the generator out of downstream projects -->
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" PrivateAssets="analyzers" />

Beides sind verifizierte Lösungen. Greifen Sie darauf zurück, wenn ein Build-Server rot ist und Sie die Pipeline dringender brauchen als die Dokumentation.

Details, die den Build rot halten

InterceptorsPreviewNamespaces funktioniert weiterhin und ist nicht die moderne Schreibweise. Der C#-14-Compiler in SDK 10.0.201 respektiert die alte Eigenschaft warnungsfrei, und das SDK selbst nutzt sie weiterhin für seine drei Namespaces. Verwenden Sie in neuem Code InterceptorsNamespaces, aber “reparieren” Sie keinen geerbten Build, indem Sie eine funktionierende Eigenschaft umbenennen.

Die XML-Dokumentation abzuschalten schaltet den Generator nicht ab. <GenerateDocumentationFile>false</GenerateDocumentationFile> wirkt so, als müsste es einen Generator für XML-Kommentare umgehen. Tut es nicht. Der Generator interceptet AddOpenApi weiterhin, und derselbe CS9137 kommt in Zeile 597 statt 598 zurück. Wenn Sie ihn loswerden wollen, entfernen Sie den Analyzer.

Die Interception gilt pro Aufrufstelle und pro Kompilierung. Dieser Punkt kostet Leute Stunden, nachdem der Build längst grün ist. Die Transformer werden in die Kompilierung eingebacken, in der der AddOpenApi()-Aufruf physisch steht, und sie tragen ausschließlich die XML-Kommentare dieser Kompilierung. Verschieben Sie den Aufruf in eine gemeinsame Defaults-Bibliothek, verschwinden die Zusammenfassungen Ihres API-Projekts stillschweigend aus dem Dokument. Gemessen an der obigen Reproduktion, mit AddOpenApi() direkt im API-Projekt:

{
  "summary": "Gets a single widget by id.",
  "parameters": [
    { "name": "id", "description": "The widget identifier." }
  ]
}

Bei identischem, gleich dokumentiertem Endpunkt, aber mit AddOpenApi() aus der referenzierten Bibliothek aufgerufen, fehlen sowohl summary als auch die description des Parameters. Lassen Sie den AddOpenApi()-Aufruf in dem Projekt, dessen Kommentare Sie wollen, oder speisen Sie die XML-Dateien der anderen Assemblys über AdditionalFiles ein.

Ein nicht-literaler Dokumentname wird nicht interceptet. AddOpenApi(documentName) mit documentName als Variable erzeugt gar keinen Interceptor, Sie bekommen also weder einen Fehler noch XML-Kommentare. Nur literale Zeichenketten werden erkannt.

EmitCompilerGeneratedFiles kann einen zweiten, schlimmeren Fehler erzeugen. Die generierte Datei anzusehen ist der richtige Reflex, aber wenn Sie zusätzlich CompilerGeneratedFilesOutputPath auf einen Ordner innerhalb des Projektverzeichnisses legen, wird die ausgegebene Datei beim nächsten Build zu einer echten Kompilierungseingabe:

Generated\...\OpenApiXmlCommentSupport.generated.cs(67,42):
error CS0433: The type 'XmlComment' exists in both 'Api' and 'Api'

Lassen Sie den Ausgabepfad unterhalb von obj, oder ergänzen Sie ein passendes <Compile Remove>.

Interceptors sind nicht das LangVersion-Problem, nach dem sie aussehen. Sie sind seit C# 12 zulässig, ein explizites <LangVersion>12.0</LangVersion> kompiliert die generierte Datei also problemlos, sobald der Namespace freigegeben ist. Suchen Sie den Fehler nicht in der Sprachversion.

Prüfen Sie den ganzen Graphen, nicht nur ein Projekt. Sobald Sie das im Fehler genannte Projekt korrigiert haben, scheitert oft das nächste Projekt weiter oben in der Kette beim nächsten Build genauso. dotnet msbuild <project> -getProperty:InterceptorsNamespaces über die Solution findet alle in einem Durchgang.

Verwandte Artikel

Der Generator hinter diesem Fehler ist dieselbe Maschinerie, die in was ein Source Generator ist und wann Sie einen brauchen beschrieben wird, und der Interceptor-Mechanismus selbst ist in Interceptors in C# 12 behandelt. Wenn Sie mitten in einem Upgrade hier gelandet sind: der andere Build-Bruch in dieser Paketfamilie ist der verschwundene Typ OpenApiReference, und der größere Umzug steht in von Swashbuckle zum eingebauten OpenAPI-Generator migrieren. Sobald das Dokument wieder kompiliert, ist die Anpassung mit Operation- und Schema-Transformern der nächste Schritt, und die Auslieferung mit Scalar setzt eine Oberfläche davor.

Quellen

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Zurück