Custom error handling globally in asp.net web api - c#

I am using asp.net web api.
[Route("api/employee")]
[HttpPost]
public dynamic GetData(EmployeeModel model)
{
EmployeeService emp = new EmployeeService();
emp.GetData(model);
}
This is how I am handling error globally:
public class ExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
//Code to log the exception goes here:
}
}
in the WebApiConfig.cs file, I am registering the filter:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
....
config.Filters.Add(new ExceptionFilter());
}
}
Whenever there is an exception, the exception filter is able to catch the exception & It can log the exception. All this is working fine.
What I want: With every exception, I want to log specific details, those details are available in respective methods but how do I pass them to exception filter? The only work around I see is, add try catch block in individual methods and log the exception along with specific details.
Another thing that I want to capture is the request object of each request. In this case it will be ExployeeModel. Even if I somehow get the request object, how to I type cast into correct type. One endpoint can expect EmployeeModel other can expect DepartmentModel.

Related

Log all handles exception

How can I log all handled exceptions?
I want that whenever I catch an exception I should be able to log it
I want it to work globally and not that i should have to write it each time I catch
I tried subscribing to AppDomain.CurrentDomain.FirstChanceException and it did work but I did not have the full stack trace and it called multiple times for each exception (I don't know why)
I also tried wrapping my controller with ActionFilterAttribute like below and it worked on all exception from the controller only and not if the exception was caught in a service that was called from the controller
public class ExceptionLoggingHandler : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if(filterContext.Exception !=null)
{
System.Diagnostics.Debug.WriteLine(filterContext.Exception.Message);
}
base.OnResultExecuted(filterContext);
}
}
In ASP.NET MVC, you can add your filter as a global filter in the RegisterGlobalFilters method inside FilterConfig.cs. It should then catch all exceptions in all controller actions, and in any methods called from those actions - unless of course those methods already have catch blocks inside them which swallow the exception. In that case the caught exception (unless it's then re-thrown) will inevitably go undetected higher up the stack, which is, naturally, the whole point of catching exceptions.
e.g.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new ExceptionLoggingHandler());
}
}
Also, your attribute should inherit from HandleErrorAttribute, not ActionFilterAttribute.
Something like this:
public class ExceptionLoggingHandler : HandleErrorAttribute
{
public ExceptionLoggingHandler() : base()
{
}
public override void OnException(ExceptionContext context)
{
System.Diagnostics.Debug.WriteLine(context.Exception.Message);
context.ExceptionHandled = true;
//.... continue to produce a suitable response
}
}
(In the .... area you can continue to develop the handler to log more sophisticated data, and return a suitable response, perhaps along the lines of this one (other examples are also available online.)

Exception Attribute for Class library

My service class has many methods, which call other service and this service has specified exceptions. I want to throw my exception when method catch this specified exception.
I.e.
try
{
// call other service
}
catch(ServiceXxxException serviceEx)
{
throw new MyException(...);
}
but I have many such methods and I don't want to grow code. Is it possible to create exception attribute like ExceptionFilterAttribute for ASP.NET MVC/Core ?
You can create general filter to handle any exception may occur and you can use filter attribute to handle, you can use it within the controller or action, something like this :
CustomExceptionFilter]
public class HomeController:Controller
{
//......
}
//Over the Action
[CustomExceptionFilter]
public ActionResult Index()
{
//.......
}
please follow this article :
https://www.c-sharpcorner.com/UploadFile/0ef46a/exception-filters-in-mvc/

How to add value to the default exception response in ABP?

I want to add an ID (GUID) to the exception and:
Log it
Return it to the client json response
Where should I generate this log ID value and add it to the exception message that is logged. And where to change the following default response?
{
"targetUrl": null,
"result": null,
"success": false,
"error": {
"message": "An internal error occurred during your request!",
"details": "..."
},
"unAuthorizedRequest": false
}
I am using .NET Core version.
If you want to disable displaying the message for a particular AJAX call, add abpHandleError: false into the abp.ajax options.
Or you can disable the default behavior of the framework exception wrapper
public class PeopleController : AbpController
{
[HttpPost]
[WrapResult(WrapOnSuccess = false, WrapOnError = false)]
public JsonResult SavePerson(SavePersonModel person)
{
//TODO: save new person to database and return new person's id
return Json(new {PersonId = 42});
}
}
https://aspnetboilerplate.com/Pages/Documents/Javascript-API/AJAX?searchKey=wrap#asp-net-mvc-controllers
Another thing is; you can send exception details to the client by the below configuration
...
using Abp.Web.Configuration;
...
public override void PreInitialize()
{
Configuration.Modules.AbpWebCommon().SendAllExceptionsToClients = true;
}
...
https://aspnetboilerplate.com/Pages/Startup-Configuration#configuring-modules
Result Wrapping & Exception Handling:
ASP.NET Boilerplate does not wrap Web API actions by default if an action has successfully executed. It, however, handles and wraps exceptions. You can add the WrapResult/DontWrapResult attributes to actions and controllers for finer control. You can change this default behavior from the startup configuration (using Configuration.Modules.AbpWebApi()...). See the AJAX document for more info about result wrapping.
https://aspnetboilerplate.com/Pages/Documents/Web-API-Controllers?searchKey=wrap#result-wrapping-exception-handling
Wrapping Results
ASP.NET Boilerplate wraps the return values of dynamic Web API actions using an AjaxResponse object. See the ajax documentation for more information on wrapping. You can enable/disable wrapping per method or per application service. See this example application service:
public interface ITestAppService : IApplicationService
{
[DontWrapResult]
DoItOutput DoIt(DoItInput input);
}
https://aspnetboilerplate.com/Pages/Documents/Dynamic-Web-API?searchKey=wrap#wrapping-results
Lastly you can write your own ResultWrapperHandler...
public class CustomResultWrapperHandler : ResultWrapperHandler, ITransientDependency
{
//...
protected override void WrapResultIfNeeded(HttpRequestMessage request, HttpResponseMessage response)
{
//...
base.WrapResultIfNeeded(request, response);
}
}
if you want to get special message in some case you can use
throw new UserFriendlyException("your message");
the above code just effects on error message and doesn't show the details.
so its good option for production version.

ASP.NET Core Exception middelware nesting exceptions for each layer

I created a global Exception handler middelware to catch all my custom exceptions.
When throwing an Exception in my DAL I expect that the middelware will catch it as the same type that it was thrown.
// API
[HttpGet]
[Route("api/users")]
public IActionResult Get(int id)
{
var user = _userService.GetById(id);
return Ok(user);
}
// Repository
public async Task<List<User>> GetById(int id)
{
throw new EntityNotFoundException("code", "message");
// .. return user
}
// Exception handler
public async Task Invoke(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex) // ex is of type JsonSerializationException
{
if (ex is EntityNotFoundException)
{
// Handle exception
}
}
}
In the above example the Exception is handled but is of type JsonSerializationException with an InnerException of type System.AggregateException that contains another InnerException with type EntityNotFoundException.
It seems that the Exception gets nested for each layer it gets passed along (DAL > Service > API). How can I avoid this so that I can catch the Exception as the original type?
The example you provided looks good but it lacks one important thing, which is single responsibility.
ASP.NET Core has a better approach, which is using exception filters, that can be registered globally too and can be written for each custom-exception and even for unhandled exceptions.
Sample:
public class EntityNotFoundExceptionFilter : IExceptionFilter
{
public EntityNotFoundExceptionFilter(// some dependencies that u want to inject)
{
...
}
public void OnException(ExceptionContext context)
{
if (!(context.Exception is EntityNotFoundException))
{
return;
}
context.ExceptionHandled = true;
context.Result = new NotFoundObjectResult // will produce 404 response, you can also set context.HttpContext.Response.StatusCode based on your exceptions statuscode and return an ObjectResult instead
{
context.Exception.Message
}
}
}
Now in your Startup.cs in the ConfigureServices(...) function add the following
public void ConfigureService(IServiceCollection services)
{
...
services.AddMvc(options =>
{
...
options.Filters.Add(typeof(EntityNotFoundExceptionFilter));
...
}
...
}
You will end up writing many filters but it is a cleaner approach and that is how the asp.net-core filterpipeline should be used + this will be working :)
I am not 100% sure why there are so many exceptions in your current implementation but my guess is that asp.net tries to return the exception and then fails to serialize it and stuff like that.
Edit:
I create a minimal example that can be found here. Just access the url via http://localhost:58741/api/some after cloning the project.

Global Error Handling in MVC 6

In my MVC 5 application unhandled exception are capture within the Global Application_Error event and then redirected to ErrorController.
The last error is added to HttpApplicationState in the Global.Error event and retrieved in the Controller.
MVC 6 doesn't have the Global file. it uses the IExceptionFilter in capturing the unhandled exception.
public class GlobalExceptionFilter : IExceptionFilter, IDisposable {
private readonly ILogger logger;
private bool _disposed;
public GlobalExceptionFilter(ILoggerFactory logger) {
if (logger == null) {
throw new ArgumentNullException(nameof(logger));
}
this.logger = logger.CreateLogger("Global Exception Filter");
}
public void OnException(ExceptionContext context) {
logger.LogError("GlobalExceptionFilter", context.Exception);
//redirect to controller
}
public void Dispose() {
if (this._disposed) {
return;
}
this._disposed = true;
}
private static int GetHttpStatusCode(Exception ex) {
if (ex is HttpResponseException) {
return (int)(ex as HttpResponseException).HttpStatusCode;
}
return (int)HttpStatusCode.InternalServerError;
}
}
Is it possible to do the same in OnException?
From asp.net core documentation (check here)
In general, filters are meant to handle cross-cutting business and
application concerns. This is often the same use case for middleware.
Filters are very similar to middleware in capability, but let you
scope that behavior and insert it into a location in your app where it
makes sense, such as before a view, or after model binding. Filters
are a part of MVC, and have access to its context and constructs. For
instance, middleware can’t easily detect whether model validation on a
request has generated errors, and respond accordingly, but a filter
can easily do so.
Based on explanation of this documentation. Both middle ware approach and filter approach will meet your requirements. If you need more information of MVC pipeline and its information of errors, you should use filter approach.

Categories

Resources