dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.48k stars 10.04k forks source link

MapFallback catch all requests to API controller when ConsumeAttribute added #41060

Open Brainman643 opened 2 years ago

Brainman643 commented 2 years ago

Is there an existing issue for this?

Describe the bug

Hello. In .net 6 behavior of MapFallback broke when ConsumesAttribute was added. MapFallback catch all requests to API controller. In .net 6 index.html file always returns on requests to API controller but if I remove endpoints.MapFallbackToFile or delete ConsumesAttribute filter then everything works as I expected. In .net 5 the example works correctly.

ConsumesAttribute was added for the correct generation of swagger.json by Swashbuckle in order not to add it to every action or controller.

Expected Behavior

Requests to controllers must not be catched by MapFallback.

Steps To Reproduce

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers(options => options.Filters.Add(new ConsumesAttribute("application/json")));
        }
        public void Configure(IApplicationBuilder app)
        {
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapFallbackToFile("index.html");
            });
        }
    }

Exceptions (if any)

No response

.NET Version

6.0.200

Anything else?

No response

javiercn commented 2 years ago

@Brainman643 thanks for contacting us.

Here is what is happening.

I believe this is a side-effect of moving the Consumes to be evaluated earlier (as part of route matching via a matcher policy) during the request processing pipeline.

On .NET 5.0 there wasn't any accept policy, so any endpoint with [Consumes] attribute would match even if the content-type from the header was incompatible with the endpoint. Later on, the Consumes filter would take effect and generate the expected 415 response.

On .NET 6.0 we added and registered an AcceptsMatcherPolicy by default to evaluate this during routing for minimal APIs. As a result of this, evaluating the compatibility with the content type has moved earlier in the request pipeline and the endpoint is being discarded. Since the endpoint is being discarded, the fallback endpoint added for SPAs and Blazor Webassembly now gets selected instead.

You should be able to add this to your map fallback to file call to avoid the fallback from being matched in these situations

    endpoints.MapFallbackToFile("index.html").WithMetadata(new HttpMethodMetadata(new[] { "GET" }))
ghost commented 2 years ago

Thanks for contacting us. We're moving this issue to the .NET 7 Planning milestone for future evaluation / consideration. Because it's not immediately obvious that this is a bug in our framework, we would like to keep this around to collect more feedback, which can later help us determine the impact of it. 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.

tnlthanzeel commented 2 years ago

Is there an existing issue for this?

  • [x] I have searched the existing issues

Describe the bug

Hello. In .net 6 behavior of MapFallback broke when ConsumesAttribute was added. MapFallback catch all requests to API controller. In .net 6 index.html file always returns on requests to API controller but if I remove endpoints.MapFallbackToFile or delete ConsumesAttribute filter then everything works as I expected. In .net 5 the example works correctly.

ConsumesAttribute was added for the correct generation of swagger.json by Swashbuckle in order not to add it to every action or controller.

Expected Behavior

Requests to controllers must not be catched by MapFallback.

Steps To Reproduce

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers(options => options.Filters.Add(new ConsumesAttribute("application/json")));
        }
        public void Configure(IApplicationBuilder app)
        {
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapFallbackToFile("index.html");
            });
        }
    }

Exceptions (if any)

No response

.NET Version

6.0.200

Anything else?

No response

same issue for me too, is there a solution?

tnlthanzeel commented 2 years ago

@Brainman643 thanks for contacting us.

Here is what is happening.

I believe this is a side-effect of moving the Consumes to be evaluated earlier (as part of route matching via a matcher policy) during the request processing pipeline.

On .NET 5.0 there wasn't any accept policy, so any endpoint with [Consumes] attribute would match even if the content-type from the header was incompatible with the endpoint. Later on, the Consumes filter would take effect and generate the expected 415 response.

On .NET 6.0 we added and registered an AcceptsMatcherPolicy by default to evaluate this during routing for minimal APIs. As a result of this, evaluating the compatibility with the content type has moved earlier in the request pipeline and the endpoint is being discarded. Since the endpoint is being discarded, the fallback endpoint added for SPAs and Blazor Webassembly now gets selected instead.

You should be able to add this to your map fallback to file call to avoid the fallback from being matched in these situations

    endpoints.MapFallbackToFile("index.html").WithMetadata(new HttpMethodMetadata(new[] { "GET" }))

this solutioj doent work for me. is there anytging else to fix this?

javiercn commented 2 years ago

@Brainman643 can you explain what is not working for you in a separate issue?

(Include please a minimal repro project as a public gh repo).

MackinnonBuck commented 2 years ago

Done in #43984

davidfowl commented 2 years ago

Does this regress anything else? Is it a breaking change?

javiercn commented 2 years ago

@davidfowl very theoretically if you were requesting a SPA with a POST, PUT, etc. request, but that's not something that would affect any production scenario. The main scenario for this is to serve index.html in SPAs and Blazor.

We can add a small announcement for it, but I highly doubt it's a problem.

javiercn commented 2 years ago

We should keep the issue open, though as MacKinnon's fix reduces the impact, but does not remove the problem.

ghost commented 2 years ago

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.

javiercn commented 2 years ago

Note for triage:

davidfowl commented 2 years ago

Can we add the announcement and mark it as a breaking change?

javiercn commented 2 years ago

@davidfowl absolutely.

@MackinnonBuck can you take care of it?

MackinnonBuck commented 2 years ago

https://github.com/aspnet/Announcements/issues/495

tnlthanzeel commented 12 months ago

is this fixed?

omarceloribeiro commented 7 months ago

I got this issue in blazor web assembly .net core hosted. I created a api folder in controllers, then create my api controllers. so when I hit the url /api/products the .net core fallback to index.html resulting the a blazor web page respone "Sorry, there's nothing at this address."

oddly, when I open in InPrivate tab, or if I press control F5 the .net core works correctly and returns my api. also, if I access via HttClient (RestClient) it works in google chrome, but doesnt work in Firefox. the response is empty in firefox. edit: The HttpClient also works in Firefox if I open in InPrivate tab.

seems to be something with cookies, header and the serviceworker. weird

edit: found this error in console in anonymous tab Uncaught TypeError: navigator.serviceWorker is undefined

https://github.com/microsoft/TypeScript/issues/52044

maybe this is making the site work in anonymous tab 😆

Edit: in my case the problem in blazor wasm (with PWA enabled) was the serviceworker intercepting the api call on client side. just needed to customize the service-worker.publish.js to exclude the path /api/ I dont think it relates the open issue, but maybe can help someone with the same problem in blazor wasm :)

martinlingstuyl commented 6 months ago

I'm on .net 8 and same issue for me...