ASP.NET C# Catch all exceptions in a class
I know this is not the way to do it, and it isn't clean at all. I just wonder if it's possible.
If I have a class with a bunch of methods
public class Foo {
methodA() {}
methodB() {}
metho开发者_运维知识库dC() {}
}
Is it possible to catch all exceptions that could possibly occur without having to write a try/catch in each method?
Yes it is. The simplest way would be a Attribute for this class like this one:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class HandleErrorAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (filterContext.ExceptionHandled)
{
return;
}
var exception = filterContext.Exception;
// that need to be your current request object. In this case I use a custom one so I must fetch it from the items collection of the current request, where I had stored it before.
var request = filterContext.HttpContext.Items[Request.RequestKey] as Request;
if (request != null)
{
// overwrite ErrorResponse with a response object of your choice or write directly to the filterContext.HttpContext.Response
var errorResponse = new ErrorResponse(request, exception);
errorResponse.Write(filterContext.HttpContext.Response);
filterContext.ExceptionHandled = true;
}
}
}
// Or a just slightly modified version of the default ASP.Net MVC HandleError Attribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CustomHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
// Fields
private const string _defaultView = "Error";
private string _master;
private readonly object _typeId = new object();
private string _view;
// Methods
public virtual void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.IsChildAction && (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled))
{
Exception innerException = filterContext.Exception;
if ((new HttpException(null, innerException).GetHttpCode() == 500))
{
string controllerName = (string)filterContext.RouteData.Values["controller"];
string actionName = (string)filterContext.RouteData.Values["action"];
HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
ViewResult result = new ViewResult();
result.ViewName = this.View;
result.MasterName = this.Master;
result.ViewData = new ViewDataDictionary<HandleErrorInfo>(model);
result.TempData = filterContext.Controller.TempData;
filterContext.Result = result;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
}
public string Master
{
get
{
return (this._master ?? string.Empty);
}
set
{
this._master = value;
}
}
public override object TypeId
{
get
{
return this._typeId;
}
}
public string View
{
get
{
if (string.IsNullOrEmpty(this._view))
{
return "Error";
}
return this._view;
}
set
{
this._view = value;
}
}
}
Usage (untested cause I used it in context of controller that already implement all required interfaces)
[HandleErrorAttribute]
public class Foo : IExceptionFilter // (I am not sure about this one IActionFilter)
{
public void MethodA()
{
// body
}
public void MethodB()
{
// body
}
public void MethodC()
{
// body
}
}
Or you can do something like this:
public class ExecuteHelper
{
public static void Catch(Action action)
{
try
{
action();
}
catch (Exception ex)
{
// Do what you want
}
}
}
And use it in a Function body:
public void Foo(string something)
{
ExecuteHelper.Catch(() =>
{
// Do something with something or without something
});
}
You could write a higher order function to handle the exceptions, which would make it somewhat cleaner.
private T FooExceptionHandler(Func<T> function)
{
try
{
return function();
}
catch
{
//handle it
}
}
You can replace Func with Action if you don't have a return value. You can use it in two ways, outside of the function:
FooExceptionHandler(MethodA);
or inside each function:
MethodA()
{
return FooExceptionHandler(()=>
{
//Function body goes here
});
}
No, there isn't. try
/catch
blocks can only occur in methods. You could use some sort of AOP framework however to automatically generate those blocks. postcrap is a pretty lightweight AOP component.
You can handle it in the function that calls these methods...
By default, in ASP.NET you can override the OnError
method and then do Server.ClearError
to dispose of the exception.
I'm not sure if it applies to your case (only works in Page
and Global.asax
)
精彩评论