Asp.Net exception handling module¶
The exception handling module is comprised of these main components:
- An exception handling middleware
- An exception to http converter
- An exception to problem details converter
The exception handling module sits on top of the ASP.NET Core
execution
pipeline and is responsible of handling the exception thrown by any component in
the upstream execution pipeline.
Info
The exception handling module has some limitations: It depends on
ASP.NET Core
(there is no current support for Console Apps
for example)
and the only supported media type
is json
, actually application/problem+json
,
it has its own type, but is still json
based.
The exception handling middleware
performs several steps during the exception
handling, which includes exception logging, translate the exception to its
corresponding http status code
using an IExceptionToHttpStatusCodeConverter
instance, construct the ProblemDetails
representation using the
IExceptionToProblemDetailsConverter
instance, and finally serializes the
ProblemDetail
instance using the current Mvc
contract serializer options.
IExceptionToHttpStatusCodeConverter
and IExceptionToProblemDetailsConverter
implementations can be replaced supplying customized implementation, if needed.
Take into account that IExceptionToProblemDetailsConverter
provide several
extensibility points in the form of protected virtual methods
that can be
overwritten if you do not want to create your implementation from the scratch.
Please continue reading the next sections to get a deeper understanding of the features and components offered by this module.
Configuring the module¶
The module is added by default to the ASP.NET Core
pipeline if your
application extends from SuiteAspNetApplicationModule
. Nevertheless, if you
want to do it by your own in your custom module implementation, or to configure
the module options through ExceptionHandlingModuleOptions
, you should do as
following:
C# | |
---|---|
The ProblemDetailsTypeBaseUri
must be set to the unique Uri
base identifier
defined for your application. It is unique for the overall application features,
it runs at the module pipeline and any exception handled will use this base path
to build up the resulting ProblemDetails
' Type
attribute value.
If you want to instruct the module to do specific mapping for some exceptions,
you need to map them using the MapExceptionToHttpStatusCode
of the
ExceptionHandlingModuleOptions
instance.
Customizing the module behavior¶
If you want to customize module behavior you can extend or replace the
IExceptionToHttpStatusCodeConverter
and/or
IExceptionToProblemDetailsConverter
which provides the conversions to
HttpStatusCode
the former and to ProblemDetails
the latter.
Localizable exceptions¶
The framework provide a generic localizable exception called
LocalizedException
, which requires a generic type argument indicating the
localization resource type identifier to get the localized resource from.
This exception, besides the said generic type parameter, requires the
specification of a localization key
to identify the localized text to be used
when localization process is performed. Let's see an example:
C# | |
---|---|
From the previous example we can note that MyModuleResources
is the resource
bundle type identifier, and MSG_LOCALIZED_EXCEPTION
is the localization key to
be used to localize the exception message. The first argument is the exception
message and is used for internal purposes only, such as logging, whereas the
localized exception is what is more likely to be seen by the end user or
displayed in the GUI.
Note that LocalizedException
is a concrete class, not abstract. It means that
you can use directly, as in the example shown before, nevertheless you should
provide more meaningful exceptions instead of use the generic ones.
Using templated localization resources¶
The localized resource value may be a template instead of a static string. This
template can provide placeholders for it replacement at runtime. The values used
to fill in those placeholders are taken from the LocalizationData
dictionary,
where each placeholder must match wih the key of the item in the dictionary.
In the following example we can see the usage of the localization data
dictionary to provide runtime values for the localization resource template
identified by MSG_LOCALIZED_EXCEPTION_TEMPLATE
key.
The json
localization resource looks like this:
JSON | |
---|---|
Warn
The placeholders in the localization resource must be enclosed in brackets, and referencing the dictionary value by its key (eg. "..{itemKey1}...{itemKey2}"). This placeholder representation differs from the standard form using positional indexed placeholders ("[0]..[1]").
Exception logging¶
Exceptions can specify the error log level to be used during exception handling
process. If you want to specify the level you should implement
IHasErrorLogLevel
interface and return the log level you want to be used for
the logging process of your exception.
If you want to have a more fine grained logging process control, you can provide
a specific logging behavior by implementing ISupportLog
interface and provide
the custom logging logic in the Log
method. The logger instance will be
provided at runtime by the Exception Handling Middleware
.
Adding custom data to ProblemDetails
¶
The ProblemDetails
object can be used to hold and render extra data. These
extra data values must be added by the application and helps the API client to
know more about the error ocurred.
The Data
dictionary is defined in Exception
class, therefore all specialized
exceptions types inherits this dictionary. Any value added to it will be pushed
into the resulting ProblemDetails
error object.
C# | |
---|---|
Exceptions with error codes¶
Exception can provide error codes to provide a more clearer understanding for
the clients of what happened server-side. Error code will be appended to the end
of the ProblemDetails
' Type
attribute.
For example given the value http://itsynch.com/myApp/errors
for the
ProblemDetailsTypeBaseUri
attribute, if an exception provides the code
MA-001
, the resulting ProblemDetails
' Type
will be:
JSON | |
---|---|
The usage of a standard error code nomenclature is encouraged.
Built-in provided exceptions¶
The Suite Framework provides some built-in implementations.
LocalizedException¶
This exception does not provide domain information about the error, it is intended to be used as base exception not to be used directly.
EntityNotFoundException¶
This exception has a meaning for the business: it is thrown when an entity is not found when we expected to found it. Typically when a search by identifier is done and we expect to encounter the entity, but we could not, and we can't go further from this point on.
This entity is localized at runtime providing locale aware information in the corresponding language, and admit two values:
- EntityType: the entity type we were searching for.
- EntityId: the id we were searching for.
EntityType and EntityId will be used to fill in the placeholders of the localization resource related with this exception.
EntityNotFoundException
will be always translated to the Not Found
HTTP
status code, which is 404.
BusinessException¶
This exception represents an error in our business domain. This error implements
IBusinessException
(which in turns implements IHasErrorCode
),
ICanLocalizeExceptionDetails
and extends from LocalizedException
, this means
that the exception can provide localized information about it message and
details about it as well.
A more detailed example of a business exception is show here below:
The example depict how to provide exception code, exception message and keys for
message and detail localized values, supplied in the constructor. Also a
localization value is provided to be used at runtime. Finally some extra data
values are provided which will be rendered in the resulting ProblemDetails
error object.
BusinessException
will be always translated to the Bad Request
HTTP status
code, which is 400. If you want to know more about the type BusinessException
you will need to use the Type
attribute of the ProblemDetails
error object.
Use a standard error code for Suite applications¶
The usage of a standard and uniform error naming rule is encouraged. Please use the following naming rule to identify error codes:
Bash | |
---|---|
Where: APP-CODE: is an alphanumeric value with four characters max. ERROR-NUMBER: is numeric value with six digits max, padding left spaces with zeroes.
For example:
- AIMS-000001: stands for error 1 for AIMS application.
- IINS-000105: stands for error 105 for iInspector application.