In this section I create an exception filter to return more meaningful JSON to the calling application when an unhandled exception is encountered in an action method.
- [Instructor] In this section, we're going to add an exception filter. Exception filters are part of the rich ASP.NET Core filter ecosystem. Authentication, authorization, exceptions, lots of different filters can be applied and we're going to add an exception filter. These are invoked any time an unhandled exception is encountered in an action method. The filter itself only has one method, OnException, which has full access to the execution context and as with any filter, they can be set at the application, controller, or action level.
To build our exception filter, let's create a new folder. Add, New Folder, and we'll just call it Filters and we'll add a new class into the folder and we're going to call this the SpyStoreExceptionFilter and we want to inherit from IExceptionFilter.
We need to have ASP.NET Core MVC filters. We should also add a using for ASP.NET Core MVC and then we're going to add two more using statements. So, using Microsoft.EntityFrameworkCore as well as we want access to our custom exception. The one method that we need to implement in exception filter is OnException, but there's some set-up work we need to do first.
What we want to return when there's an exception is a more meaningful message than the generic messages that come from EntityFramework or .NET. We also want to return the stack trace if we're in a development environment. Let's set up a private read-only Boolean to hold whether or not we are in development. Let's call it isDevelopment. We need to add a constructor so that the exception filter knows whether or not we're in development and we'll take isDevelopment, the one Boolean parameter, and then we will set isDevelopment equals to isDevelopment.
Our exception filter itself is going to listen for certain exceptions and respond appropriately. First we have to get the exception. Let's set up a variable to hold that and that is available from the context. We will then set up a variable to hold the stack trace and we will get the stack trace if we are in development and then we want context.Exception.stackTrace.
Otherwise, we want just an empty string. We're going to set up a variable to hold the error message and we get that from, ex.Message and then the specific error itself, we are going to make a friendly message, so we just start off with, String.Empty. Next, we set up a variable to hold our action result.
That's an IActionResult and we'll just name that actionResult and then let's plow through the errors. The first one we want to check to see is if we got an InvalidQuantityException and if we do, we want to return a 400 so let's set the friendly error message equals to Invalid quantity request and then set the actionResult to a new BadRequestObjectResult and we're going to stub out a method called create the anonymous object, passing in error, message, and stack trace and we'll create that method shortly.
Going to add another condition here so I could have made this a case statement, but just trying to keep it simple for demonstration purposes, and this is if we get a concurrency exception, it's also going to return a 400. So, what we can do here is copy this, but what we're going to change is the actual error message to Concurrency Issue and then the final trap is some unknown error and then in this case, actionResult is just going to be a new ObjectResult.
We still want to send in the content, which is the friendly error message, the actual message from the exception and then the stack trace, which will be populated if we're in development, otherwise, will be an empty string. We also have to set the status code and the status code here is a 500 for server error. The final step that we do is we set the context result to our action result.
So, context.Result equals actionResult and now we are going to return much friendlier JSON out of unhandled exceptions. Final thing we have to do is create our helper method. So, that's a private static can return an object, Create Content, takes in a string for an error, a string for a message, a string for a stack trace, and returns a new anonymous object where error equals error, message equals message, and stackTrace equals stackTrace.
That's how simple it is to create an exception filter. In the next section where we do our configuration of the pipeline and add in all the necessary services, we will then apply this exception filter to the site.
- Creating the .NET Core project
- Adding Entity Framework
- Migrating the data access layer (DAL)
- Configuring services and the HTTP pipeline
- Adding remaining services to the dependency injection container
- Migrating controllers and actions
- Testing the services