Alexander Beletsky's development blog

My profession is engineering

Latest version of ELMAH MVC controller

Integrating ELMAH to ASP.NET MVC in right way is blog post I created sometime ago. It appears really popular, because a lot of people had the same issue as me and found solution I created really applicable. It was really cool to receive all that feedback! By the way, elmah.mvc.controller is my first github repository I got pull request!

Especially, I would like to thank to Seba Illingworth and Barry Dorrans who found really nasty issues and helped to fix those.

The controller’s code has been moved to github long time ago, but what I see many people just copy-past code from article into their solutions. The code I gave in previous post has been changed drastically, but instead of re-writting original post I decided to create new one.

Latest version of ELMAH MVC controller

So, after all modifications it looks like:

namespace ElmahMvc.Areas.Admin.Controllers {
    class ElmahResult : ActionResult {
        private string _resouceType;

        public ElmahResult(string resouceType) {
            _resouceType = resouceType;
        }

        public override void ExecuteResult(ControllerContext context) {
            var factory = new Elmah.ErrorLogPageFactory();

            if (!string.IsNullOrEmpty(_resouceType)) {
                var pathInfo = "/" + _resouceType;
                context.HttpContext.RewritePath(FilePath(context), pathInfo, context.HttpContext.Request.QueryString.ToString());
            }

            var currentApplication = (HttpApplication)context.HttpContext.GetService(typeof(HttpApplication));
            var currentContext = currentApplication.Context;

            var httpHandler = factory.GetHandler(currentContext, null, null, null);
            if (httpHandler is IHttpAsyncHandler) {
                var asyncHttpHandler = (IHttpAsyncHandler)httpHandler;
                asyncHttpHandler.BeginProcessRequest(currentContext, (r) => { }, null);
            }
            else {
                httpHandler.ProcessRequest(currentContext);
            }
        }

        private string FilePath(ControllerContext context) {
            return _resouceType != "stylesheet" ? context.HttpContext.Request.Path.Replace(String.Format("/{0}", _resouceType), string.Empty) : context.HttpContext.Request.Path;
        }
    }

    public class ElmahController : Controller {
        public ActionResult Index(string type) {
            return new ElmahResult(type);
        }
    }
}

How to use it in my application?

Easy. Install ELMAH by NuGet, in package console

 Install-Package elmah

It is optional (but preferable) to create new Area called Admin. Inside AreaRegistration.cs your should place routing for ELMAH controller:

context.MapRoute(
        "Admin_elmah",
        "Admin/elmah/{type}",
        new { action = "Index", controller = "Elmah", type = UrlParameter.Optional }
    );

Create ElmahController.cs (just from code above) and place to yours Areas/Admin/Controller folder, add file to project. Don’t forget to change the namespace according to your project.

Configure ELMAH logging options (Memory, XML, SQL), use Web.Config of this project as example. Run application, and see that:

 /admin/elmah

works.

Optional (but very preferable) is to secure your controller with Authorize attribute:

 [Authorize(Users = "Admin")]
 public class ElmahController : Controller
 {

That’s it.

Known issues

One current known issue - if I’m using SqlErrorLog as error log class and press “Download log” button on ELMAH dashboard, you’ve got empty result. Unfortunately, it does not work now, since issue in ELMAH core that I hope will be fixed in nearest release.

NuGet package for it?

I didn’t expect such popularity of that class, but now I seriosly think putting this on NuGet. I’ll try to package that as soon as possible.