WEBVTT

00:00.410 --> 00:05.720
Okay to continue on from the previous lesson, we're going to populate our handle exception method.

00:05.720 --> 00:12.470
What do we want to do when we do encounter an exception in our dotnet code.

00:12.470 --> 00:18.920
So inside this private method this handle exception method let's just remove the throw new exception.

00:18.920 --> 00:20.870
And first of all we'll use our logger.

00:20.870 --> 00:22.730
And we'll say log error.

00:22.790 --> 00:26.150
And we'll pass in the exception called x.

00:26.150 --> 00:34.610
And we'll use the message property from there and effectively output our exception into the log.

00:34.640 --> 00:40.220
Now we're going to update our response that we send back to the client.

00:40.250 --> 00:43.190
Now we have access to the Httpcontext.

00:43.190 --> 00:45.560
So we'll specify context.

00:45.560 --> 00:46.970
And then the response.

00:46.970 --> 00:48.830
This gives us access to that.

00:48.830 --> 00:51.320
And we can set the content type.

00:51.320 --> 00:56.090
And we're going to set it to be application forward slash JSON.

00:56.390 --> 01:04.490
So this will ensure that we send back a JSON formatted Response, and we'll also set the context.

01:04.520 --> 01:07.790
Dot response dot status code.

01:07.790 --> 01:12.380
And we're going to set this equal to and we'll cast this into an integer.

01:12.380 --> 01:15.260
So in parentheses specify int.

01:15.260 --> 01:21.470
And then we'll use one of the constants that's provided from system.net the HTTP status code and the

01:21.470 --> 01:23.300
internal server error.

01:23.720 --> 01:25.700
And then we'll create our response.

01:25.700 --> 01:28.640
So I'll say var response equals new.

01:28.640 --> 01:35.360
And we can use the class from Microsoft ASP.Net core MVC called Problem Details.

01:35.720 --> 01:42.380
Inside here we can specify the status and make sure we bring this in.

01:42.380 --> 01:46.520
And inside here we can specify the status.

01:47.120 --> 01:51.350
And I'm just going to set this to 500 for a status code of 500.

01:51.380 --> 01:52.880
Lead detail.

01:52.880 --> 01:55.730
We're going to check to see what environment we're running in.

01:55.760 --> 02:02.540
So if env is development then we want to send back the full stack trace.

02:02.540 --> 02:04.710
So we'll use a ternary operator here.

02:04.710 --> 02:15.090
So if we are in development we'll specify x dot stack trace and use the two string method on it, which

02:15.090 --> 02:20.280
we need to make sure is optional because it may or may not be present.

02:20.280 --> 02:23.430
So we don't want to cause an exception inside our exception.

02:23.430 --> 02:28.710
If we don't have a stack trace and we don't use this optional chaining, then that would throw an exception

02:28.710 --> 02:31.290
inside our exception handler.

02:31.350 --> 02:33.900
Who knows what would happen in that scenario.

02:33.930 --> 02:39.750
Actually, our application would just throw an unhandled exception in that case, and it wouldn't break

02:39.750 --> 02:42.030
the internet or anything like that.

02:42.030 --> 02:46.470
And if we do not have the stack trace, then it's just going to be null.

02:46.470 --> 02:52.050
And if we're not in development mode, then we're just going to return null for the detail.

02:52.050 --> 02:58.020
And below this we'll specify a title and we'll set it to x dot message.

02:58.020 --> 02:59.850
So that's what we're going to return.

03:00.150 --> 03:07.200
And then we'll specify our options because we want to use our JSON serialized response.

03:07.200 --> 03:09.060
We want to give it its standard formatting.

03:09.060 --> 03:13.230
We're not in the context of an API controller inside our exception middleware.

03:13.560 --> 03:15.930
When we're inside an API controller.

03:16.140 --> 03:21.420
Net will format the JSON response correctly, which means giving it camel casing.

03:21.420 --> 03:30.120
So we're going to create some options for our JSON serializer and say new JSON serialize options.

03:30.630 --> 03:35.640
And then we'll open curly brackets and we'll set the property naming policy.

03:35.640 --> 03:40.110
And we're going to set this equal to JSON naming policy dot CamelCase.

03:40.110 --> 03:44.100
That's the correct format for a JSON response.

03:44.310 --> 03:45.720
Then we'll create the JSON.

03:45.720 --> 03:51.540
In fact let's move that below the options so I don't go off the edge of the screen below.

03:51.540 --> 03:55.710
This will save our JSON equals JSON serializer.

03:55.710 --> 03:58.590
And we're going to serialize our response.

03:58.590 --> 04:00.300
So we'll pass in the response.

04:00.300 --> 04:04.830
And then we'll pass in as a second parameter the options we created above.

04:04.960 --> 04:06.940
and then we can return this response.

04:06.970 --> 04:14.590
So we'll say await context dot response and write async and pass in JSON.

04:14.590 --> 04:15.580
So great.

04:15.580 --> 04:17.410
That's now our middleware created.

04:17.410 --> 04:20.800
And now let's see how we use this in our program class.

04:20.800 --> 04:23.260
So let's open up the Program.cs.

04:23.380 --> 04:31.240
Now we need two elements here because inside our middleware what we've used is an interface for the

04:31.240 --> 04:32.410
AI middleware.

04:33.040 --> 04:40.270
Now when we use a service like this, even though it's a service provided by dotnet, the AI middleware

04:40.300 --> 04:46.450
service, then we still need to provide this as a service inside our program class.

04:46.450 --> 04:54.010
And the reason for that is we're using dependency injection here to inject the AI host environment and

04:54.010 --> 04:54.790
the logger.

04:55.330 --> 05:00.280
And if we want to inject anything into something that we're using, then this has to be declared as

05:00.280 --> 05:03.340
a service inside our program class.

05:03.340 --> 05:07.360
And we also need to add this as Middleware inside there as well.

05:07.360 --> 05:10.540
So first of all, let's take a look at adding this as a service.

05:10.570 --> 05:16.150
Now in this part of our code where we add services to the container I'm sure I've mentioned it before,

05:16.150 --> 05:19.870
but the ordering isn't particularly important inside here.

05:19.870 --> 05:22.300
We can put this service wherever we want.

05:22.330 --> 05:26.050
I'm just going to add it below the add, cause it really doesn't matter.

05:26.320 --> 05:33.490
But I'm going to say builder and then services and I'm going to add transients here.

05:33.520 --> 05:36.670
Now there's different options of how we want.

05:36.820 --> 05:39.340
Net framework to manage a service.

05:39.370 --> 05:41.410
There's add transients.

05:41.410 --> 05:48.850
There's add scopes and there's add singleton all of which are available for us to choose as to how do

05:48.850 --> 05:55.300
we want the framework to initialize this service, and how do we want it to dispose of this service.

05:55.330 --> 05:58.330
The most common one that we'll use is add scoped.

05:58.330 --> 06:06.460
And if I just go back to the middleware pipeline, then scoped means effectively that the service will

06:06.460 --> 06:14.230
be created when the request comes in, and will be available for the entirety of this request, so this

06:14.230 --> 06:16.060
is ad scoped.

06:16.120 --> 06:27.010
If I use ad transient, then the service is only created for the specific method where it is needed.

06:27.040 --> 06:34.030
So I'll just highlight this as to the scope of when this service will be instantiated and when it will

06:34.030 --> 06:35.350
be disposed of.

06:35.380 --> 06:42.730
And the other approach is to use a singleton which would be fully or it would be instantiated when the

06:42.730 --> 06:47.350
application starts and it's only disposed of when the application is finished.

06:47.380 --> 06:53.080
Now for this specific service that we're using, transient is the most appropriate because we don't

06:53.110 --> 06:56.770
expect we're going to have exceptions at every part of our application.

06:56.770 --> 06:59.710
Exceptions should be exceptional.

06:59.890 --> 07:06.820
We only really want to instantiate our AI middleware service effectively when it's actually needed,

07:06.820 --> 07:09.470
as an exception is being thrown.

07:09.470 --> 07:16.280
So a transient is the appropriate level for this particular service.

07:16.310 --> 07:23.960
And later we'll be adding our own scoped services because we would want them scoped to the request when

07:23.960 --> 07:27.740
it comes in and not disposed of until the request is finished.

07:27.740 --> 07:30.560
But for this one we're going to specify a transient.

07:30.710 --> 07:37.160
And we need to specify exception middleware as the service that we're using here.

07:37.160 --> 07:41.870
This is the service where we're injecting the logger and the host environment.

07:41.900 --> 07:46.670
Now we also need to add our new middleware to the HTTP request pipeline.

07:46.670 --> 07:49.850
And ordering is important inside here.

07:49.850 --> 07:55.040
And because it's our exception middleware, we need this to be at the very top of the pipeline so that

07:55.040 --> 08:01.580
any other middleware can throw an exception, and then that will get passed back up the middleware pipeline

08:01.580 --> 08:05.570
until it reaches something that can catch that exception.

08:05.810 --> 08:07.790
So the idea is we stick this at the top.

08:07.790 --> 08:10.640
So we're going to say app use middleware.

08:10.640 --> 08:15.920
And then we're going to pass in exception middleware inside there.

08:15.950 --> 08:18.200
Now that should be enough for us to test this.

08:18.200 --> 08:23.150
And I doubt that hot reloading could accommodate our changes there.

08:23.150 --> 08:27.620
So if we open up the terminal it does ask us if we want to restart our app.

08:28.100 --> 08:29.720
I'm going to say yes.

08:29.720 --> 08:32.720
And you might be tempted to say always here.

08:32.720 --> 08:34.880
I've never had much success with that.

08:34.880 --> 08:39.860
To always restart when a hot reload change doesn't take effect.

08:39.890 --> 08:45.500
I've always found it preferable and more reliable just to come back into the terminal and see what's

08:45.500 --> 08:46.910
going on with our app.

08:47.210 --> 08:49.700
So I'm just going to say yes to restart the app.

08:50.180 --> 08:56.600
And your first troubleshooting step, by the way, consistently is always just to restart the API server.

08:56.600 --> 08:59.870
If something isn't working as you would expect it.

09:00.290 --> 09:05.810
If you ask a question in the Q&amp;A and it's not clear whether or not you've taken that step, and it's

09:05.810 --> 09:11.830
not obvious that it's a different type of error, I'm always going to ask you to go back and check and

09:11.830 --> 09:17.110
make sure that the issue persists after this particular step, because it is a very common cause of

09:17.110 --> 09:23.530
issues, is just to not restart the API server after making a change.

09:23.530 --> 09:29.620
So what should happen now is we should see the correctly formatted response when we do make the request

09:29.650 --> 09:31.270
to go and get this server error.

09:31.270 --> 09:35.950
And we can see now that this is indeed JSON formatted, we've got our title, we've got the status and

09:35.950 --> 09:37.030
we've got the detail.

09:37.030 --> 09:40.540
And what we also have is in the detail the exception.

09:40.540 --> 09:46.120
We have these new lines at various places inside here.

09:46.120 --> 09:52.270
And when it comes to using and displaying this stack trace, it just formats a little bit better on

09:52.270 --> 09:54.700
our HTML when we use this.

09:54.700 --> 09:56.320
So that's our middleware enabled.

09:56.320 --> 10:01.690
And now we've got all of our server side errors effectively doing what we want them to do.

10:01.690 --> 10:06.670
So we'll move over to the client side next and set things up in there so that we can test our ability

10:06.670 --> 10:11.350
and centralize our error handling inside the client as well.
