ASP.NET Core Exception Handling Tutorial | .NET 8

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this net API has a problem and the problem is that any time it throws an exception it is been converted into a 500 internal s error and because of that it is too hard to diagnose what's going on with the API when one of those exceptions happen so today I'm going to show you how to implement a global exception Handler so we can properly map each of those exceptions into corresponding HTTP responses that have all the relevant information for us to diagnose what's going on and so like I said anytime we execute one of these requests either this first one here that receives all games or the second one that receives a game just by ID we're just getting this 500 internet server error now one thing to notice here is that I have modified application so that it behaves as if it was in production as opposed to my local development environment and how did I do that well what I did is let me show you I'm just going to stop my server briefly and close this I went into my launch settings. Json file under the properties directory right here and I went ahead I modified this value here right for my HTTP profile I changed the AET core environment variable from the development into production right because by default what you're going to have here is just development like this and this is going to have a different experience right so if I just go ahead and run this what you're going to see is that if you go back into hello exceptions here and you send a request it's going to be kind of similar but now we're going to have the entire stock Trace right there in the response right and so this is not the experience that you're going to get in production right and you should not get ever this experience in production because it's just revealing too much about what's going on inside right uh what we really care about is the production experience not the development experience right so let's close this and let's stop the server and let's go ahead and just revert that back into production so how can we improve that experience so that we have more information to diagnose the issues right so let's close this and let's close that and let's go into our program. CS file right so this is where we Define our API like like you like I said it has two end points defined right here and the repository itself has been modified to draw some exceptions uh forcefully so we can start investigating what's going on right so so it's not really important to see what exactly is going on behind the scenes in the repository what matters is how can we improve experience for the client and the first thing that we can do here which is actually very cheap is to add what is known as a problem details service so what is that service that service allows us to to turn uh this failure responses into proper problem details now what are these problem details well if I show you this page very briefly I'm going to show you this so there is a an entire specification a know a well-known standard on how to report problems in a HTTP apis right and this page describes everything that you want to know about how exactly you should be forming your responses so that they have all of the the right information right I'm not going to read all of this the good thing is that in aset core there's already a service that allows you to convert your error responses into prol details right and so let me show you how to enable that what we're going to do is just chain here just under my at single tun call over here I'm going to add problem details just like this by doing this H we are adding the service that is able to collect and prepare that additional metadata for the response for their response but we have to do a little bit more than that uh because we have to also add a middleware so that that Pro can be used as far as the pipeline right so just down here just under app we're going to do the follow we're going to say app. use status code pages right that's the first piece of mware that you want to include so that those front details can be turned into proper like it says status code pages that can show the information back to us uh by going into the middleware uh but that's going to work only for kind of expected status Cotes right and what I mean is that that's going to help in the case of here for instance when we R return results not found right that's going to help there but it's not going to help really with the with exceptional cases exceptions like that we're interested in right now for that what you want to do is just say app. use exception Handler right by using this middleware here now your your exceptions are actually going to be turned into problem details bying taking advantage of the problem details service all right so let's take a look at that let's see how that actually works so let's go ahead and run the application once again and I'm going to go back into my hello exceptions HTTP file over here and then let me close this so now when we send the request as you're going to see on the right side I mean we still have the 500 internal server error over here right we have the 500 stand but now down here as you can see we also have this entire section as you can see this entire section of a Json section that describes a problemos by following the standard as you can see there's RFC 9 9110 uh this is the standard way to report problem details back to the client right and as you can see it has a title that says an error occurred while processing the request right and Status 500 so this is a better experience than what we have initially right when we have absolutely nothing in the in the body of the response but still it's not enough for us to diagnose what's going on how to correlate this with the back end and in fact if we look at our logs over here we're going to see in the lcks in the back end that I mean we do have the exception stack Trace over here but there's not enough information for us to correlate this H with what's going on with with that response right there's not enough information so how can we deal with this what we're really missing here is some sort of exception handling right so proper exception handling so let's see how can we achieve that let's close this and let's close that and over here and let's go ahead back into our PR that CS file over here and of course what we can start doing here is to add some sort of a perhaps TR cach right the typical TR cach we could go into each of our end points and start adding a TR catch statements here and to start adding some loging and to start responding with proper prop prop back into the client with more metadata uh but that's going to be a little bit timeconsuming and that's going to mean that we're going to be repeating that same code over and over again into each of our invs right so we don't really want to do that what we want to do is to implement a what is known as a global exception hter so that anytime a session happens we just catch it there and we do something about it in that central location okay so how to go ahead and Implement that session hle let me show you how we're going to do is first open up our solution Explorer down here okay let me collapse the other one for a moment and we're going to go ahead and just right click on the project let's add a brand new file and we're going to name this one it's going to be a class uh let's name it Global exception Handler of course you can name it with any name it doesn't matter uh but this is going to be the file that's going to implement the the new ey exception Handler interface that's available starting with net 8 okay so you're going to go ahead and Implement I exception Handler okay and then uh let's do control dot so we can go ahead and implement the interface right here and so as you can see all you have to do is implement this one method here try handl a sync which is going to be invoked anytime an exception is thrown from somewhere in the application where you're not handling the exception okay now let me let me put the the parameters down here so we can see better as you can see here you're going to receive the HTTP context you're going to receive the exception and even a cancellation token okay so now we have to decide what to do over here anytime an exception comes in so what should we do well the first thing we should do is add some proper loging in the back end right with enough information for us to correlate later so for to do that let's go ahead and introduce a logger here so I'm going to declare private readon it's going to be an ilogger of type Global exception Handler right and let's go ahead and also introduce this into our Constructors let's actually generate a Constructor and we can probably improve this liit control dot here by using a primary Constructor right so that's that's what it is okay so now we have our logger and now that we have the logger we can go ahead and write some sort of loging uh that's relevant for our application what we're going to do uh even before actually using the login is to H create some sort of identifier of the of the the request right some sort of Trace identifier Trace ID right that's ID that we're going to be correlating from the back end all the way back into the client right so to Define that Trace ID what you can do is the following you can just say Okay so VAR Trace ID is going to be this line over here now what this line is doing is saying okay so I'm going to go ahead and either try to get the ID from the current activity right so the activity is uh is is kind of the I mean the activity is the identifier of an operation that relates to the current thread in your application right so every threat every operation in your net application is going to have some sort of H some sort of activity current activity right but in the case that there is no activity for some reason we're going to say okay in that case we're just going to go ahead and get the trace identifier of the HTTP context which is the identifier that every single request is going to automatically get for you right so that's a way that we have to capture some sort of Trace ID and now that we have the trace ID we can go ahead and actually create some sort of error so we're going to say um logger.log error yep and so we're going to first start with that exception let me send it to the other line so we're going to get the exception and then we're going to provide some sort of a message right so what we're going to do is the follow we're going to say um could not process a request on machine and here we're going to start providing some some richer information to this exception that we're loging in the back right we're going to say that the machine is going to be machine name right so I'm using struct log here I'm going to provide a value for that in a moment and then I'm going to also say that I'm going to mention here what's going to be that Trace ID so it gets captured in the structor log so the trace ID is going to be just that value of the of Trace ID that I'm going to provide in a moment now let's provide parameters for this for the machine name we're going to be using environment. machine name and for the trace ID of course we're going to be using the trace ID variable that we just capture right so that's going to give us a some good lcks let me close this and that okay that's going to write some some good lcks in the back end but now we have to provide some proper response I mean in the respones has to be all of this important information and also we have to to figure out how to map that exception into the proper status code and and a good title right and so for that what you can do is the following you can just say await right and you're going to use the results class here results and then we're going to say problem right results problem and then here you can provide a series of parameters to Define what you want to include to that problem details standard problem details are going to return back to the client so let's start with the title we're going to set some title here and we're going to figure out how to do the proper title in a second so let's just leave it empty for now we're going to go back to that in a moment we want to provide some status code so let's go for standard 500 error for a moment we're going to go back to this in a moment also H but also what you can specify here is what is known as extensions right extensions are are a way to provide some additional details into your into your pro details so let's do extensions and these extensions is going to be a dictionary right of type string a string object but this has a few particularities so this is going to be object a nullable object here right and to actually Define the trace ID we're going to say is just with this syntax over here so Trace ID and then we're going to do comma and this is the trace ID all right so just just close that and that should Define our uh problem details now in order to actually send this problem details object into the into the client what we want to do is just to do dot here and then do execute async and then we send in the HTTP context so that's going to write directly this Pro details into the current HTTP context right and then out into the response are going to go back into the client right so that's that and then also this method here as you can see from the signature it is going to it needs to return a Boolean right it needs to return a true or false right so what does that mean well if we return true here as we're going to do return true that means that the pipeline has to stop here right there's nothing else that needs to execute after this exception Handler and it means that we have properly handled the exception if you want to you can just return false and that means that the pipeline it will keep executing any other middleware that H that happens to be waiting after this middleware here right and so you could use that if you if you wanted you can Implement multiple exception handlers for multiple exceptions and so you can have some of them just return false and some of them return true for the for the final one if you wanted to but for this exercise let's just return true we're going to say that here is what everything stops because we're handling the exception properly all right and so now one thing that we're missing here of course is a proper title and the proper status code depending on the exception that we're handling here and so to deal with that what we're going to do is to implement a a little mapping function that can deal with this this mapping situation right and so what we're going to do is just down here we're going to implement private static and this is going to actually return a topple so that we can return both the status code and the title in just one response right so this is going to return status code and it's going to return a title all right a title and then let's name this one map exception and it's going to receive our exception exception all right okay so that's the signature and then what we're going to do here here is to of course use a a switch just like it is being suggested right now I'm going to actually take that suggestion so by default we're going to be returning a 500 internal Ser error but we also want to be able to deal with specific exceptions to map them to proper things now for this let actually take a quick look at what's going on with that repository so why is it drawing exceptions right and so as you can see in the get all a sync method what we have done is just simulate that it is returning an invalid operation exception whenever the supposedly the base connection is closed right and in the case of get sync when the ID is less than one there's a little rule here that says that you cannot have an ID less than one so we're going to be returning an argument out of inception so what we're going to do here is that for application we're going to say that whenever we have we have an argument out of R reception we want to turn that into a b request back into the client right and we want to send the actual message that's here this message here we want to include it as part of the problem details but for any other exception including this invalid exception we we are just fine with the 500 error all right and so because of that let's go back into Global exception Handler what we can do is the following we can we can say that our argument out of rate exception uh is going to map into the following tole it's going to be a status 400 bad request and for the message instead of just saying B request we're going to say exception. message right that's going to be the response and then in the other case instead of just saying internal server error because that's not very not very friendly we're going to actually do a message like we made a mistake but we are working on on it all right that's going to be our message okay and so with this mapping function we can of course you could expand this for many more sections if you wanted to but for now we're going to go ahead and just use that function down here okay let's use that function over here so we can capture right we're going to capture the status code and title uh into that uh that map ension function over there right so we invoke map exception with exception and we get back status code and title now that we have those two we can go ahead and use the title over here and the status code down here right status code all right and yeah I mean at this point we have our Global exception Handler ready right it has everything that we need at this point to properly catch every single exception does not handle anywhere else in the application and map it to the proper problem details response now we do need to register this glob exception Handler uh back in pram CS so let me show you how to do that so we're back in pam. CS and what you want to do here is just this just after our call to ad Pros we can just change one more call let's do that we're going to say add exception Handler and that's going to be our Global exception Handler okay and just by doing that we are plugging everything up and so we should be able to now see a much better response so let's go back into our terminal let's go ahead and let me actually clean this for a moment net run okay and then let's go back into our file over here HTTP exceptions this one over here okay let's close this and now let's see what happens when we try to invoke the the games input here so send request and as you can see on the right side of course we still get our 500 internal server error over there but if we see down here the the response down here has been improved right so now we do have our title that says we made a mistake but we're working on it okay that's that's expected it is a 500 error and we have a trace ID down here that we can use to correlate back to the to the locks right so in fact if we open the locks right now so let's open the locks and let's look at what's going on here so here's the setion and if we scroll down a little bit here we should be able to match the trace ID that's right here with the trace ID that we have down there right so they are exactly the same the same ID so this is incredibly useful because now if if a client report the trace ID you can now go into your locks right wherever you're storing your locks in the cloud and just find the trace ID and immediately start figuring out okay so the database connection is closed and okay let's do something about that right so you know exactly what's going on okay so that's the power of this and not only that H we are properly mapping the exceptions right so now if you go into this other request over here right with a case where we're providing a zero where zero is an invalid ID V rules in the repository so if you now try to send this request it's going to also return an exception but in this case as you you can see is going to return a 400 by request so it's no longer a 500 as I was before so it's a 400 it's the proper response and we have our proper details over here with a proper title that says the ID must be greater than zero which is the the exception the message that we got in the repositor itself and then we also have our Trace ID and the status code right so that is a much better way to map all of these exceptions into responses that we can actually use to diagnose what's going on with the application right and so that's almost that that's almost it but there's one more thing I want to show you is a small trick uh because if you see the the logs down here uh we actually have more than one lck for every failure right so notice here that we have one failure here right that says that's coming from the exception Handler middleware right and then we have another lock here that's that's coming from our Global exception Handler right so we're getting two locks for every exception I don't really like to have two locks it's just that the the default Handler is already loging for you but you don't want you don't want to do that necessarily so what I'm going to do is just stop this this and this and uh let me close the other so let me just go I close all let's go into abs. Json and what we can do is to H add a login section here to mute the default login that the standard Handler is is doing there right so we can do is just add the following I'm going to copy this to just not not mess mess things up I'm going to just copy this from my notepad right there and by adding this line here what I'm saying is that for anything that the exception Handler mirror is reporting by itself uh I don't want to be logging anything I want to do all the logs directly in my Global exception hler right so that's what you're saying over there so if I go ahead and do donet run again and actually let me before we do that let's just clean this and let's do net run let's go back into our file and let's go ahead and run this again and again we get the same thing on the on the response but now in the login side as you can see we only have one exception reported in the logs there is no more duplication of those logs over here all right so yeah so hopefully that's useful that's what I wanted to show you today that's the right way to handle exceptions properly so you can have a much better time diagnosing the issues in your application so yeah I hope you liked it and I'll see you in the next video
Info
Channel: Julio Casal
Views: 7,986
Rating: undefined out of 5
Keywords:
Id: HTCb1zXQ6E4
Channel Id: undefined
Length: 20min 21sec (1221 seconds)
Published: Thu Nov 16 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.