Pavalisoft.ExceptionHandling is an open source ASP.NET Core global exception handler extension complaint with .NET Standard 2.0 written in C#, which provides ExceptionFilter and ExceptionHandlingMiddleware APIs.
The main goal of the Pavalisoft.ExceptionHandling package is to make developer's life easier to handle exceptions handling scenarios at single place and concentrate on functionality. It's additional feature ExceptionManager and inbuilt ExceptionHandlers
supports various exception handling mechanisms with configurable ExceptionSettings
By default, Pavalisoft.ExceptionHandling also supports exceptions logging and exception messages localization through ExceptionSettings configuration.
ExceptionRaiser supports to raise the exceptions from the code wherever required which should be handled through ExceptionManager using ErrorDetail.
Provides inbuilt ObjectResult
and ViewResult
specific creators and result handlers to create HttpResponseMessage
s for WebApi and WebApp implementations. While creating the ViewResult
for the handled exception, the ViewResult
creators takes the the Error ViewName
from ErrorDetail.ViewName
from ExceptionSettings. The ExceptionData object will be returned in ObjectResult
as json content and will be returned its properties/attributes as ViewData
in ViewResult
to the ErrorDetail.ViewName
view.
Complete Documentation is available at https://pavalisoft.github.io/ExceptionHandling/ for Pavalisoft.ExceptionHandling API
Refer https://github.com/pavalisoft/ExceptionHandling/tree/master/Samples for reference implementations
- Pavalisoft.ExceptionHandling.Sample - Console application :
ExceptionHandlingMiddleware
withObjectResultCreator
,ObjectResultHandler
, Application specificExceptionCodesDecider
,ExceptionSettings
in appsettings.json, exceptions logging and exception messages localization. - Pavalisoft.ExceptionHandling.NoConfigSample - Console application :
ExceptionHandlingMiddleware
withObjectResultCreator
,ObjectResultHandler
, Application specificExceptionCodesDecider
,ExceptionSettings
object creation in Program.cs, exceptions logging and exception messages localization. - Pavalisoft.ExceptionHandling.FilterSample - ASP.NET Core MVC WebApp :
ExceptionFilter
withViewResultCreator
,ViewResultHandler
, Application specificExceptionCodesDecider
,ExceptionSettings
in appsettings.json, exceptions logging and exception messages localization. - Pavalisoft.ExceptionHandling.RestFilterSample - ASP.NET Core MVC WebApi :
ExceptionFilter
withObjectResultCreator
,ObjectResultHandler
, Application specificExceptionCodesDecider
,ExceptionSettings
in appsettings.json, exceptions logging and exception messages localization. - Pavalisoft.ExceptionHandling.MiddlewareSample - ASP.NET Core MVC WebApp :
ExceptionHandlingMiddleware
withViewResultCreator
,ViewResultHandler
, Application specificExceptionCodesDecider
,ExceptionSettings
in appsettings.json, exceptions logging and exception messages localization. - Pavalisoft.ExceptionHandling.RestMiddlewareSample - ASP.NET Core MVC WebApi :
ExceptionHandlingMiddleware
withObjectResultCreator
,ObjectResultHandler
, Application specificExceptionCodesDecider
,ExceptionSettings
in appsettings.json, exceptions logging and exception messages localization.
Exception Manager Usage with ExceptionFilter
- Define the Error Details and Exception Handlers in Exceptions configuration section in appSettings.json.
{
"Exceptions": {
"EnableLocalization": "true",
"EnableLogging": "true",
"DefaultErrorDetail": "E6000",
"DefaulExceptiontHandler": "SupressHandler",
"ErrorDetails": [
{
"LogLevel": "Error",
"ErrorCode": "6000",
"StatusCode": "500",
"Message": "{0}",
"HandlerName": "SupressHandler",
"EventId": {
"Id": "1",
"Name": "General"
},
"ViewName": "ErrorResponse"
},
{
"LogLevel": "Error",
"ErrorCode": "6001",
"StatusCode": "500",
"Message": "Unhandled Exception occured.",
"HandlerName": "SupressHandler",
"EventId": {
"Id": "1",
"Name": "General"
},
"ViewName": "ErrorResponse"
},
{
"LogLevel": "Error",
"ErrorCode": "6002",
"StatusCode": "200",
"Message": "Argument {0} is null",
"HandlerName": "PropagateHandler",
"EventId": {
"Id": "1",
"Name": "General"
},
"ViewName": "ErrorResponse"
},
{
"LogLevel": "Error",
"ErrorCode": "6003",
"StatusCode": "202",
"Message": "Unbale to connect to {0} server",
"WrapMessage": "Username or password is invalid",
"HandlerName": "WrapHandler",
"EventId": {
"Id": "1",
"Name": "Secured"
},
"ViewName": "ErrorResponse"
},
{
"LogLevel": "Error",
"ErrorCode": "6004",
"StatusCode": "404",
"Message": "Argument out of index at {0}",
"HandlerName": "SupressHandler",
"EventId": {
"Id": "1",
"Name": "General"
},
"ViewName": "ErrorResponse"
}
],
"ExceptionHandlers": [
{
"Name": "SupressHandler",
"Behaviour": "Supress"
},
{
"Name": "WrapHandler",
"Behaviour": "Wrap"
},
{
"Name": "PropagateHandler",
"Behaviour": "Propagate"
}
]
}
}
- Add the resx (e.g SharedResource.resx) file with the exception localization test to the Resources folder and a class with the same name as resx file(e.g. SharedResource.cs to support localization.
Pavalisoft.ExceptionHandling.FilterSample
|- Resources
|----- SharedResource.resx
|----- SharedResource.te-in.resx
|- SharedResource.cs
using Microsoft.Extensions.Localization;
namespace Pavalisoft.ExceptionHandling.FilterSample
{
public interface ISharedResource
{
}
public class SharedResource : ISharedResource
{
private readonly IStringLocalizer _localizer;
public SharedResource(IStringLocalizer<SharedResource> localizer)
{
_localizer = localizer;
}
public string this[string index]
{
get
{
return _localizer[index];
}
}
}
}
- Add Pavalisoft.ExceptionHandling package to project then add `ExceptionFilter' to MVC services and request pipeline with logging and localization.
...
// Imports Pavalisoft.ExceptionHandling
using Pavalisoft.ExceptionHandling.ActionResultCreators;
using Pavalisoft.ExceptionHandling.ActionResultHandlers;
...
namespace Pavalisoft.ExceptionHandling.FilterSample
{
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
...
// Add Logging and Localization Middleware to services
services.AddLogging();
services.AddLocalization(options => options.ResourcesPath = "Resources");
// Adds Pavalisoft.ExceptionHandling Exception Filer to MVC Middleware services with Application Specific Exception Codes decider.
services.AddExceptionFilter<ViewResultCreator, ViewResultHandler, SharedResources, AppExceptionCodesDecider>();
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
// Uses Pavalisoft.ExceptionHandling Exception Filer in Request Pipeline
app.UseExceptionHandlingFilter();
...
}
...
}
/// <summary>
/// Application Specific Exception Codes provider implementation
/// </summary>
public class AppExceptionCodesDecider : ExceptionCodesDecider
{
public override ExceptionCodeDetails DecideExceptionCode(Exception ex)
{
if(ex is System.ArgumentOutOfRangeException)
{
return new ExceptionCodeDetails("E6004", new object[] { "test1" });
}
return base.DecideExceptionCode(ex);
}
}
}
- Use the other
services.AddExceptionFilter<ViewResultCreator, ViewResultHandler, SharedResources, AppExceptionCodesDecider>()
extension method to pass theExceptionSettings
instead of json in appsettings.json file inservices.AddExceptionFilter<ViewResultCreator, ViewResultHandler, SharedResources, AppExceptionCodesDecider>();
method.
...
// Imports Pavalisoft.ExceptionHandling
using Pavalisoft.ExceptionHandling.ActionResultCreators;
using Pavalisoft.ExceptionHandling.ActionResultHandlers;
...
namespace Pavalisoft.ExceptionHandling.FilterSample
{
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
...
// Add Logging and Localization Middleware to services
services.AddLogging();
services.AddLocalization(options => options.ResourcesPath = "Resources");
// Adds Pavalisoft.ExceptionHandling Exception Filer to MVC Middleware services with Application Specific Exception Codes decider.
services.AddExceptionFilter<ViewResultCreator, ViewResultHandler, SharedResources, AppExceptionCodesDecider>(null, CreateExceptionSettings());
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
// Uses Pavalisoft.ExceptionHandling Exception Filer in Request Pipeline
app.UseExceptionHandlingFilter();
...
}
...
private ExceptionSettings CreateExceptionSettings()
{
return new ExceptionSettings {
EnableLocalization = true,
EnableLogging = true,
DefaultErrorDetail = "E6001",
DefaulExceptiontHandler = "BaseHandler",
ErrorDetails = new List<ErrorDetail> {
new ErrorDetail
{
LogLevel = LogLevel.Error,
ErrorCode = "6001",
StatusCode = System.Net.HttpStatusCode.OK,
Message = "Unhandled Exception occurred.",
WrapMessage = "Unhandled Exception occurred.",
HandlerName = "BaseHandler",
EventId = new EventId
{
Id = 1,
Name = "General"
},
ViewName = "Error"
}
},
ExceptionHandlers = new List<ExceptionHandlerDefinition>
{
new ExceptionHandlerDefinition
{
Name = "BaseHandler",
Behaviour = HandlingBehaviour.Supress,
Config = string.Empty
}
}
};
}
}
/// <summary>
/// Application Specific Exception Codes provider implementation
/// </summary>
public class AppExceptionCodesDecider : ExceptionCodesDecider
{
public override ExceptionCodeDetails DecideExceptionCode(Exception ex)
{
if(ex is System.ArgumentOutOfRangeException)
{
return new ExceptionCodeDetails("E6004", new object[] { "test1" });
}
return base.DecideExceptionCode(ex);
}
}
}
Note: Use ObjectResultCreator
and ObjectResultHandler
in WebAPI applications instead of ViewResultCreator
and ViewResultHandler
- Use ExceptionManager and/or ExceptionRaiser methods handle and raise exceptions.
// Import Pavalisoft.ExceptionHandling interfaces
using Pavalisoft.ExceptionHandling.Interfaces;
namespace Pavalisoft.ExceptionHandling.FilterSample.Controllers
{
public class TestController : Controller
{
private readonly IExceptionManager _exceptionManager;
private readonly IExceptionRaiser _exceptionRaiser;
public TestController(IExceptionManager exceptionManager, IExceptionRaiser exceptionRaiser)
{
_exceptionManager = exceptionManager;
_exceptionRaiser = exceptionRaiser;
}
public IActionResult Index()
{
// This exception will be caught at ExceptionFilter and gets handled automatically.
throw new System.ArgumentOutOfRangeException("test");
}
public IActionResult RaiseException()
{
// Raises an exception with the error code which will be handled by
// ExceptionManager at ExceptionFilter level using the ErrorDetail having LogLevel
// as Error and ExceptionCode as 6002.
_exceptionRaiser.RaiseException("E6002", new System.ArgumentNullException(), "test");
return View();
}
public IActionResult ManageException()
{
// Handles the an exception with the error code which will be caught at ExceptionFilter level
// using the ErrorDetail having LogLevel as Error and ExceptionCode as 6002.
_exceptionManager.ManageException("E6002", new System.ArgumentNullException(), "test");
return View();
}
}
}
- Create ErrorResponse.cshtml to View/Shared folder with the below html
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<p>
<strong>Exception Code:</strong><code>@ViewData["ExceptionCode"]</code>
</p>
<p>
<strong>Message:</strong><code>@ViewData["Message"]</code>
</p>
<p>
<strong>Event Id:</strong><code>@ViewData["EventId"]</code>
</p>
<p>
<strong>Event Name:</strong><code>@ViewData["EventName"]</code>
</p>
Exception Manager Usage with ExceptionHandlingMiddleware
- Define the Error Details and Exception Handlers in Exceptions configuration section in appSettings.json.
{
"Exceptions": {
"EnableLocalization": "true",
"EnableLogging": "true",
"DefaultErrorDetail": "E6000",
"DefaulExceptiontHandler": "SupressHandler",
"ErrorDetails": [
{
"LogLevel": "Error",
"ErrorCode": "6000",
"StatusCode": "500",
"Message": "{0}",
"HandlerName": "SupressHandler",
"EventId": {
"Id": "1",
"Name": "General"
},
"ViewName": "ErrorResponse"
},
{
"LogLevel": "Error",
"ErrorCode": "6001",
"StatusCode": "500",
"Message": "Unhandled Exception occured.",
"HandlerName": "SupressHandler",
"EventId": {
"Id": "1",
"Name": "General"
},
"ViewName": "ErrorResponse"
},
{
"LogLevel": "Error",
"ErrorCode": "6002",
"StatusCode": "200",
"Message": "Argument {0} is null",
"HandlerName": "PropagateHandler",
"EventId": {
"Id": "1",
"Name": "General"
},
"ViewName": "ErrorResponse"
},
{
"LogLevel": "Error",
"ErrorCode": "6003",
"StatusCode": "202",
"Message": "Unbale to connect to {0} server",
"WrapMessage": "Username or password is invalid",
"HandlerName": "WrapHandler",
"EventId": {
"Id": "1",
"Name": "Secured"
},
"ViewName": "ErrorResponse"
},
{
"LogLevel": "Error",
"ErrorCode": "6004",
"StatusCode": "404",
"Message": "Argument out of index at {0}",
"HandlerName": "SupressHandler",
"EventId": {
"Id": "1",
"Name": "General"
},
"ViewName": "ErrorResponse"
}
],
"ExceptionHandlers": [
{
"Name": "SupressHandler",
"Behaviour": "Supress"
},
{
"Name": "WrapHandler",
"Behaviour": "Wrap"
},
{
"Name": "PropagateHandler",
"Behaviour": "Propagate"
}
]
}
}
- Add the resx (e.g SharedResource.resx) file with the exception localization test to the Resources folder and a class with the same name as resx file(e.g. SharedResource.cs to support localization.
Pavalisoft.ExceptionHandling.MiddlewareSample
|- Resources
|----- SharedResource.resx
|----- SharedResource.te-in.resx
|- SharedResource.cs
using Microsoft.Extensions.Localization;
namespace Pavalisoft.ExceptionHandling.MiddlewareSample
{
public interface ISharedResource
{
}
public class SharedResource : ISharedResource
{
private readonly IStringLocalizer _localizer;
public SharedResource(IStringLocalizer<SharedResource> localizer)
{
_localizer = localizer;
}
public string this[string index]
{
get
{
return _localizer[index];
}
}
}
}
- Add Pavalisoft.ExceptionHandling package to project then add `ExceptionFilter' to MVC services and request pipeline with logging and localization.
...
// Imports Pavalisoft.ExceptionHandling
using Pavalisoft.ExceptionHandling.ActionResultCreators;
using Pavalisoft.ExceptionHandling.ActionResultHandlers;
...
namespace Pavalisoft.ExceptionHandling.MiddlewareSample
{
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
...
// Add Logging and Localization Middleware to services
services.AddLogging();
services.AddLocalization(options => options.ResourcesPath = "Resources");
// Adds Pavalisoft.ExceptionHandling Middleware to MVC Middleware services with Application Specific Exception Codes decider.
services.AddExceptionHandling<ViewResultCreator, ViewResultHandler,SharedResource, AppExceptionCodesDecider>();
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
// Uses Pavalisoft.ExceptionHandling Middleware in Request Pipeline
app.UseExceptionHandlingMiddleware();
...
}
...
}
/// <summary>
/// Application Specific Exception Codes provider implementation
/// </summary>
public class AppExceptionCodesDecider : ExceptionCodesDecider
{
public override ExceptionCodeDetails DecideExceptionCode(Exception ex)
{
if(ex is System.ArgumentOutOfRangeException)
{
return new ExceptionCodeDetails("E6004", new object[] { "test1" });
}
return base.DecideExceptionCode(ex);
}
}
}
- Use the other
services.AddExceptionHandling<ViewResultCreator, ViewResultHandler, SharedResources, AppExceptionCodesDecider>()
extension method to pass theExceptionSettings
instead of json in appsettings.json file inservices.AddExceptionFilter<ViewResultCreator, ViewResultHandler, SharedResources, AppExceptionCodesDecider>();
method.
...
// Imports Pavalisoft.ExceptionHandling
using Pavalisoft.ExceptionHandling.ActionResultCreators;
using Pavalisoft.ExceptionHandling.ActionResultHandlers;
...
namespace Pavalisoft.ExceptionHandling.MiddlewareSample
{
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
...
// Add Logging and Localization Middleware to services
services.AddLogging();
services.AddLocalization(options => options.ResourcesPath = "Resources");
// Adds Pavalisoft.ExceptionHandling Middleware to MVC Middleware services with Application Specific Exception Codes decider.
services.AddExceptionHandling<ViewResultCreator, ViewResultHandler,SharedResource, AppExceptionCodesDecider>(null, CreateExceptionSettings());
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
// Uses Pavalisoft.ExceptionHandling Middleware in Request Pipeline
app.UseExceptionHandlingMiddleware();
...
}
...
private ExceptionSettings CreateExceptionSettings()
{
return new ExceptionSettings {
EnableLocalization = true,
EnableLogging = true,
DefaultErrorDetail = "E6001",
DefaulExceptiontHandler = "BaseHandler",
ErrorDetails = new List<ErrorDetail> {
new ErrorDetail
{
LogLevel = LogLevel.Error,
ErrorCode = "6001",
StatusCode = System.Net.HttpStatusCode.OK,
Message = "Unhandled Exception occurred.",
WrapMessage = "Unhandled Exception occurred.",
HandlerName = "BaseHandler",
EventId = new EventId
{
Id = 1,
Name = "General"
},
ViewName = "Error"
}
},
ExceptionHandlers = new List<ExceptionHandlerDefinition>
{
new ExceptionHandlerDefinition
{
Name = "BaseHandler",
Behaviour = HandlingBehaviour.Supress,
Config = string.Empty
}
}
};
}
}
/// <summary>
/// Application Specific Exception Codes provider implementation
/// </summary>
public class AppExceptionCodesDecider : ExceptionCodesDecider
{
public override ExceptionCodeDetails DecideExceptionCode(Exception ex)
{
if(ex is System.ArgumentOutOfRangeException)
{
return new ExceptionCodeDetails("E6004", new object[] { "test1" });
}
return base.DecideExceptionCode(ex);
}
}
}
Note: Use ObjectResultCreator
and ObjectResultHandler
in WebAPI applications instead of ViewResultCreator
and ViewResultHandler
- Use ExceptionManager and/or ExceptionRaiser methods handle and raise exceptions.
// Import Pavalisoft.ExceptionHandling interfaces
using Pavalisoft.ExceptionHandling.Interfaces;
namespace Pavalisoft.ExceptionHandling.MiddlewareSample.Controllers
{
public class TestController : Controller
{
private readonly IExceptionManager _exceptionManager;
private readonly IExceptionRaiser _exceptionRaiser;
public TestController(IExceptionManager exceptionManager, IExceptionRaiser exceptionRaiser)
{
_exceptionManager = exceptionManager;
_exceptionRaiser = exceptionRaiser;
}
public IActionResult Index()
{
// This exception will be caught at ExceptionHandlingMiddleware and gets handled automatically.
throw new System.ArgumentOutOfRangeException("test");
}
public IActionResult RaiseException()
{
// Raises an exception with the error code which will be handled by
// ExceptionManager at ExceptionHandlingMiddleware level using the ErrorDetail having LogLevel
// as Error and ExceptionCode as 6002.
_exceptionRaiser.RaiseException("E6002", new System.ArgumentNullException(), "test");
return View();
}
public IActionResult ManageException()
{
// Handles the an exception with the error code which will be caught at ExceptionHandlingMiddleware level
// using the ErrorDetail having LogLevel as Error and ExceptionCode as 6002.
_exceptionManager.ManageException("E6002", new System.ArgumentNullException(), "test");
return View();
}
}
}
- Create ErrorResponse.cshtml to View/Shared folder with the below html
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<p>
<strong>Exception Code:</strong><code>@ViewData["ExceptionCode"]</code>
</p>
<p>
<strong>Message:</strong><code>@ViewData["Message"]</code>
</p>
<p>
<strong>Event Id:</strong><code>@ViewData["EventId"]</code>
</p>
<p>
<strong>Event Name:</strong><code>@ViewData["EventName"]</code>
</p>
The below are the inbuilt exception handlers provided.
- DefaultExceptionHandler : Provides Default implementation.
- WrapExceptionHandler : Provides implementation to wrap the exception after handling.
The below are the inbuilt action result creators provided.
- ObjectResultCreator : Provides implementation to create
ObjectResult
usingErrorDetail
. - ViewResultCreator : Provides implementation to create
ViewResult
with the ViewName in theErrorDetail
.
The below are the inbuilt action result handlers provided.
- ObjectResultHandler : Provides features to handle REST API Application additional exception handling conditions.
- ViewResultHandler : Provides features to handle Web Application additional exception handling conditions.
Get latest builds from nuget
Package | Version |
---|---|
Pavalisoft.ExceptionHandling | 1.0.0 |
Getting started with Git and GitHub
- Setting up Git for Windows and connecting to GitHub
- Forking a GitHub repository
- The simple guide to GIT guide
- Open an issue if you encounter a bug or have a suggestion for improvements/features
Once you're familiar with Git and GitHub, clone the repository and start contributing.