-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add IDocumentProvider
service and its implementation
#1658
Conversation
{ | ||
} | ||
|
||
public IEnumerable<Type> ControllerTypes { get; private set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
think we should support only the AspNetCoreToSwaggerGenerator and ignore the Web API (legacy) generator. I think this property would not be needed this way...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🆗
🆙📅d to address your comments @RSuter. I look forward to any alternative suggestions or further thoughts you have. |
{ | ||
// This service will be looked up by name from the service collection when using | ||
// the Microsoft.Extensions.ApiDescription tool | ||
public interface IDocumentProvider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this interface is the only public API which is relevant for you, is this correct?
Shouldn't it be renamed to IOpenApiDocumentProvider or also use a document type enum - because there might be other document types in the future and we maybe should be more specific about the document type it generates?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to be public
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a contract that we're implementing via late binding - it's not going to have types like enums - because there's no library. It's a way for us to consume a document in a generic way.
If you want a different abstraction for inside NSwag that sounds good, but it's not what we will consume.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, if we can make it internal and it doesnt give name collisions problems with other libraries (e.g. Swashbuckle in the same app) I think it's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🆙📅
@dougbu is this now ready to be merged? |
It won't harm anything to merge this (though squashing the 10 commits might help 😃. But, based on our offline thread about the |
@dougbu I made a PR against the branch in this PR, dougbu#1 I think this should cover scenario 3 (change middleware api). Is this ok and will work with your other code? Open task: Update wiki here: https://github.com/RSuter/NSwag/wiki/Middlewares |
@RSuter well, I was just testing the changes I'd made. I'll push to my remote branch so that you can compare and contrast… |
2da52e8
to
a13c550
Compare
🆙📅 @RSuter other than WIP items mentioned in the top top commit, the main thing I haven't done but is recommended is switch to the FYI @rynowak |
I'm now trying to merge all my work but it's now a big mess. But there are main problems:
Will update my PR against your PR soon. |
Because users may want to configure the first, possibly only, document.
I tried that approach but found it falls down because the UI middleware needs to know where the generator middleware is hosted. But, this will be much simpler to do once I move to an
🆗 though I'm not quite sure I understand the concern. All middleware in my approach handles all the documents. Well, except the Redoc UI one. Names are primarily important for routing and the
Sure. |
@@ -0,0 +1,19 @@ | |||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I look again at the existing samples, this one isn't needed. And, I started with the wrong template here, ignoring the lack of actual APIs exposed and bulking the project up with irrelevant files.
using NSwag.AspNetCore.Middlewares; | ||
using NSwag.SwaggerGeneration.AspNetCore; | ||
|
||
namespace Microsoft.Extensions.DependencyInjection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The namespace here is very important. Users should be able to do mainline scenarios as soon as they add the NSwag.AspNetCore package to their project. No need to add a using NSwag.*
statement in their Startup
class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without a call to AddSwagger() the interface will not be registered and thus the whole thing wont work, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a different concern. Everything fails nice and loudly when AddSwagger()
is not called but the Use*(...)
methods are.
I think this API is really confusing because AddOpenApi() and AddDocument() are doing the same but have a different name... That's why I'd like to have this nested configuration, i.e. AddOpenApi() adds the required services and AddDocument (as in Like this one:
I think it should be like this in a common scenario (simplest case): AddSwagger() // registers services This way each call has its own defined responsibility...
How should this solve this structural problem? Can you give an example? |
And let's not use OpenApi in the method and stick with Swagger for now... otherwise it gets really confusing because OpenApi does not enforce OpenAPI v3.0 and v2.0 is still supported so we have two methods which should do the same but internally dont (one registers the services the other doesnt). |
Not quite.
That will work fine using my approach as well. The Users will be able to mess themselves up by calling
Users would be able to stick with the usual ASP.NET Core configuration patterns. (MVC and EF get a bit more complicated because they aren't themselves exposed as middleware.) For example, services.AddSwagger();
services.Configure<SwaggerMiddlewareOptions>(o => o.SwaggerRoute = "/openApi/{documentName}/swagger.json");
services.Configure<SwaggerUi3Options>(o => o.SwaggerUiRoute = "/myUi"); then the |
This is really bad as you can have only one SwaggerMiddlewareOptions or SwaggerUi3Options option... What if I need two Swagger UIs? |
… also SwaggerMiddlewareOptions has a PostProcess (Action(request, document)) which cannot be specified per document this way... |
Yes, but Swashbuckle does it the same way - and I'd rather trade this problem for more flexibility. If you don't change the routes it just works - otherwise you have to be aware that you can misconfigure the thing... For me these (AddSwagger, UseSwagger and UseSwaggerUi) are 3 different services... you can use UseSwaggerUi without the other two (e.g. with an external spec) |
Ok. |
f388a2e
to
bbf9e37
Compare
- RicoSuter#1626 - does not "provide an api to generate multiple / all documents"; could be layered on this work - otherwise, meets requirements listed in RicoSuter#1626 - assumes the following answers to open questions in RicoSuter#1626 (generally means everything is opt-in) - without an `AddSwagger()` call, `IDocumentProvider` service will not exist - registered document name / identifier is new `SwaggerSettings<>.DocumentName` property - document is not registered unless `DocumentName` is non-`null` i.e. `IDocumentProvider` won't know about it - `SwaggerSettings<>.MiddlewareBasePath` and `SwaggerRoute` are independent of `DocumentName` - middleware does not depend on the `IDocumentProvider` or registrar services; duplicating some code - many thanks to @rynowak for writing this proposal
…umentProvider` - remove some code from files added in 5b7e0a3b34 - revert changes made in 5b7e0a3b34 to existing files
- `internal` again - commit 4057107.
…s(...)` - add NSwag.Sample.OpenApi project - rework bd9c7fc; revert part of that commit e.g. undo `SwaggerExtensions` changes nit: - correct doc comment for `AspNetCoreToSwaggerGeneratorSettings` WIP: - some doc comments are currently empty - names are tentative
- move `PostProcess` document from `SwaggerDocumentSettings` to `SwaggerMiddlewareOptions` - adjust `SwaggerDocumentProvider` to match, breaking some `IDocumentProvider` scenarios (!!) - rename a few classes to use "Swagger" more - split extensions into type-specific classes with appropriate namespaces - fix `SwaggerMiddlewareOptions.SwaggerRoute` being invalid from a Microsoft.AspNetCore.Routing perspective - change `SwaggerBuilderExtensions` to support creating documents with `SchemaType.OpenApi3` default - change `SwaggerApplicationBuilderExtensions` to - split `UseSwagger(...)` from `UseSwaggerReDocUi(...)` and `UseSwaggerUi4(...)` - add UI middleware supporting a single `documentName` "Reviewers:" comments ask make suggestions for future improvements / extensions and ask for better names
bbf9e37
to
2f71924
Compare
…to `SwaggerMiddlewareOptions.PostProcess`
🆙📅 only remaining WIP bits are a couple of names and a few empty doc comments. From my perspective, this PR has the following advantages:
|
@RSuter please note the "Reviewers" comments in a few files |
I updated my PR to support {documentName} and decided to merge this in...
Some cleanup can only be done when removing features (WebApi generator middleware etc.), see #984 I hope this is ok for you? And I'm really sorry for all this back and forth... but I really need to move on and work on other issues - we already lost too much time here... |
@RSuter yes, this is fine. Much better than fine: You've now got an I was somewhat sorry to see the middleware pipeline still contains multiple One more real concern, echoing my earlier "supports post-processing in |
You are right, this also bothers me. The following code is actually not executed when running via command line: The idea is that the PostProcess here should only be used to change BasePath, Schemes and Host based on the request, but of course it cannot be enforced. How would you proceed?
Yes, exactly - you should use a custom document processor for that - but you don't have access to a request there (because a spec is independent of an actual HTTP request). |
If it were me, this is the route I'd go because adjusting these values to match the request is so useful. Suggest also mentioning the processing order of Separately, including all schemes, hosts and
Reasonable. In retrospect, the main thing my trial addition of a |
Yes, but I don't like having two concepts (document processors and postprocess) for the same scenario... we could just provide a generic
Ok, then we'll do that. But in the case of using the command line you need to define these properties via config anyway so why not force it also for the hosted scenario?
Good point. |
I'm missing something. Force what? If you mean forcing use of config, aren't |
I meant force the user to load the host, schemes etc from the config (eg appsettings.json) so that it works in the host scenario and cli scenario.. but this might upset users :-) |
I agree setting the document properties statically would be a regression. After talking more internally, I'm sorry to say the |
IDocumentProvider
interface and service implementing it #1626IDocumentProvider
interface and service implementing it #1626IDocumentProvider
interface and service implementing it #1626 (generally means everything is opt-in)AddSwagger()
call,IDocumentProvider
service will not existSwaggerSettings<>.DocumentName
propertyDocumentName
is non-null
i.e.IDocumentProvider
won't know about itSwaggerSettings<>.MiddlewareBasePath
andSwaggerRoute
are independent ofDocumentName
IDocumentProvider
or registrar services; duplicating some code