Skip to content

IHostingEnvironment.IsDevelopment() lowering Request Size limit #9918

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

Closed
Frankwayne opened this issue May 2, 2019 · 13 comments
Closed

IHostingEnvironment.IsDevelopment() lowering Request Size limit #9918

Frankwayne opened this issue May 2, 2019 · 13 comments
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions

Comments

@Frankwayne
Copy link

I have posted this on stack overflow but no bites yet. I was wondering if anyone else has seen this behavior before.
https://stackoverflow.com/questions/55941369/ihostingenvironment-isdevelopment-lowering-request-size-limit

Here is a copy of my stackoverflow question below

I'm having an issue where using the method call IHostingEnvironment.IsDevelopment() is causing 413 to be thrown back by the web server. When I remove this call, My method works with the same request.

I'm not sure if it is somehow lowering the DefaultRequestSize limit of 30MB aspnet/Announcements#267

or if there is something else going on that I do not know about.

I have alleviated the problem by removing the IHostingEnviornment.IsDevelopment() call out of the ConfigureServices(IServiceCollection) method in my startup class by moving my custom service configuration into

ConfigureProductionServices(IServiceCollection) and ConfigureDevelopmentServices(IServiceCollection)

and removing the call to the IHostingEnvironment.ISDevelopment() but I want to know what is going wrong with the above method as it should be supported.

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-2.2

I have configured my Startup constructor to take the following input


  public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            // whatever else need to be coded for startup
            HostingEnvironment = env;
        }

where I call the env variable in my ConfigureSerivces method


public void ConfigureServices(IServiceCollection services)
{
   if (HostingEnvironment.IsDevelopment())
   {
           //Dev services added
   }
   else
  {
            // Prod services added
   }
}

The above configuration setup some how cause 413 to return from my web api calls when before they used to work.

I have worked around the issue with the issue with the following code methods


  public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            // whatever else need to be coded for startup
            HostingEnvironment = env;
}


  public void ConfigureDevelopmentServices(IServiceCollection services)
        {
           // Add Dev Services
            StartupConfigureServices(services);
        }

        public void ConfigureProductionServices(IServiceCollection services)
        {
         // Add Prod Services
            StartupConfigureServices(services);
        }

but I can't help the feeling that this will come back to bite me one day.

I can also use the follow attribute on my controller method to also fix this issue

[DisableRequestSizeLimit]
but it does have to be placed above the Route Attribute for some reason. I have no desire to use this fix as I feel its pretty unsafe, and I'm still clueless on what is going on.

I have place the following line of code in one controller and debugged the application with both startup designs but I still get a null value for both designs in my controller method call.

        var test = HttpContext.Features.Get<IHttpMaxRequestBodySizeFeature>().MaxRequestBodySize;
@Tratcher
Copy link
Member

Tratcher commented May 2, 2019

IsDevelopment only checks state, it doesn't change anything. What are you doing in //Dev services added?

I have place the following line of code in one controller and debugged the application with both startup designs but I still get a null value for both designs in my controller method call.

What is null? Get<IHttpMaxRequestBodySizeFeature>() or MaxRequestBodySize?

@Tratcher
Copy link
Member

Tratcher commented May 2, 2019

See #8293 for adding IHttpMaxRequestBodySizeFeature to IIS in-process.

@Frankwayne
Copy link
Author

@Tratcher

The property MaxRequestBodySize is null.

For the //Dev services Added I'm making
services.AddingSingleton<Interface, type>() calls

It looks like I was wrong, about how to cause the issue I'm facing. Apparently IIS Express is keeping my site running in the background and just replacing the binaries, which was giving me false positives. I can use the IHostingEnvironment.IsDevelopment() call and ConfigureDevelopmentServies(......) call, and they both give me the same behavior.

I was even wrong with the following attribute helping with the issue.

        [DisableRequestSizeLimit]

So I have two controllers with different endpoints

controller1/SmallRequestApi
controller2/BiggerRequestApi

On a fresh start where the IISExpress Site has been stopped completely, here is the behavior I'm seeing, in the order of my request calls.

controller2/BiggerRequestApi Return 413 status code *Note All Calls will fail with a 413 at this point **
controller1/SmallRequestApi Returns 200 status code
controller2/BiggerRequestApi Returns 200 status code

Normal behavior after this point.

------- Stop the web project but do not stop the IISExpress Site ----------------------

controller2/BiggerRequestApi Returns 200 status code
controller1/SmallRequestApi Returns 200 status code

Normal behavior after this point.

----------- If I stop the web project but not stop the IISExpress Site but wait awhile (like 5 minutes or so ----------

controller2/BiggerRequestApi Return 413 status code *Note All Calls will fail with a 413 at this point **
controller1/SmallRequestApi Returns 200 status code
controller2/BiggerRequestApi Returns 200 status code

Normal behavior after this point.


If I stop the IISExpress site for my local development and try this order of operations I get the following behavior

controller1/SmallRequestApi Returns 200 status code
controller2/BiggerRequestApi Returns 200 status code

Normal behavior after this point.

I have made a simple middle ware component to see which features are getting added where

       public void Configure(IApplicationBuilder app)
        {
            app.Use(async (context, next) =>
            {
                var features1 = context.Features;
                await next.Invoke();
                var features2 = context.Features;
            });

            app.ConfigureGlobalExceptionHandler();
            app.UseAuthentication();
//// another custom Middleware added
            app.UseMvc();

            var test = app.ServerFeatures;
            var test2 = test.IsReadOnly;
        }

The first call to the endpoint

controller2/BiggerRequestApi returned a 413 without hitting my breakpoints in my test middleware
controller1/SmallRequestApi Returns 200 status code able to hit the test middleware breakpoints
controller2/BiggerRequestApi returns 200 able to hit the test middleware breakpoints.

@Tratcher
Copy link
Member

Tratcher commented May 3, 2019

Can you share a minimal repro project with us?

@Frankwayne
Copy link
Author

I will attempt to do so but it may take some time to strip and replicate the issue out

@Frankwayne
Copy link
Author

@Tratcher

took a good bit of testing but here is a repo of the issue

https://github.com/Frankwayne/asp-net-core-413

there is a linqpad script in the scripts folder that you can use after you spin up the webserver.

Apparently it doesn't matter for the IISExpress reset. each run of the script output the 413 for the Large Request Message , then a 200 for the small request size, then 200 for each Large Request call

@Frankwayne
Copy link
Author

Strange using the Http paths appear to work just fine.

@Frankwayne
Copy link
Author

https://docs.microsoft.com/en-us/iis/configuration/system.webserver/serverruntime

It appears that it defaults to the serverruntime attribute value uploadReadAheadSize default value of
49152
checking the lenght of my byte array going over this value causes the behavior I'm seeing. A byte array lenght of 49152 works just fine on https. 49153 request size doesnt work until either of the behaviors

1 ) Small request size is send to other endpoint and 200
2) small request size is sent to same endpoint 413, Then the next large request size will work on the same endpoint.

Changing the attribute value in the .vs/config/applicationhost.config file does not appear to effect this behavior sadly.

It would appear that I need to add my own web.config file and then set this attribute. Since I'm using .Net Framework 4.7 instead of .net core my process is an out of memory process. This has solved my issue.

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/?view=aspnetcore-2.2

@Frankwayne
Copy link
Author

@Tratcher I'm not sure if you wish to consider this a bug or not

@Tratcher
Copy link
Member

Tratcher commented May 6, 2019

From your description this is an IIS behavior, not an Asp.Net behavior. I don't quite understand how it manifested in this way. @jkotalik @shirhatti

@Frankwayne
Copy link
Author

I'm not either. I think it has something to do with the reverse proxy that is being set up for an out of memory kestrel server. The reverse proxy may not know the settings on the kestrel server for the maximum request size until a request comes through. When that request comes through it set the settings for the kesetrel server to the IIS reverse proxy for that connection.

of course that is just a hypothesis.

@Tratcher
Copy link
Member

Tratcher commented May 6, 2019

IIS request size limits would be applied independently of Kestrel. If you hit the IIS limit then the request shouldn't reach Kestrel.

@Frankwayne
Copy link
Author

@Tractcher which is what I believe was happening. IIS was blocking my connection with 413, until an TCP connection was made with the server. At leas that is what I believed was happen with the linqpad script.

Each run of the linqpad script would throw a 413 so It wasn't just loading the configuration into the two server. Its like IIS express forgot the setting on each run and would block until a connection was made then somehow allow in my larger sized payloads

@ghost ghost locked as resolved and limited conversation to collaborators Dec 3, 2019
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
Projects
None yet
Development

No branches or pull requests

4 participants