| File: AtsGoApiReferenceExporter.cs | Web Access |
| Project: src\src\Aspire.Hosting.CodeGeneration.Go\Aspire.Hosting.CodeGeneration.Go.csproj (Aspire.Hosting.CodeGeneration.Go) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; using Aspire.TypeSystem; namespace Aspire.Hosting.CodeGeneration.Go; /// <summary> /// Exports the canonical Go API reference for the surface <see cref="AtsGoCodeGenerator"/> generates. /// </summary> /// <remarks> /// <para> /// This deliberately lives on its own type rather than on <see cref="AtsGoCodeGenerator"/>. /// <c>Aspire.TypeSystem</c> is force-shared from the apphost server's default /// <see cref="System.Runtime.Loader.AssemblyLoadContext"/> (see /// <c>src/Aspire.Hosting.RemoteHost/IntegrationLoadContext.cs</c>) and freezes its strong-name /// <c>AssemblyVersion</c> at a constant so an older CLI still binds a newer SDK's codegen assembly. /// Version binding therefore succeeds, but an older CLI's bundled copy has no /// <see cref="IApiReferenceExporter"/> in it: the interface is new. A type's interface list is /// resolved eagerly when the type loads, so putting the interface on the code generator would make /// the generator itself unloadable under any CLI that predates the interface, and /// <c>CodeGeneratorResolver</c> would then find no Go generator at all — Go generation, not just /// export, would stop working. /// </para> /// <para> /// Keeping export on a separate type confines that loss to the feature the older CLI cannot use /// anyway: <c>CodeGeneratorResolver</c> salvages the loadable types out of the /// <see cref="System.Reflection.ReflectionTypeLoadException"/>, so the generator survives and only /// this type disappears. /// </para> /// </remarks> internal sealed class AtsGoApiReferenceExporter : IApiReferenceExporter { /// <inheritdoc /> public string Language => "Go"; /// <inheritdoc /> public JsonElement ExportApi( AtsContext context, ApiReferenceExportOptions options, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(context); ArgumentNullException.ThrowIfNull(options); cancellationToken.ThrowIfCancellationRequested(); // Project through the generator itself, so the exported documentation describes the names, // types and signatures generation would emit rather than a second, independently derived // reading of the ATS context. Names are resolved over the context passed in, which holds the // exported package and the types it references, so an app host that combines more integrations // can qualify a name that is bare here. The generator keeps per-run name state, so every // export uses a fresh instance. var model = new AtsGoCodeGenerator().BuildApiModel( context, options.PackageName, options.PackageVersion, options.ExportingAssemblyNames, cancellationToken); // JsonDocument.Parse + Clone rather than JsonSerializer, because this assembly is // AOT-compatible and the serializer's reflection-based overloads are not. using var document = JsonDocument.Parse(GoApiExportWriter.WriteToJson(model)); return document.RootElement.Clone(); } }