Skip to content
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

Incorrect OpenAPI schema generated for implicit services/special types/parseables #44677

Open
1 task done
martincostello opened this issue Oct 21, 2022 · 12 comments
Open
1 task done
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc

Comments

@martincostello
Copy link
Member

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I'm working on a talk I'll be giving soon on new features in ASP.NET Core 7 and Minimal APIs, and in the process of updating my sample application for RC2 I've noticed a number of issues with the OpenAPI schema generated for various endpoints in the sample.

  1. Using implicit service resolution for an MVC controller renders the service as an object in the OpenAPI schema and as a query string parameter.

image

image

  1. Using TryParse() support for parameters for an MVC controller has a similar issue, and renders the query string parameter as an object mirroring the C# model, rather than as a string.

image

image

  1. Using the support for Stream and PipeReader to consume the request body shows both Stream and PipeReader in the schema.

image

image

Expected Behavior

  1. MyService is not shown as an endpoint parameter and is not included in the OpenAPI schemas.
  2. The name parameter is shown as a simple string and Name is not included in the OpenAPI schemas.
  3. Stream and PipeReader are not included in the OpenAPI schemas.

Steps To Reproduce

  1. Clone the martincostello/aspnet-core-7-samples repository.
  2. Build and run the application.
  3. View the rendered OpenAPI schema with Swagger UI at https://localhost:5001/swagger-ui/index.html.

Exceptions (if any)

None.

.NET Version

7.0.100-rc.2.22477.23

Anything else?

> dotnet --info
.NET SDK:
 Version:   7.0.100-rc.2.22477.23
 Commit:    0a5360315a

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22000
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\7.0.100-rc.2.22477.23\

Host:
  Version:      7.0.0-rc.2.22472.3
  Architecture: x64
  Commit:       550605cc93
@captainsafia
Copy link
Member

Great sample app! Thanks for putting it together.

Using implicit service resolution for an MVC controller renders the service as an object in the OpenAPI schema and as a query string parameter.

It looks like the ApiExplorer is producing an ApiParameterDescription for the service parameter and it ends up being treated as a query parameter by the fallback logic in Swashbuckle. I'm not totally familiar with MVC's model binding logic but my suspicion is that we'll have to update this to not generate a parameter description for parameters that might be implicit services. Paging @brunolins16 for model binding insights.

Using TryParse() support for parameters for an MVC controller has a similar issue, and renders the query string parameter as an object mirroring the C# model, rather than as a string.

I suspect the same thing happening for services is happening here. We need to update the pseudo-model binding logic in the ApiExplorer to match the new behavior in MVC.

Using the support for Stream and PipeReader to consume the request body shows both Stream and PipeReader in the schema.

We're using Swahsbuckle's schema generator here (see this PR). It looks like the schema generator does not support generating schemes for those two types yet...

@brunolins16
Copy link
Member

  1. Using implicit service resolution for an MVC controller renders the service as an object in the OpenAPI schema and as a query string parameter.

@martincostello implicit service resolution, as all other implicit source resolution, are enable by default for API Controllers only, so you need to add the ApiControllerAttribute and this should be fixed

@brunolins16
Copy link
Member

I suspect the same thing happening for services is happening here. We need to update the pseudo-model binding logic in the ApiExplorer to match the new behavior in MVC.

A type with TryParse is consider Simple Type and Metadata.IsComplexType should be false and report it correctly. Let me take a further look at how this code works to see if I can understand what I happening.

martincostello added a commit to martincostello/aspnet-core-7-samples that referenced this issue Oct 22, 2022
@martincostello
Copy link
Member Author

Confirmed that adding [ApiController] fixed item 1.

martincostello added a commit to martincostello/Swashbuckle.AspNetCore that referenced this issue Oct 22, 2022
Do not generate schema models for `Stream` and `PipeReader`.
See dotnet/aspnetcore#44677 (comment).
@martincostello
Copy link
Member Author

@captainsafia Do you think this is the right fix for item 3, or have I got the best representation for the data here completely wrong and it just "fixes it" by accident?

domaindrivendev/Swashbuckle.AspNetCore@master...martincostello:Swashbuckle.AspNetCore:handle-stream-and-pipereader

Testing locally, Stream and PipeReader stop being returned in the schema with these changes.

image

@martincostello
Copy link
Member Author

@brunolins16 I had a quick look at the code. I didn't fully dig through and understand it all, but I wondered if this line needs changing to use string for the type if IsParseableType is true?

UnderlyingOrModelType = Nullable.GetUnderlyingType(ModelType) ?? ModelType;

- UnderlyingOrModelType = Nullable.GetUnderlyingType(ModelType) ?? ModelType;
+ UnderlyingOrModelType = IsParseableType ? typeof(string) : Nullable.GetUnderlyingType(ModelType) ?? ModelType;

@brunolins16
Copy link
Member

@brunolins16 I had a quick look at the code. I didn't fully dig through and understand it all, but I wondered if this line needs changing to use string for the type if IsParseableType is true?

UnderlyingOrModelType = Nullable.GetUnderlyingType(ModelType) ?? ModelType;

- UnderlyingOrModelType = Nullable.GetUnderlyingType(ModelType) ?? ModelType;
+ UnderlyingOrModelType = IsParseableType ? typeof(string) : Nullable.GetUnderlyingType(ModelType) ?? ModelType;

I think is not possible to simply change it because it might affect the binding logic. However we might be able to apply the same idea in the API Explorer but we will need to think how can we differentiate from primitives (int, bool, etc.).

I need to check what we are doing for Minimal Endpoints.

BTW: Types with Type Converter have the same problem

@brunolins16
Copy link
Member

@martincostello Maybe we can do the same as here IsPrimitive:

var displayType = !parameter.ParameterType.IsPrimitive && Nullable.GetUnderlyingType(parameter.ParameterType)?.IsPrimitive != true
? typeof(string) : parameter.ParameterType;

I will do some experiments and create a PR if it works. Thanks for reporting this bug.

@brunolins16 brunolins16 self-assigned this Oct 24, 2022
@brunolins16
Copy link
Member

I give it a try but, if I got it correctly, IsPrimitive is based on the CorElementType that means some types will not be covered (that probably make sense for OpenAPI), eg. decimal or guid, and will be reported as string. That is probably the cause of #39886

@captainsafia
Copy link
Member

@captainsafia Do you think this is the right fix for item 3, or have I got the best representation for the data here completely wrong and it just "fixes it" by accident?

domaindrivendev/Swashbuckle.AspNetCore@master...martincostello:Swashbuckle.AspNetCore:handle-stream-and-pipereader

Testing locally, Stream and PipeReader stop being returned in the schema with these changes.

image

I think that should be sufficient given the version of OpenAPI schema that Swashbuckle is currently targeting. I went down a bit of a rabbit hole trying to figure out what the best type/format to use is given the different OAS versions but this seems to be appropriate for v3.0.

@martincostello
Copy link
Member Author

Great, thanks for looking @captainsafia - I'll open a PR against Swashbuckle with that change shortly 👍

@ghost
Copy link

ghost commented Oct 27, 2022

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@brunolins16 brunolins16 removed their assignment Feb 24, 2023
@captainsafia captainsafia added area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc and removed area-web-frameworks labels Jun 20, 2023
@dotnet-policy-service dotnet-policy-service bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@wtgodbe wtgodbe removed the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@dotnet-policy-service dotnet-policy-service bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@wtgodbe wtgodbe removed the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 13, 2024
@dotnet dotnet deleted a comment from dotnet-policy-service bot Feb 13, 2024
@dotnet dotnet deleted a comment from dotnet-policy-service bot Feb 13, 2024
martincostello added a commit to martincostello/Swashbuckle.AspNetCore that referenced this issue Apr 13, 2024
Do not generate schema models for `Stream` and `PipeReader`.
See dotnet/aspnetcore#44677 (comment).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc
Projects
No open projects
Status: No status
Development

No branches or pull requests

6 participants