Exception handling in ASP .NET Core
.NET Core .NET

Exception handling in ASP .NET Core

Mishel Shaji
Mishel Shaji

Exception handling is the mechanism by which errors in the application is captured and handled. It is one of the most important features of a programming language. In this post, we’ll learn about exception handling in ASP .NET core.

What happens by default?

By default, you will get an error page with a status code (500 here) when an unhandled exception has occurred. To better understand this, let us create an error in our application. Modify contents of the configure method as shown below.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.Run(context =>
    {
        throw new Exception("An exception");
    });
}

Run the project by pressing Ctrl + F5. You will get an error page.

asp .net core default exception page

Manual Exception handling in ASP .NET Core

You might have noticed that the default exception page is visually unappealing for the users. Also, it does not say much about the exception (for developers).

Developer exception page

To replace the page with a developer-friendly exception page, UseDeveloperExceptionPage middleware can be used.

Developer exception pages should not be shown only when the app is under development. Never display it publicly when the application is in the production environment.

Try the example given below.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if(env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.Run(context =>
    {
        throw new Exception("An exception");
    });
}

Run the project by pressing Ctrl + F5. You will get an error page similar to the one shown below.

The UseDeveloperExceptionPage middleware should be placed before other middlewares to catch exceptions.

Exception handler page

The ExceptionHandler middleware can be used to display a custom error page for the production environment. Also, it will

  • Record error log.
  • Executes the request again in an alternate pipeline if the response has not started.
if (env.IsDevelopment())
{
     app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.Run(context =>{
    throw new Exception("An exception"); 
});

Exception handler lambda

Providing lambda to UseExceptionHandler allows us to deal with the error before sending a response to the client.

Here’s an example.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseExceptionHandler(errorApp =>
        {
            errorApp.Run(async context =>
            {
                context.Response.StatusCode = 500;
                context.Response.ContentType = "text/html";
                await context.Response.WriteAsync("\r\n");
                await context.Response.WriteAsync("ERROR!

\r\n");                                                    var exceptionHandlerPathFeature = context.Features.Get();

                // Use exceptionHandlerPathFeature to process the exception
                if(exceptionHandlerPathFeature.Error is OutOfMemoryException)
                {
                    await context.Response.WriteAsync(exceptionHandlerPathFeature.Error.Message);
                }
                else if(exceptionHandlerPathFeature.Error is ArithmeticException)
                {
                    await context.Response.WriteAsync(exceptionHandlerPathFeature.Error.Message);
                }
                await context.Response.WriteAsync("\r\n");
            });
        });
        app.UseHsts();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }
    app.Run(context =>{
        throw new OutOfMemoryException("Oops! Our servers cant take the load now. Please try again later");
        //Uncomment this to see the difference.
        //throw new ArithmeticException("An arithmetic error has occured");
    });
}

UseStatusCodePages

You might have already noticed that ASP .NET Core simply displays the error status code with an empty body. To replace such empty pages with custom pages for error codes, we can use UseStatusCodePages middleware.

To see the default error page, simply run your application and navigate to a page that does not exist. Say, https://localhost:<port-here>/my-error-page.

Now, add the following line to the beginning of Configure() method in Startup.cs.

app.UseStatusCodePages();

Run the project again and navigate to a page that does not exist. You will get a page saying Status Code: 404; Not Found.

Well, this looks really ugly. So, let’s display a custom error page with a custom message by modifying app.UseStatusCodePages(); ( which we have added just before ) as shown below.

app.UseStatusCodePages("text/html","<html><head><title>Error: {0}</title></head><body><h1>Error occured. {0}</h1></body></html>");

Again, run the project and navigate to a page that doesn’t exist to create a 404 error.

If you like to add some error-handling code yourself, use the overload of UseStatusCodePages that takes a lambda expression.

app.UseStatusCodePages(async context =>
 {
     context.HttpContext.Response.ContentType = "text/plain";
     await context.HttpContext.Response.WriteAsync("Status code: " + context.HttpContext.Response.StatusCode);
 });

UseStatusCodePagesWithRedirect

This method returns 302 code to the client and redirects them to the page specified.

To see how this works, go to solution explorer and Right-click on Pages -> Add ->Razor Page ->Add. Name the page as ErrorPage, uncheck Generate Page Model Class and click Add.

This will add a new page to the Pages folder. Now, open the page and modify it as shown below.

@page
 @{
     ViewData["Title"] = "ErrorPage";
 }
 An Error has occured
 Error Code: @HttpContext.Request.Query["ErrorCode"]

Open the Configure() method in Startup.cs and modify it as shown below.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        //app.UseDeveloperExceptionPage();
    }
    else
    {
        //app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        //app.UseHsts();
    }

    app.UseStatusCodePagesWithRedirects("/ErrorPage?ErrorCode={0}");
         
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseMvc();
}

Run the application by pressing Ctrl + F5 and navigate to a page that does not exist.

You will get a page similar to the one shown below.

asp .net core error page with redirect

UseStatusCodePagesWithReExecute

Unlike UseStatusCodePagesWithRedirect, this method returns the original status code to the client and generates the response by re-executing the request pipeline with the alternate path provided.

app.UseStatusCodePagesWithReExecute("/ErrorPage","?ErrorCode={0}");