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

IFeatureCollection has been disposed when trying to access HttpContext.Request.Headers #20551

Closed
Jasdo opened this issue Apr 5, 2020 · 7 comments
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update.

Comments

@Jasdo
Copy link

Jasdo commented Apr 5, 2020

Steps to reprodce

  1. Create a simple API ASP.NET Core 3.1 Web Application using Visual Studio 2019 template.
  2. In the handler method, add access to HttpContext.Request.Headers.
  3. Create a REST client that sends many requests simultaneously.

The result is that eventually, a System.ObjectDisposedException will be thrown upon accessing HttpContext.Request.Headers.

Startup code

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<WeatherForecastController>();
        services.AddMvc().AddControllersAsServices();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

Controller code

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;
    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        var headers = HttpContext.Request.Headers;
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

Client code

static void Main(string[] args)
{
    Parallel.For(0, 3000, i =>
    {
        var getWeatherUri = new Uri("https://localhost:44341/weatherforecast");

        MediaTypeWithQualityHeaderValue requestHeader = new MediaTypeWithQualityHeaderValue("application/json");
        var client = new HttpClient();
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(requestHeader);
        var response = client.GetAsync(getWeatherUri.AbsoluteUri).Result;
        if (!response.IsSuccessStatusCode)
        {
            throw new Exception($"{response.StatusCode}: {response.RequestMessage} | {response.ReasonPhrase}");
        }
    });
}

Further technical details

  • Exception details:
    System.ObjectDisposedException
    HResult=0x80131622
    Message=IFeatureCollection has been disposed.
    Object name: 'Collection'.
    Source=Microsoft.AspNetCore.Http.Features
    StackTrace:
    at Microsoft.AspNetCore.Http.Features.FeatureReferences`1.ThrowContextDisposed() in /_/src/Http/Http.Features/src/FeatureReferences.cs:line 120

  • ASP.NET Core version - 3.1.0

  • Output of dotnet --info:
    dotnetInfo.txt

  • The IDE is VS2019 Version 16.4.1

@Tratcher
Copy link
Member

Tratcher commented Apr 6, 2020

Do you have the full stacktrace for the exception?

Is this on IIS or Kestrel? Seems like IIS.

If you observe and categorize the failures as shown by HttpClient, what's the breakdown that timeout, receive 500s, etc.? This may be related to the client timing out and disconnecting. Are there any more interesting failures reported by the client?

Also, how does it behave if you switch to HTTP/2?

@analogrelay
Copy link
Contributor

        services.AddSingleton<WeatherForecastController>();

Does it work if you remove this? I'm not sure Controllers are supposed to be singletons. (cc @rynowak)

@analogrelay analogrelay added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Apr 6, 2020
@Jasdo
Copy link
Author

Jasdo commented Apr 7, 2020

        services.AddSingleton<WeatherForecastController>();

Does it work if you remove this? I'm not sure Controllers are supposed to be singletons. (cc @rynowak)

Yes, it works.
The problem is that it creates a new instance of the controller for each REST call, and I'm trying to avoid that. Of course I can move the part that I want to be a "singleton" to another class, but everything worked fine before we migrated to 3.1 from 2.1.
I assume it is related to this change in FeatureReferences.

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Apr 7, 2020
@analogrelay
Copy link
Contributor

The problem is that it creates a new instance of the controller for each REST call, and I'm trying to avoid that.

Why are you trying to avoid that? If you need a singleton, it should be a service consumed by the controller, not the controller itself.

@Tratcher
Copy link
Member

Tratcher commented Apr 7, 2020

I checked with MVC and controllers are not supported as singletons. They have request state, so even if you didn't hit issues like this, you'd still have concurrency problems.

@Jasdo
Copy link
Author

Jasdo commented Apr 7, 2020

The problem is that it creates a new instance of the controller for each REST call, and I'm trying to avoid that.

Why are you trying to avoid that? If you need a singleton, it should be a service consumed by the controller, not the controller itself.

Yes, this is how it is implemented now in our code, the thing is that using the controller as a singleton worked until we migrated from ASP .NET Core 2.1 to 3.1.

@Jasdo
Copy link
Author

Jasdo commented Apr 7, 2020

@Tratcher, @anurse
Thank you for your help!

@Jasdo Jasdo closed this as completed Apr 7, 2020
@ghost ghost locked as resolved and limited conversation to collaborators May 7, 2020
@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 Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update.
Projects
None yet
Development

No branches or pull requests

5 participants