Skip to content

[Minimal APIs] async handlers with single HttpContext parameter are not working #45373

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

Open
1 task done
gurustron opened this issue Nov 30, 2022 · 11 comments
Open
1 task done
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc
Milestone

Comments

@gurustron
Copy link
Contributor

gurustron commented Nov 30, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

It seems that issue described in #39956 was not fixed but even got worse - Minimal APIs handler with single param of type HttpContext results in empty response.

app.MapPost("testpost_works", async (HttpContext context, CancellationToken ct) => await Task.FromResult(context.Request.Method + " response"));
app.MapPost("testpost_fails", Handler);
app.MapGet("testget_works", async (HttpContext context, CancellationToken ct) => await Task.FromResult(context.Request.Method + " response"));
app.MapGet("testget_fails1", async (HttpContext context) => await Task.FromResult(context.Request.Method + " response"));
app.MapGet("testget_fails2", Handler);

async Task<string> Handler(HttpContext context) => await Task.FromResult(context.Request.Method + "response");

Endpoints suffixed fails return empty result while others return "VERB response"

In addition only "works" endpoints are recognized by swagger:

image

Expected Behavior

All endpoints return "VERB response"

Steps To Reproduce

Use Minimal APIs defined above.

Exceptions (if any)

No response

.NET Version

7.0.100

Anything else?

dotnet --info
.NET SDK:
Version: 7.0.100
Commit: e12b7af219

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\

@gurustron gurustron changed the title [Minimal APIs] Single HttpContext parameter handlers are not workings [Minimal APIs] async handlers with single HttpContext parameter are not working Nov 30, 2022
@javiercn javiercn added the old-area-web-frameworks-do-not-use *DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels label Dec 1, 2022
@captainsafia
Copy link
Member

captainsafia commented Dec 1, 2022

Triage: This behavior is a result of the change introduced in this PR.

We introduced an analyzer for this in .NET 8 at #44048 that we should consider backporting to .NET 7. @JamesNK Thoughts on backporting this?

The PR above backports a runtime fix that was addressed in #39956.

Note: this runtime behavior also exists in .NET 6.

@captainsafia
Copy link
Member

Addendum: at least for the OpenAPI-related aspects we are tracking this via #44970.

@captainsafia captainsafia added this to the 7.0.x milestone Dec 8, 2022
@eerhardt
Copy link
Member

eerhardt commented Dec 8, 2022

My understanding of https://github.com/dotnet/aspnetcore/pull/42519/files#diff-f8807c470bcc3a077fb176668a46df57b4bb99c992b6b7b375665f8bf3903c94L202-L207 is that we were doing "trim unsafe" behavior before that change - specifically we would JSON serialize the T value of Task<T>. That's not a warning we can suppress because if the app didn't enable JSON source generation, trimming will change the behavior here.

So in this case, the options I see are:

  1. Marking the API as RequiresUnreferencedCode
  2. Removing the behavior (what Remove RequiresUnreferencedCode from low-level endpoint map methods #42519 did)
  3. Adding an analyzer that warns specifically for this situation saying that it is not trim safe, and then suppressing the warning in our code.
    • Or resolving the JSON serialization trimming issue in ASP.NET all up, and then suppressing the warning in our code.

@JamesNK
Copy link
Member

JamesNK commented Dec 8, 2022

@JamesNK Thoughts on a partial revert of #42519 (files)?

cc: @eerhardt

I'm against reverting the change. These low-level methods are used by app frameworks, e.g. gRPC, and app frameworks should have a simple way to add endpoints that doesn't create warnings.

I don't have a problem with backporting the analyzer #44048

@g-jozsef
Copy link

g-jozsef commented Jan 25, 2023

A workaround (at least for .net 7.0.100) is to force the type to be a simple Delegate instead of a RequestDelegate (for functions with a single HttpContext param)

public async Task<....> TestFunction(HttpContext http)
Delegate d = TestFunction;
builder.MapGet("/some-endpoint", d)

Response body is populated correctly with all headers, and it even shows up in the generated openapi docs

@gurustron
Copy link
Contributor Author

@g-jozsef yes it is either casting to "correct" type or adding a parameter, for example CancelationToken.

@captainsafia captainsafia added area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc and removed old-area-web-frameworks-do-not-use *DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels labels Jun 20, 2023
@LeonSpors
Copy link

@g-jozsef yes it is either casting to "correct" type or adding a parameter, for example CancelationToken.

Thank you for the workaround! I've tested it, and it works perfectly. I appreciate your help.
Do you believe it's advisable to incorporate a cancellation token in every asynchronous request across all scenarios?

@captainsafia
Any updates on when we can expect a fix for this issue?

@captainsafia
Copy link
Member

@g-jozsef yes it is either casting to "correct" type or adding a parameter, for example CancelationToken.

Thank you for the workaround! I've tested it, and it works perfectly. I appreciate your help. Do you believe it's advisable to incorporate a cancellation token in every asynchronous request across all scenarios?

@captainsafia Any updates on when we can expect a fix for this issue?

At the moment, I don't believe that we would do anything to change the overload behavior here. This issue occurs because the compiler favors the RequestDelegate overload of the MapX methods when the provided handler takes a single HttpContext and returns a Task. Adding a cast or an additional parameter changes the signature of the delegate and the compiler will pick the MapX(Delegate handler) overload in those scenarios. I think requiring an explicit cast is sufficient in those scenarios.

@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
@ghord
Copy link

ghord commented May 3, 2024

Woudn't it be better to partially revert Map as suggested by @captainsafia and introduce new method such as MapTrimSafe for gRPC and other app frameworks? Frameworks can move to more verbose name of the method without impacting users. It is easy to trip over this for beginners...

@bjornen77
Copy link
Contributor

@g-jozsef yes it is either casting to "correct" type or adding a parameter, for example CancelationToken.

Thank you for the workaround! I've tested it, and it works perfectly. I appreciate your help. Do you believe it's advisable to incorporate a cancellation token in every asynchronous request across all scenarios?
@captainsafia Any updates on when we can expect a fix for this issue?

At the moment, I don't believe that we would do anything to change the overload behavior here. This issue occurs because the compiler favors the RequestDelegate overload of the MapX methods when the provided handler takes a single HttpContext and returns a Task. Adding a cast or an additional parameter changes the signature of the delegate and the compiler will pick the MapX(Delegate handler) overload in those scenarios. I think requiring an explicit cast is sufficient in those scenarios.

Would it be possible to use the new C#13 OverloadResolutionPriorityAttribute to solve this?
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13#overload-resolution-priority

@captainsafia @JamesNK

@mkArtakMSFT mkArtakMSFT modified the milestones: 7.0.x, Backlog Oct 30, 2024
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
None yet
Development

No branches or pull requests