feat: generate OpenApiOptions extensions for ASP.NET Core OpenAPI (#704)
✨ Add code generation support for Microsoft.AspNetCore.OpenApi.OpenApiOptions
This PR implements issue #704: enabling automatic OpenAPI schema mapping for value objects via source generator.
✅ What’s included
- ✨ New feature: Generates a static method
MapVogenTypesIn{AssemblyName}(this OpenApiOptions)in aVogenOpenApiExtensionsclass. - 🧠 The method registers all Vogen value objects into
OpenApiOptions.AddSchemaTransformer, mapping their underlying types (e.g.,int,Guid) to OpenAPI schemas (e.g.,type: integer,format: int32). - 🧪 Verified compatibility with both nullable and non-nullable value objects.
- 🛠️ Integrated into
VogenGeneratorwith compile-time detection ofMicrosoft.AspNetCore.OpenApipresence. - ✅ All new tests pass. Current tests fail not due to my fault, checked on main branch too.
🧪 How to use
-
Add this line in your assembly:
[assembly: VogenDefaults(OpenApiSchemaCustomizations = OpenApiSchemaCustomizations.GenerateOpenApiMappingExtensionMethod)] -
In your Program.cs or Startup.cs:
options.MapVogenTypesInMyAssembly(); // Assembly name will vary
Example of generated code:
public static class VogenOpenApiExtensions
{
public static global::Microsoft.AspNetCore.OpenApi.OpenApiOptions MapVogenTypesInMyNotes_Contracts(this global::Microsoft.AspNetCore.OpenApi.OpenApiOptions options)
{
options.AddSchemaTransformer((schema, context, cancellationToken) =>
{
if (context.JsonTypeInfo.Type == typeof(global::MyNotes.Contracts.Notes.Requests.TestId))
{
schema.Type = "integer";
schema.Format = "int32";
}
if (context.JsonTypeInfo.Type == typeof(global::System.Nullable<MyNotes.Contracts.Notes.Requests.TestId>))
{
schema.Type = "integer";
schema.Format = "int32";
schema.Nullable = true;
}
return global::System.Threading.Tasks.Task.CompletedTask;
});
return options;
}
}
Thanks for the PR @amyboose - much appreciated! It looks great. It seems some of the tests are failing though. Happy to help fix if you need me.
I fixed some of the tests.
But I couldn't handle the snapshots. It looks like the snapshots are wrong. For example test Instance_names_can_have_reserved_keywords generates:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
while verified snapshot:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
And StructGenerator contains:
string GenerateCode() => $@"
{Util.WriteStartNamespace(item.FullNamespace)}
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""{Util.GenerateYourAssemblyName()}"", ""{Util.GenerateYourAssemblyVersion()}"")]
{Util.GenerateAnyConversionAttributes(tds, item)}
There is a problem with indents and I don’t understand why I generate an indent that is shorter in length than in verified snapshots.
I also noticed that somehow the version in GeneratedCodeAttribute in shapshots is magically always 1.0.0.0. I couldn't solve this problem in the usual way.
But I also suggest using an explicit indication to ignore the MinVer version in RunSnapshots.ps1 using -p:MinVerSkip=true:
if($reset)
{
WriteStage("... resetting snapshots before running them ...")
exec { & dotnet build Vogen.sln -c Release -p:MinVerSkip=true -p Thorough=true -p ResetSnapshots=true --no-restore --verbosity $verbosity}
}
else
{
WriteStage("... running snapshots ...")
exec { & dotnet build Vogen.sln -c Release -p:MinVerSkip=true -p Thorough=true --no-restore --verbosity $verbosity}
}
The Vogen.dll library always took the current version 8.0.0.0 from me. But it would be good if it ignored MinVer within the test environment. Something like:
<PropertyGroup>
<MinVerSkip Condition=" '$(MinVerSkip)' == '' and '$(MINVER_SKIP)' != '' ">$(MINVER_SKIP)</MinVerSkip>
</PropertyGroup>
As a result, I was able to make some of the tests work, but I couldn't cope with snapshots. So, please help in this regard. It would also be good if MivVer would automatically work correctly both in the IDE and in scripts.
Hi, thanks for looking at the fixes. One of the issues is my fault: there's a 'scrubber' for the snapshots that turns 8.0.0.0 into 1.0.0.0. Every time I do a major version number change, I forget to update this! Apologies for that. The indentation is irrelevant; Vogen formats the output (but I've seen been told by the Roslyn team that it shouldn't, so I'll probably change that at some point). I've just checked out the PR and I'm now resetting the snapshots. Everything should be OK then, so I'll add to this PR and then get it merged. Thanks again for your contribution! Much appreciated.
LGTM! Thank you!