-
Notifications
You must be signed in to change notification settings - Fork 111
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
NullReferenceException in .NET6 in Development mode #162
Comments
Actually, I'm also seeing this in Production mode when debugging in Visual Studio. I don't seem to be seeing (or at least not logging) the above errors in my dev and prod azure app services. |
Ok, last bit of info ... seems to only happen on http status 204 errors. I use NSwag to generate api clients, and a 204 response generates a client-specific exception. Other status codes on the exception type, like 500, seem to be fine. But a 204 causes the null ref exception. Doc on CompleteAsyc indicates it may throw under certain circumstances. Trying to step into IISHttpContext.FeatureCollection.cs seems to indicate _writeBodyTask is null (which is odd because the line is |
Hey @ErikPilsits-RJW! Thanks for all the details provided. It sounds like a non-trivial setup. Like, what's the relation with the 204 client-generated exception and your server-side API? Are you calling another API upstream? Do you think you'd be able to produce a repro for this? 🤔 |
Hi, same Erik. It's not too difficult actually. My API is calling an upstream API, and I use NSwag to generate the upstream client. It's NSwag's convention to throw client exceptions on anything that isn't success. I am mapping that exception to a status code problem details, and set the status in that lambda. It is after the details instance is returned that the exception occurs. I only get the null ref when setting a 204 status. 500 is ok, for example. I will try to create some kind of minimal API repro if I can, not sure it will be today though. Though I believe you'd be able to repro this without any of the upstream - just create a base API, in your controller throw some custom exception, and map that exception to a status code problem details where you set a 204 status. |
I wonder if this is an ASP.NET Core thing? I.e. in the platform itself? I mean, it doesn't make sense to try to write a body with a 204 status code. I wonder if the AspNetCore Module or Kestrel is actually preventing this somehow. |
The main issue here, IMO, is throwing exceptions for success status codes. That in itself is just bonkers. I actually encountered the same last week with one of our own NSwag-generated clients 🙈 Do you actually intend to map 2xx status codes to problem responses? Otherwise you could handle the exception case where the status is 204 and return |
I think we can rule out both development mode and the |
Yeah, I never liked that about nswag clients, but I don't see a way to avoid that behavior. And a try catch for every client call to trap the 204? Now that's crazy. Is there a way in the mapping function to return a basic 204, ie just pass it through?
So I thought the same thing, and maybe it was an issue with the response content. In the write details function, the context has a null Content-Length. But it's the same thing for a 500 response with no content, it has a Content-Length of null, so it's not specifically that. Working on a simple repro now. |
Surely you must be able to do this centrally?
Not really. You can return There's a big assumption in the middleware that exceptions are... exceptional and should always be handled as such. An upstream server returning an empty (but 100% successful) response isn't really exceptional 😂 |
I will probably have to do something like this, another middleware or whatever, unless I can find something in the NSwag pipeline to handle it. In my app code there are not many places that the upstream could actually return a 204, and where those are, I'm try/catch ing those for error handling anyway. I kind of stumbled across this in testing. So I wrote a minimal api repro, and you're correct. This is a framework thing.
I guess there's not much you could (should) do about this? Thoughts? Repro using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection.Extensions;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
services.TryAddSingleton<IActionResultExecutor<ObjectResult>, ProblemDetailsResultExecutor>();
services.AddProblemDetails(o =>
{
o.MapToStatusCode<CustomException>(204);
o.ShouldLogUnhandledException = (ctx, ex, pd) => false;
});
var app = builder.Build();
app.UseProblemDetails();
app.MapGet("/problem-details", _ => throw new CustomException("some error message"));
app.Run();
internal class CustomException : Exception
{
public CustomException(string message) : base(message)
{ }
}
public class ProblemDetailsResultExecutor : IActionResultExecutor<ObjectResult>
{
public virtual Task ExecuteAsync(ActionContext context, ObjectResult result)
{
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(result);
var executor = Results.Json(result.Value, null, "application/problem+json", result.StatusCode);
return executor.ExecuteAsync(context.HttpContext);
}
} |
But in this case, at least you're getting a proper error message. It might be worth looking into filing an issue for the IIS server to get rid of the NRE and add a proper error message there as well. Yeah, I don't think there's much I can do here, I'm afraid 😞 |
I ended up shamelessly borrowing the framework of this middleware to write an exception handling middleware, which can swallow all the nswag client 204 exceptions and just return a real 204 in the response. It goes in the pipeline after this middleware. |
So ... after thinking about this today, my approach works for me, narrowly, as an API wrapper. But if I was doing more with the client response, I'm back to try/catch on each client call. There's no framework way to centrally catch NSwag exceptions and turn them into normal responses. HttpClient handler is too low level, as the client takes care of deserialization after the client return. There are NSwag issues open for this issue. |
I ended up overriding the nswag client generator template to return |
That sounds like a decent solution. I'll try to find a minimal repro for the NRE and submit an issue/PR to AspNetCore if I manage to reproduce it reliably. I agree with David that it seems like a bug 🐛 |
In .NET6 the framework automatically enables the developer exception page, and I think this is causing a conflict. When debugging in VS I see these errors after an exception.
followed shortly by
and the exceptions bubble up all the way to
Best I can tell, the exception is thrown when
WriteProblemDetails
callsawait context.Response.CompleteAsync();
, and I believe it has to do with the developer exception page middleware being enabled. I have not found any way in .NET6 to disable the developer exception middleware.The text was updated successfully, but these errors were encountered: