aspnet-api-versioning icon indicating copy to clipboard operation
aspnet-api-versioning copied to clipboard

Does .NET 9's OpenApi support render this obsolete?

Open armanossiloko opened this issue 1 year ago • 15 comments
trafficstars

In the recently released .NET 9, there's built in support for generating openapi documents. However, these documents have to be predefined by specifying services.AddOpenApi();.

This means that all API document names have to be defined in advance before the IServiceProvider is even built. This seems to totally "break" the flow of the Asp.Versioning.Mvc.ApiExplorer package. If I am not wrong, it was Microsoft themselves who delegated the original Microsoft.AspNetCore.Mvc.Versioning to the community which ended up turning into this aspnet-api-versioning.

Since documents have to be known in advance now and this package was basically providing an IApiVersionDescriptionProvider in runtime, does .NET 9's default OpenApi document generation render aspnet-api-versioning obsolete? None of what Micorosft provided with .NET 9 seems to display proper versioning support at all, just some different ways to generate documents at build time. Is there a way to integrate this with .NET 9's default OpenApi support now or am I missing something here?

armanossiloko avatar Nov 16 '24 18:11 armanossiloko

@armanossiloko There was a little bit of conversation around this issue when I took a stab at updating our eShop sample app, which uses ASP.NET versioning, to use the new OpenAPI package in https://github.com/dotnet/eShop/pull/360#discussion_r1594822030. Ultimately, the (ugly) resolution that we landed on in that PR is to declare the versions up front as you mentioned.

At the time, @commonsensesoftware mentioned having some ideas around API changes to make in Asp.Versioning to support easier resolution of documents. I think I also recall some ideas thrown around for an AddVersionedOpenApi API that would encapsulate the document registration and the versioning pattern in one.

captainsafia avatar Nov 25 '24 20:11 captainsafia

@captainsafia Thanks for digging that up and refreshing my memory.

@armanossiloko at this very moment I don't have a working example I can show. What you should need to do is use a IConfigureOptions or IPostConfigureOptions on OpenApiOptions where you inject IApiVersionDescriptorProvider and append the necessary entries. This is effectively the same process that is used with Swashbuckle (which you can see here). I haven't tried it myself, but that should work. I'm actively working on getting a release ready for .NET 9. Thanks for bringing this up. I will look into providing an out-of-the-box integrated solution or, at least, provide an end-to-end example that shows all of the pieces working with the new library. If you find any other sharp edges with what's possible right now, feel free to share or post an issue.

"If I am not wrong, it was Microsoft..."

Actually, you'd be wrong, but that's ok. It's common misunderstanding. I've always been the sole owner, maintainer, documenter, etc of API Versioning. I was once a Microsoft employee so in that sense it was Microsoft. When I left, the transition was less than smooth. There was a lot of things that had to change such as moving the project under the .NET Foundation and renaming packages. All that being said, I've had, and continue to have, a good working relationship with the ASP.NET team, but I've never been part of the team and they've never been co-owners of API Versioning - despite the name. I hope that clears that up. 😉

commonsensesoftware avatar Nov 25 '24 22:11 commonsensesoftware

What you should need to do is use a IConfigureOptions or IPostConfigureOptions on OpenApiOptions where you inject IApiVersionDescriptorProvider and append the necessary entries.

Looking at the source code for OpenApi, I'm pretty certain you can't do this. AspNetCore adds keyed singleton services keyed by the API name, and registers multiple OpenApiOptions instances, again keyed by API name. Happy to be proven wrong, but I don't think the above will work. See https://github.com/dotnet/aspnetcore/blob/main/src/OpenApi/src/Extensions/OpenApiServiceCollectionExtensions.cs#L55

robertcoltheart avatar Nov 26 '24 00:11 robertcoltheart

The eShop demo app uses Asp.Versioning to implement versioning for its Catalog API and I just updated it to add a new API version. There is the small disconnect that AddOpenApi wants the document names to be supplied "up front", but I worked around that by just ensuring that I used names that match the names expected by Asp.Versioning. Not perfect but it does work and I think the failure cases would be immediately apparent.

mikekistler avatar Jan 24 '25 00:01 mikekistler

The eShop demo app uses Asp.Versioning to implement versioning for its Catalog API and I just updated it to add a new API version. There is the small disconnect that AddOpenApi wants the document names to be supplied "up front", but I worked around that by just ensuring that I used names that match the names expected by Asp.Versioning. Not perfect but it does work and I think the failure cases would be immediately apparent.

Thanks! It still sucks a lot that we have to go some hacky route to get it working, but it is what it is.

armanossiloko avatar Jan 26 '25 01:01 armanossiloko

Image

Jesus Christ it took 2 hours to migrate to .NET 9 while maintaining versioning support and upgrading to the latest bells and whistles (Scalar).

elibroftw avatar Feb 03 '25 02:02 elibroftw

Image

Jesus Christ it took 2 hours to migrate to .NET 9 while maintaining versioning support and upgrading to the latest bells and whistles (Scalar).

:D It takes quite some effort. Not a fan of it myself either. Sadly, the "workflow" has become just harder and worse this way.

armanossiloko avatar Feb 03 '25 13:02 armanossiloko

So currently this library does not support OpenApi as implemented in dotnet 9?

runxc1 avatar Mar 10 '25 15:03 runxc1

You can use this library with the OpenAPI document generation support in .NET 9. See my earlier comment on how I implemented it in the eShop demo app.

mikekistler avatar Mar 10 '25 15:03 mikekistler

You can use this library with the OpenAPI document generation support in .NET 9. See my earlier comment on how I implemented it in the eShop demo app.

I have also updated my blog post to show the full picture including the use of scalar instead of swagger.

elibroftw avatar Mar 10 '25 16:03 elibroftw

You can use this library with the OpenAPI document generation support in .NET 9. See my earlier comment on how I implemented it in the eShop demo app.

I have also updated my blog post to show the full picture including the use of scalar instead of swagger.

How to optimize string[] versions = ["v1", "v2"]; This line of code, Previously, Swagger could automatically cycle through all version numbers in an interface.

ShenHaoCore avatar May 16 '25 09:05 ShenHaoCore

How to optimize string[] versions = ["v1", "v2"]; This line of code

If you are using ApiVersionAttribute I guess you could retrieve them at startup with reflection.

pyce-lb avatar May 17 '25 01:05 pyce-lb

You can use this library with the OpenAPI document generation support in .NET 9. See my earlier comment on how I implemented it in the eShop demo app.

I have also updated my blog post to show the full picture including the use of scalar instead of swagger.

I'm wondering if this is something we could add "as is" to Asp.Versioning? Something like: builder.Services.AddOpenApiWithVersioning(opt => { ... });

pyce-lb avatar May 17 '25 02:05 pyce-lb

You can use this library with the OpenAPI document generation support in .NET 9. See my earlier comment on how I implemented it in the eShop demo app.

I have also updated my blog post to show the full picture including the use of scalar instead of swagger.

For anyone trying this approach, setting GroupNameFormat is necessary.

// the default format will just be ApiVersion.ToString(); for example, 1.0.
// this will format the version as "'v'major[.minor][-status]"
builder.AddApiExplorer(options => options.GroupNameFormat = "'v'VVV");

I couldn't figure out why this is the case. My guess was/is something is looking for the 'v' prefix, but I could only make it work with 'v'VVV and 'v'V formats, but not with 'v'VV (I used versions 1.0 and 2.0 in my setup).

pyce-lb avatar May 19 '25 19:05 pyce-lb

I'm actively working on getting a release ready for .NET 9. Thanks for bringing this up. I will look into providing an out-of-the-box integrated solution or, at least, provide an end-to-end example that shows all of the pieces working with the new library.

Is this something you are still working on @commonsensesoftware? Any way I can help? I could maybe add this approach to the examples for you to review?

pyce-lb avatar May 19 '25 19:05 pyce-lb