Okay to continue on from the previous lesson, we're going to populate our handle exception method.
What do we want to do when we do encounter an exception in our dotnet code.
So inside this private method this handle exception method let's just remove the throw new exception.
And first of all we'll use our logger.
And we'll say log error.
And we'll pass in the exception called x.
And we'll use the message property from there and effectively output our exception into the log.
Now we're going to update our response that we send back to the client.
Now we have access to the Httpcontext.
So we'll specify context.
And then the response.
This gives us access to that.
And we can set the content type.
And we're going to set it to be application forward slash JSON.
So this will ensure that we send back a JSON formatted Response, and we'll also set the context.
Dot response dot status code.
And we're going to set this equal to and we'll cast this into an integer.
So in parentheses specify int.
And then we'll use one of the constants that's provided from system.net the HTTP status code and the
internal server error.
And then we'll create our response.
So I'll say var response equals new.
And we can use the class from Microsoft ASP.Net core MVC called Problem Details.
Inside here we can specify the status and make sure we bring this in.
And inside here we can specify the status.
And I'm just going to set this to 500 for a status code of 500.
Lead detail.
We're going to check to see what environment we're running in.
So if env is development then we want to send back the full stack trace.
So we'll use a ternary operator here.
So if we are in development we'll specify x dot stack trace and use the two string method on it, which
we need to make sure is optional because it may or may not be present.
So we don't want to cause an exception inside our exception.
If we don't have a stack trace and we don't use this optional chaining, then that would throw an exception
inside our exception handler.
Who knows what would happen in that scenario.
Actually, our application would just throw an unhandled exception in that case, and it wouldn't break
the internet or anything like that.
And if we do not have the stack trace, then it's just going to be null.
And if we're not in development mode, then we're just going to return null for the detail.
And below this we'll specify a title and we'll set it to x dot message.
So that's what we're going to return.
And then we'll specify our options because we want to use our JSON serialized response.
We want to give it its standard formatting.
We're not in the context of an API controller inside our exception middleware.
When we're inside an API controller.
Net will format the JSON response correctly, which means giving it camel casing.
So we're going to create some options for our JSON serializer and say new JSON serialize options.
And then we'll open curly brackets and we'll set the property naming policy.
And we're going to set this equal to JSON naming policy dot CamelCase.
That's the correct format for a JSON response.
Then we'll create the JSON.
In fact let's move that below the options so I don't go off the edge of the screen below.
This will save our JSON equals JSON serializer.
And we're going to serialize our response.
So we'll pass in the response.
And then we'll pass in as a second parameter the options we created above.
and then we can return this response.
So we'll say await context dot response and write async and pass in JSON.
So great.
That's now our middleware created.
And now let's see how we use this in our program class.
So let's open up the Program.cs.
Now we need two elements here because inside our middleware what we've used is an interface for the
AI middleware.
Now when we use a service like this, even though it's a service provided by dotnet, the AI middleware
service, then we still need to provide this as a service inside our program class.
And the reason for that is we're using dependency injection here to inject the AI host environment and
the logger.
And if we want to inject anything into something that we're using, then this has to be declared as
a service inside our program class.
And we also need to add this as Middleware inside there as well.
So first of all, let's take a look at adding this as a service.
Now in this part of our code where we add services to the container I'm sure I've mentioned it before,
but the ordering isn't particularly important inside here.
We can put this service wherever we want.
I'm just going to add it below the add, cause it really doesn't matter.
But I'm going to say builder and then services and I'm going to add transients here.
Now there's different options of how we want.
Net framework to manage a service.
There's add transients.
There's add scopes and there's add singleton all of which are available for us to choose as to how do
we want the framework to initialize this service, and how do we want it to dispose of this service.
The most common one that we'll use is add scoped.
And if I just go back to the middleware pipeline, then scoped means effectively that the service will
be created when the request comes in, and will be available for the entirety of this request, so this
is ad scoped.
If I use ad transient, then the service is only created for the specific method where it is needed.
So I'll just highlight this as to the scope of when this service will be instantiated and when it will
be disposed of.
And the other approach is to use a singleton which would be fully or it would be instantiated when the
application starts and it's only disposed of when the application is finished.
Now for this specific service that we're using, transient is the most appropriate because we don't
expect we're going to have exceptions at every part of our application.
Exceptions should be exceptional.
We only really want to instantiate our AI middleware service effectively when it's actually needed,
as an exception is being thrown.
So a transient is the appropriate level for this particular service.
And later we'll be adding our own scoped services because we would want them scoped to the request when
it comes in and not disposed of until the request is finished.
But for this one we're going to specify a transient.
And we need to specify exception middleware as the service that we're using here.
This is the service where we're injecting the logger and the host environment.
Now we also need to add our new middleware to the HTTP request pipeline.
And ordering is important inside here.
And because it's our exception middleware, we need this to be at the very top of the pipeline so that
any other middleware can throw an exception, and then that will get passed back up the middleware pipeline
until it reaches something that can catch that exception.
So the idea is we stick this at the top.
So we're going to say app use middleware.
And then we're going to pass in exception middleware inside there.
Now that should be enough for us to test this.
And I doubt that hot reloading could accommodate our changes there.
So if we open up the terminal it does ask us if we want to restart our app.
I'm going to say yes.
And you might be tempted to say always here.
I've never had much success with that.
To always restart when a hot reload change doesn't take effect.
I've always found it preferable and more reliable just to come back into the terminal and see what's
going on with our app.
So I'm just going to say yes to restart the app.
And your first troubleshooting step, by the way, consistently is always just to restart the API server.
If something isn't working as you would expect it.
If you ask a question in the Q&A and it's not clear whether or not you've taken that step, and it's
not obvious that it's a different type of error, I'm always going to ask you to go back and check and
make sure that the issue persists after this particular step, because it is a very common cause of
issues, is just to not restart the API server after making a change.
So what should happen now is we should see the correctly formatted response when we do make the request
to go and get this server error.
And we can see now that this is indeed JSON formatted, we've got our title, we've got the status and
we've got the detail.
And what we also have is in the detail the exception.
We have these new lines at various places inside here.
And when it comes to using and displaying this stack trace, it just formats a little bit better on
our HTML when we use this.
So that's our middleware enabled.
And now we've got all of our server side errors effectively doing what we want them to do.
So we'll move over to the client side next and set things up in there so that we can test our ability
and centralize our error handling inside the client as well.