ASP.NET Website Error Handling

ASP.NET Website Error Handling

Errors in an application can be roughly divided into two types: exceptions that occur during code execution (such as division by 0), and standard HTTP protocol errors (such as the 404 error).

Normal exceptions can be useful for the developer during application creation, but ordinary users won’t need to see them.

UseDeveloperExceptionPage

There is a special middleware called DeveloperExceptionPageMiddleware to handle exceptions in an application which is under development. However, we don’t need to add it manually because it is added automatically. So, if we look at the code of the WebApplicationBuilder class, which is used to create the application, we can see there the following lines:

if (context.HostingEnvironment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

If the application is in development state, with middleware app.UseDeveloperExceptionPage() the application catches exceptions and displays them to the developer.

For example, let’s change the application code as follows:

var builder = WebApplication.CreateBuilder();
var app = builder.Build();
 
app.UseDeveloperExceptionPage();
 
app.Run(async (context) =>
{
    int a = 5;
    int b = 0;
    int c = a / b;
    await context.Response.WriteAsync($"c = {c}");
});
 
app.Run();

The middleware method app.Run() simulates the generation of an exception by dividing by zero. And if we run the project, we will see the exception information in the browser:

This information is enough to determine exactly where in the code an exception occurred.

Now let’s see how all this will look like for the average user. To do that let’s change the application code:

var builder = WebApplication.CreateBuilder();
var app = builder.Build();
 
app.Environment.EnvironmentName = "Production"; // Change the name of the environment
 
app.Run(async (context) =>
{
    int a = 5;
    int b = 0;
    int c = a / b;
    await context.Response.WriteAsync($"c = {c}");
});
 
app.Run();

The expression app.Environment.EnvironmentName = “Production” changes the name of the environment from “Development” (which is the default) to “Production”. In this case, the ASP.NET Core environment will no longer treat the application as being in development. Accordingly, middleware from the app.UseDeveloperExceptionPage() method will not catch the exception. And the application will return error 500 to the user, which indicates that the server had an error while processing the request. However, in reality, the nature of such an error can consist of anything.

UseExceptionHandler

This is not a good situation, and it is often necessary to give users some information about what happened. Or it is necessary to handle the situation somehow. For this purpose you can use another built-in middleware, ExceptionHandlerMiddleware, which is connected using the UseExceptionHandler() method. It redirects when an exception occurs to some address and allows to handle the exception. For example, let’s change the application code as follows:

var builder = WebApplication.CreateBuilder();
var app = builder.Build();
 
app.Environment.EnvironmentName = "Production"; // Change the name of the environment
 
// if the application is not under development
// redirect to the "/error" address
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
}
 
// middleware that handles an exception
app.Map("/error", app => app.Run(async context =>
{
    context.Response.StatusCode = 500;
    await context.Response.WriteAsync("Error 500. DivideByZeroException occurred!");
}));
 
// middleware where the exception is generated
app.Run(async (context) =>
{
    int a = 5;
    int b = 0;
    int c = a / b;
    await context.Response.WriteAsync($"c = {c}");
});
 
app.Run();

The app.UseExceptionHandler(“/error”); method redirects to “/error” when an error occurs.

The app.Map() method was used here to handle the path to a specific address. As a result, when an exception occurs, a delegate from the app.Map() method will be triggered, which will send some message to the user with a status code of 500.

However, this method has a small disadvantage – we can directly address “/error” and get the same response from the server. But in that case we can use another version of the UseExceptionHandler() method, which takes a delegate whose parameter represents anApplicationBuilder object:

var builder = WebApplication.CreateBuilder();
var app = builder.Build();
 
app.Environment.EnvironmentName = "Production";
 
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler(app => app.Run(async context =>
    {
        context.Response.StatusCode = 500;
        await context.Response.WriteAsync("Error 500. DivideByZeroException occurred!");
    }));
}
 
app.Run(async (context) =>
{
    int a = 5;
    int b = 0;
    int c = a / b;
    await context.Response.WriteAsync($"c = {c}");
});
 
app.Run();

Note that app.UseExceptionHandler() should be placed closer to the beginning of the middleware pipeline.

Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like
Read More

App Model ASP.NET

Difference between applications ASP.NET and feature-rich client applications, which makes a lot of sense when analyzing the execution…