I am looking for a simple solution to do Exception Logging combined with Error Handling in my ASP.Net MVC 1.0 application.
I\'ve read lots of articles, including Questio
I'm still a bit confused with all the different solutions out there, and how attributes can interfere with each other, but I went with this solution:
public class LogErrorsAttribute: FilterAttribute, IExceptionFilter
{
#region IExceptionFilter Members
void IExceptionFilter.OnException(ExceptionContext filterContext)
{
if (filterContext != null && filterContext.Exception != null)
{
string controller = filterContext.RouteData.Values["controller"].ToString();
string action = filterContext.RouteData.Values["action"].ToString();
string loggerName = string.Format("{0}Controller.{1}", controller, action);
log4net.LogManager.GetLogger(loggerName).Error(string.Empty, filterContext.Exception);
}
}
#endregion
}
I still use the [HandleError] attribute as explained in the original question, and I just decorate each controller with a [LogErrors] attribute.
This works for me, as it keeps the error logging in one place and doesn't cause duplicate exceptions to be logged multiple times (which will happen if I extend [HandleError] and use the attribute in multiple places).
I don't think it will be possible to combine both the Exception Logging and Error Handling into one atrribute or class, without it becoming very tedious and complex, or affecting the use of [HandleError]
But this works for me since I decorate each controller only once, with the [LogErrors] attribute, and decorate Controllers and Actions with [HandleError] exactly how I want to, without them interfering with each other.
Update:
Here is an example of How I use it:
[LogErrors(Order = 0)]
[HandleError(Order = 99)]
public class ContactController : Controller
{
public ActionResult Index()
{
return View(Views.Index);
}
public ActionResult Directions()
{
return View(Views.Directions);
}
public ActionResult ContactForm()
{
FormContactMessage formContactMessage = new FormContactMessage();
return View(Views.ContactForm,formContactMessage);
}
[HandleError(ExceptionType = typeof(SmtpException), View = "MessageFailed", Order = 1)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ContactForm(FormContactMessage formContactMessage)
{
if (ModelState.IsValid)
{
if (formContactMessage.IsValid)
{
SmtpClient client = new SmtpClient();
MailAddress recipientAddress = new MailAddress(Properties.Settings.Default.ContactFormRecipientEmailAddress);
MailAddress senderAddress = new MailAddress(Properties.Settings.Default.ContactFormSenderEmailAddress);
MailMessage mailMessage = formContactMessage.ToMailMessage(recipientAddress, senderAddress);
client.Send(mailMessage);
return View("MessageSent");
}
else
{
ModelState.AddRuleViolations(formContactMessage.GetRuleViolations());
}
}
return View(Views.ContactForm, formContactMessage);
}
private static class Views
{
public static string Index { get { return "Index"; } }
public static string Directions { get { return "Directions"; } }
public static string ContactForm { get { return "ContactForm"; } }
}
}
In the above code, SmtpExceptions in the ContactForm
action overload are handled in a very specific way - the user is presented with a ViewPage specific to failed sent messages, in this case it is called "MessageFailed" . All other exceptions are handled by the default behaviour of [HandleError]. Also note that logging of errors occurs first, followed by handling of errors. This is indicated by the following:
[LogErrors(Order = 0)]
[HandleError(Order = 99)]
Update:
There is an alternative solution to this, with a very good explanantion. I recommend reading through it to get a better understanding of the issues involved.
ASP.NET MVC HandleError Attribute, Custom Error Pages and Logging Exceptions (Thanks to Scott Shepherd below, who provided the link in an answer below).