'Custom middleware breaks Developer Exception Page
Custom middleware breaks Developer Exeption Page. Instead of page with exception details there is HTTP 500
response. Debugging line by line runs only until await _next(context);
.
Once the custom middleware is removed from WebApplication
configuration by deleting app.UseResponseTime();
all works fine.
I suspect the problem is connected to Response
stream I am interfering in, but have no more ideas how to diagnose the problem further and solve it.
Using ASP.NET Core 6.
public class ResponseTimeMiddleware
{
private readonly RequestDelegate _next;
public ResponseTimeMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var originalBody = context.Response.Body;
var newBody = new MemoryStream();
context.Response.Body = newBody;
var sw = new Stopwatch();
sw.Start();
await _next(context);
sw.Stop();
// read the new body
newBody.Position = 0;
var newContent = await new StreamReader(newBody).ReadToEndAsync();
// calculate the updated html
var updatedHtml = UpdateHtmlElement(newContent, sw.ElapsedMilliseconds);
// set the body = updated html
var updatedStream = GenerateStreamFromString(updatedHtml);
await updatedStream.CopyToAsync(originalBody);
context.Response.Body = originalBody;
}
private static Stream GenerateStreamFromString(string s)
{
// convert string to stream
return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(s ?? ""));
}
private static string UpdateHtmlElement(string originalHtml, long responseTime)
{
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(originalHtml);
var ProcTimeHtmlElement = htmlDoc.GetElementbyId("proctime");
if (ProcTimeHtmlElement != null)
{
ProcTimeHtmlElement.InnerHtml = $"{responseTime} ms";
}
return htmlDoc.DocumentNode.OuterHtml;
}
}
public static class ResponseTimeMiddlewareExtensions
{
public static IApplicationBuilder UseResponseTime(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<ResponseTimeMiddleware>();
}
}
Very standard Program.cs
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllers();
builder.Services.AddHttpContextAccessor();
var app = builder.Build();
app.UseResponseTime();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.Run();
Solution 1:[1]
I had this kind of problem in the past, and I solved it by changing the line of the custom middleware, I don't know it works for you but it doesn't hurt to try, I hope it helps.
Solution 2:[2]
It was caused beacuse you replaced your default reponse body with MemoryStream I tried as below and could see the err page,but I don't think it's a good solution:
public async Task InvokeAsync(HttpContext context)
{
var originalBody = context.Response.Body;
var newBody = new MemoryStream();
var sw = new Stopwatch();
sw.Start();
try
{
await _next(context);
}
catch (Exception ex)
{
context.Response.Body = originalBody;
await _next(context);
}
newBody.Position = 0;
sw.Stop();
// read the new body
var newContent = await new StreamReader(newBody).ReadToEndAsync();
// calculate the updated html
var updatedHtml = UpdateHtmlElement(newContent, sw.ElapsedMilliseconds);
// set the body = updated html
var updatedStream = GenerateStreamFromString(updatedHtml);
await updatedStream.CopyToAsync(originalBody);
context.Response.Body = originalBody;
}
Update
I tried to custom a error handle middleware and it worked:
public class ExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
public ExceptionHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var originalBody = context.Response.Body;
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
context.Response.Body=originalBody;
await HandleExceptionMessageAsync(context, ex).ConfigureAwait(false);
}
}
private static Task HandleExceptionMessageAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
int statusCode = (int)HttpStatusCode.InternalServerError;
var result = JsonConvert.SerializeObject(new
{
StatusCode = statusCode,
ErrorMessage = exception.Message
});
context.Response.ContentType = "application/json";
context.Response.StatusCode = statusCode;
return context.Response.WriteAsync(result);
}
}
In program.cs and before other middleware:
app.UseMiddleware<xxx.ExceptionHandlerMiddleware>();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | srhtyt1 |
Solution 2 |