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

System.NullReferenceException: Object reference not set to an instance of an object #837

Closed
saber-wang opened this issue Jun 2, 2022 · 4 comments
Assignees

Comments

@saber-wang
Copy link

Asp.Versioning.Mvc.ApiExplorer:6.0.0-preview.3
netcore:net6

After the UseExceptionHandler is enabled, an "NullReferenceException" is thrown when the interface exception occurs.

Program.cs:

using Asp.Versioning;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddExceptionHandler(options => options.ExceptionHandler= async(http)=> {
    http.Response.StatusCode = 200;
    await http.Response.WriteAsync("111"); });
builder.Services.AddApiVersioning(option =>
{
    option.ReportApiVersions = true;
    option.AssumeDefaultVersionWhenUnspecified = true;
    option.DefaultApiVersion = new ApiVersion(1, 0);
}).AddMvc().AddApiExplorer(o =>
{
    o.GroupNameFormat = "'v'VVV";
    o.SubstituteApiVersionInUrl = true;
    o.DefaultApiVersion = new ApiVersion(1, 0);
});

var app = builder.Build();


app.UseExceptionHandler();

app.MapControllers();
app.Run();

TestController.cs

using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication2
{
    [Route("api/v1/[controller]")]
    [ApiController]
    [ApiVersion("1.0")]
    public class TestController : ControllerBase
    {
        private readonly ILogger<TestController> _logger;

        public TestController(ILogger<TestController> logger, ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<TestController>();
        }

        [HttpGet]
        public async Task<object> Get()
        {
            throw new Exception();
            return new { test = "1.0" };
        }
    }
}

error:

 System.ObjectDisposedException: The response has been aborted due to an unhandled application exception.
       ---> System.NullReferenceException: Object reference not set to an instance of an object.
         at Asp.Versioning.DefaultApiVersionReporter.Report(HttpResponse response, ApiVersionModel apiVersionModel)
         at Asp.Versioning.ReportApiVersionsAttribute.ReportApiVersions(Object state)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<FireOnStarting>g__ProcessEvents|226_0(HttpProtocol protocol, Stack`1 events)
         --- End of inner exception stack trace ---
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.InitializeResponseAsync(Int32 firstWriteByteCount)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.FlushPipeAsync(CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.FlushAsync(CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Watch.BrowserRefresh.ResponseStreamWrapper.FlushAsync(CancellationToken cancellationToken)
         at System.IO.Stream.FlushAsync()
         at Microsoft.WebTools.BrowserLink.Net.ScriptInjectionFilterStream.FlushAsync(CancellationToken cancellationToken)
         at Microsoft.WebTools.BrowserLink.Net.SendFilesWrapper.StartAsync(CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.StartAndWriteAsyncAwaited(HttpResponse response, String text, Encoding encoding, CancellationToken cancellationToken, Task startAsyncTask)

The possible cause is the following code in "ExceptionHandlerMiddleware"

    private static void ClearHttpContext(HttpContext context)
    {
        context.Response.Clear();

        // An endpoint may have already been set. Since we're going to re-invoke the middleware pipeline we need to reset
        // the endpoint and route values to ensure things are re-calculated.
        context.SetEndpoint(endpoint: null);
        var routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
        if (routeValuesFeature != null)
        {
            routeValuesFeature.RouteValues = null!;
        }
    }

https://github.com/dotnet/aspnetcore/blob/02646222b7e6fb70a2fce0d3e2545ab3fae31138/src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerMiddleware.cs#L176

@commonsensesoftware
Copy link
Collaborator

Interesting... I'm surprised this has never come up before. When the pipeline is re-executed, I would expect that an Endpoint has been set, but maybe not. This appears to be the only place a NRE could occur where it's not handled. I confirmed that Endpoint.Metadata will never be null. It is surprising that executing the error handler path would yield success without an endpoint.

If you have a repro, great; otherwise, I believe I can create one fairly easily. I'm certain this is a bug, but I'd like a better understanding of the state of things when this happens. API versions should never be reported for an endpoint invoked due to an exception (they're not versioned after all).

@saber-wang
Copy link
Author

@commonsensesoftware
Copy link
Collaborator

Confirmed. It's a 🐞 . It will be fixed in the next release. Thanks for trying things out and reporting it.

@commonsensesoftware
Copy link
Collaborator

6.0 has been officially released and contains the fix for this issue. Thanks for reporting it and providing a repro.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants