Handle ASP.NET Core Exceptions Globally
C# pattern matching can compare a boxed runtime value with a constant even when equality operators reject the incompatible static types.
Transcript 6 topics
Global exception handling
0:00Don't get me wrong. I've never written a bug, and certainly none of the code that I write throws exceptions. Okay. Let's be real. All of us write code that are gonna throw exceptions no matter how good it is.
You know, even if we write airtight code, user gonna user, so stuff's gonna happen. So hopefully, we're gonna handle those exceptions gracefully. Let's take a look real quick at how asp.netcore handles exceptions and how we can handle them globally. Now if you've used asp.net Core in the past, you may be familiar with use exception handler. It's basically some middleware that's built in so that we can add global exception handling for our whole APIs or web apps.
So why don't we fire up a dot net API and see what use exception handler would look like. So I'm gonna dot net new web API. Easy enough. We'll go into the program CS and then this is adding swagger. Using this default stuff, I'm gonna replace all that.
I'm just gonna paste in what I want. Basically trim down and just use exception handler. Anytime an exception happens, we're gonna report a status code and a content type of application JSON. Error message is the message that goes back, and then we'll have a Yo endpoint. Let me save that and go to the terminal.
We'll dot net run like a boss. And then and then we'll open it in a browser. Okay. It doesn't exist there, but we'll go slash yo. Ah, and there's our endpoint there.
We get all snap. If we f 12 that, we would see it came back with the, 400 bad request. And any exception that we throw in there is gonna get passed through that whole exception handler, and and handle however we want. That's very simplistic. Right?
We would normally wanna log that in some way, maybe keeps track of some of the user's data or a transaction ID, but that's basically the guts of how that works. Now that's pretty straightforward and likely use exception handler is coming out of the box. So there's nothing really more for us to do except code it, but, let's dial it up a notch and maybe use some custom middleware to manage those exceptions.
Custom exception middleware
2:04Let's let's look at the code for that. I'm gonna stop this from running and then you know what let's go create a new file we're gonna call it a base exception and I'm just gonna paste it in there and you'll see all it has is a status code. It takes in a message, a status code, and sets that. Pretty pretty basic. You just want that message in there, so we'll save that.
And then let's say we want a product not found exception. Maybe we're gonna throw a four zero four error. Let's go back over and create that product not found exception and we'll paste it in. It's just gonna inherit from base exception and we'll pass in the product with the ID not found, the status code of not found. So keeping it simple, we're using inheritance but we're keeping it simple here.
And then it's just time to add in our middleware. So we'll create a quick file for that. We'll call it error handler middleware paste that in and then we'll take a look at it real quick. So basically it's going to receive in every error just like that use exception handler. But in our case we're going to say hey if that exception was one of our base exceptions, then log out the status code from the base exception.
Otherwise, send back a server 500 internal error. Right? The rest of it works the same. We're going to send the same message from either of those. And then all that's left to do is register it in our program CS.
Now to speed us along, I'm gonna just go ahead and copy and paste that in. We'll take out that use exception handler. I'm gonna take out that route too, and we'll paste in a new one that looks basically the same. We're gonna say app use middleware and then pass in our error handle error handler middleware. I'll learn to speak English at some point.
Trust me. And then our our map get of Yo, we'll just, send back a new product not found exception with a GUID there for the ID. Who cares what that is? And that's all there is to it. If we go and run that now let's see.
Go back out. Go.net run like a freaking boss. Okay. And then we need to go back over to the browser and refresh the page. And now we get a little prettier response back.
Right? We get a JSON object that has a title, which is the message. Right? Product with ID, whatever, not found, and then we get our 404.
So, yeah, once we hit that middleware, it's it's sending us back something really sexy as response. But let's go even farther.
IExceptionHandler basics
4:40If you're using dot net core eight or above, you should be using the IExceptionHandler interface. Oh, let's talk about it. How's it different? Well, let's get rid of that middleware for one. We'll go and just delete that file.
Good day to you. We'll say new global exception handler, and I'm just gonna paste that in and we'll go through and see what it looks like. So basically it's a GlobalExceptionHandler, it implements IExceptionHandler and it has a try handle async method where all the magic happens. Now this is basically just taking in the same kind of problem details. The IExceptionHandler is used by so many other things in asp.net, which is one reason it makes it really nice to use it because it just ties into all the stuff that Microsoft is shipping by default.
But back to this code, we're doing the same kind of stuff. We're just getting a status code. We're getting the message out of the exception and writing it back in a pretty format. And then all we have to do is update our program CS to use it. So we'll say get rid of that middleware there.
And then for the builder, we're gonna register an exception handler called global exception handler, add product details so we get that from all the pipelines available to us. And then we're gonna go just app dot use exception handler, and we're good to go. We'll leave that yo the same. We'll save that. Let's go back to the terminal.
Stop it from running. We'll go dot net run. It's running. It's running. It's alive.
Let's go refresh. Look at it. Hey. Wait a minute. Dude, that looks pretty much the same.
You just got like that instance thing added to it. I I don't see anything better, but understand this is built in. Right? You're using dot net's built in use exception handler, and you're using that IExceptionHandler interface that so many other parts of ASP dot NET Core use. And that's not all.
This is actually gonna make all of our code more modular and maintainable, and I'll show you how. We can actually have different exception handlers for different types of exceptions.
Handling specific exceptions
6:44Let's go back to the code, and I'll show you what I mean. So let's say we've got that global exception handler, but what happens if we add a new product not found exception handler? I'm gonna just paste it in there. Not exception not found exception handler. Actually, me rename that to match what the class is.
Try handle, and we're just gonna say, if the exception is not a product not found exception, return false. And I should have mentioned this before. When that try handle async, the way the pipeline knows if you've handled that exception or not is whether you return true or false. So if your middleware or your exception handler here is able to handle that exception, return it true. If not, return false.
And it'll just go continue down the pipeline till it finds something that can handle that exception, even if it's like the built in exception handling. Okay. Now for us, we're gonna have to actually handle this error for it to work, so we'll just replace that with something similar to what's in the global exception handler, except we don't have to do that checking for base exception because we know this is a product not found exception.
Registering handler order
7:52And now that I've got two exception handlers, though, I'm gonna go in and create an extension method. We'll call it magic extensions. Why is it magic? Because it just is wonderful. And all it's gonna do is take in a service collection, and we're going to add an exception handler of not found.
And we're going to add in our global exception handler, and then basically add those problem details that we had earlier just to kind of keep it clean and together. Now one thing that's important to know here is when you do this, the exception handlers run-in the order you register them. So it's gonna first pass any exception to that not found and say, can you handle this? True? Great.
False? Okay. Let's keep going. Global exception handler, can you handle this? True?
Great. If not, keep going. You get it. Now we'll come back over to the program CS, but instead of like leaving those services registered like that, we'll get rid of that and we'll say builder.services.add well, already had it copied.
Adding exception handlers
8:37Perfect. Look at me coming prepared like a boss. Add exception handlers that'll register all those services and then we should just be able to run it. Do it. Do it.
Running in our browser. So we should be able to go to our browser, hit that same endpoint and we get the same thing, but now it's going through a separate exception handler. Isn't that pretty slick? So now we can really like fine tune what kind of exceptions we're sending back based on the exceptions that happen and, make a more pleasant experience for our users while also keeping our code very modular and maintainable. Hopefully this helps you catch exceptions a little better in your asp.net Core apps, and I'll catch you next time.
Sign in to join in. Reading needs nothing.