4

I have a simple Web API Core v3.1 where I am trying to handle Exceptions Globally. After following this answer https://stackoverflow.com/a/55166404/1508398, here is my code for doing that.

 app.UseExceptionHandler(appBuilder => appBuilder.Run(async context =>
 {
     var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
     var exception = exceptionHandlerPathFeature.Error;

     var result = JsonConvert.SerializeObject(new { error = exception.Message });
     context.Response.ContentType = "application/json";
     await context.Response.WriteAsync(result);
 }));

The error I get is at context.Response.WriteAsync(result); is :

System.ObjectDisposedException: Cannot access a closed Stream.

I am pretty sure I am missing something basic but unable to figure this out.

I essentially need to wrap the response into an object whenever an exception occurrs.

bit
  • 4,407
  • 1
  • 28
  • 50
  • 1
    This means that you Dispose Response before it reaches ExceptionHandler middleware – OlegI Feb 24 '20 at 06:46
  • You are right. I have another middleware that wraps Responses. Any idea how do I keep these 2 separate? – bit Feb 24 '20 at 06:52
  • call exception handle before any other middlewares. It should solve the issue – OlegI Feb 24 '20 at 06:57
  • @bit as the linked answer shows, configuration order is important. Did you add `app.UseExceptionHandler` before `UseRouting` ? What does the configuration code look like? – Panagiotis Kanavos Feb 24 '20 at 08:47

1 Answers1

2

It looks like someone else (another middleware) has already closed the stream.

In .net-core the ordering matters. Remember in the link you shared:

Important: Remember to add it before UseMvc (or UseRouting in .Net Core 3) as order is important.

So declare the UseExceptionHandler before any other Middleware and or configuration declaration.

Check the middleware guide here

Chain multiple request delegates together with Use. The next parameter represents the next delegate in the pipeline. You can short-circuit the pipeline by not calling the next parameter. You can typically perform actions both before and after the next delegate, as the following example demonstrates:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}

UseExceptionHandler is the first middleware component added to the pipeline. Therefore, the Exception Handler Middleware catches any exceptions that occur in later calls.

The first run, terminates the pipeline. So you can do some work, but in the end when the first run occurs the Response will close.

Please share more code for us to help more.

Tony L
  • 23
  • 1
  • 6
Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61
  • I am already doing that. I have wired up the exception handling middleware 1st and then another middleware – bit Feb 24 '20 at 06:57
  • In your comment you mentioned having another middleware that wraps responses. Is that incorrect? – Athanasios Kataras Feb 24 '20 at 07:02
  • I needed to update the response in both the middle wares. I ended up combining both of them after releasing that the last middle ware should actually update the response. Thanks! – bit Feb 24 '20 at 13:05