Step one - create my own controller class. Simple, just add a BaseController to the Controllers folder
public abstract class BaseController : Controller { }
and then modify all existing contollers to inherit from BaseController rather than from System.Web.Mvc.Controller.
Next, I override the OnException method in the BaseController which is called whenever the exception is thrown within an action.
public abstract class BaseController : Controller { protected override void OnException(ExceptionContext filterContext) { var fileName = Path.Combine(Request.MapPath("~/App_Data"), "log.txt"); WriteLog(fileName, filterContext.Exception.ToString()); filterContext.ExceptionHandled = true; this.View("Error").ExecuteResult(this.ControllerContext); } static void WriteLog(string logFile, string text) { StringBuilder message = new StringBuilder(); message.AppendLine(DateTime.Now.ToString()); message.AppendLine(text); message.AppendLine("========================================="); System.IO.File.AppendAllText(logFile, message.ToString()); } }
I can verify and find out that the Yellow Screen of Death is not indeed shown
Custom Error Page
And the log file is in my App_Data folder
Log File
Now that I can see it works, I would still want to see the exceptions as soon as they occur, rather than checking the log file on each occasion. To achieve that, first I need to add
<customErrors mode="RemoteOnly" />
to the system.web section of the Web.config file and then in the OnException method check if this section is set.
protected override void OnException(ExceptionContext filterContext) { var fileName = Path.Combine(Request.MapPath("~/App_Data"), "log.txt"); WriteLog(fileName, filterContext.Exception.ToString()); if (filterContext.HttpContext.IsCustomErrorEnabled) { filterContext.ExceptionHandled = true; this.View("Error").ExecuteResult(this.ControllerContext); } }
Finally, I would like to receive an email when something on my website goes wrong. I'm adding a function for that, rearranging a few lines and come up with the final version of my BaseController (for now).
using System; using System.Web.Mvc; using System.Text; using System.IO; using System.Net.Mail; namespace Recipes.Controllers { public abstract class BaseController : Controller { protected override void OnException(ExceptionContext filterContext) { string ex = filterContext.Exception.ToString(); var fileName = Path.Combine(Request.MapPath("~/App_Data"), "log.txt"); WriteLog(fileName, ex); SendEmail(ex); if (filterContext.HttpContext.IsCustomErrorEnabled) { filterContext.ExceptionHandled = true; this.View("Error").ExecuteResult(this.ControllerContext); } } static StringBuilder ErrorText(string text) { StringBuilder message = new StringBuilder(); message.AppendLine(DateTime.Now.ToString()); message.AppendLine(text); message.AppendLine("========================================="); return message; } static void WriteLog(string logFile, string text) { System.IO.File.AppendAllText(logFile, ErrorText(text).ToString()); } static void SendEmail(string text) { MailMessage mail = new MailMessage(); SmtpClient client = new SmtpClient("smtp.example.com"); client.Credentials = new System.Net.NetworkCredential("u$3r", "pa$$word"); client.Port = 587; mail.From = new MailAddress("mvc@example.com"); mail.To.Add("developer@example.com"); mail.Subject = "Error on your website"; mail.Body = ErrorText(text).ToString(); client.Send(mail); } } }
References
Problem with generic base controller error handling in ASP.NET MVCASP.NET MVC HandleError Attribute, Custom Error Pages and Logging Exceptions
How to send email from Asp.net Mvc-3?
by Evgeny. Also posted on my website
No comments:
Post a Comment