Alexander Beletsky's development blog

My profession is engineering

Integrating ELMAH to ASP.NET MVC in right way

I’ve received great feedback on this article. Thanks all of you guys, who provided valuable comments and pull requests on github. I edited the article several time, hope its up-to-date now. You can go directly to code repository and get the test application, to see what it is all about. In case if you having some issues, just let me know.

UPDATE: Elmah.MVC is now released as NuGet package. No need to read that long blog post, just install it.

Many of you know what the ELMAH is. If you still don’t, go and read here. If you care about monitoring and stability of your web application, you definitely consider to integrate ELMAH. There are number of guidelines of how to do that. But all of them do not answer several question that MVC developers really concerned about:

  • How to add ELMAH as usual MVC controller?
  • How to add ELMAH handler to make it secure (accessible only by authorized users) in MVC application?

I’ll shed the light on both questions here.

Quick start up

The best way to add ELMAH is to use Nuget package manager (really recommend to install it). I’m using Nuget UI, so just right click on MVC application, select “Add Library Package Reference and pickup ELMAH from nuget feed. Nuget will add reference and update web.config with all required configuration. Basically you can start you application with http://localhost/yourapp/elmah.asx and see main ELMAH page.

Changing the configuration

ELMAH have been developed in ancient history times of Web Forms. And it is nicely done to be as much universal as possible and implemented as HttpHandler. In web.config you have several line of configuration that register this handler. This is of cause works, but URI like this http://localhost/yourapp/elmah.asx is absolutely not MVC way. So, what you have to do is simply comment out those configuration.

<system.web>

        <!--<httpHandlers>
            <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
        </httpHandlers>-->
  
    </system.web>

<system.webServer>

    <!--<handlers>
    <remove name="Wild" />
    <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
    </handlers>-->
 
</system.webServer>

Add ELMAH controller

Now add ELMAH controller to application, the code of controller is:

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

And setup a proper routing for it:

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

Implementation of ElmahResult action result

He we go for most interesting part. I’ve checked the sources of ELMAH and reused Elmah.ErrorLogPageFactory to handle those custom HTTP request. After several modifications and pull request by seba-i the code is:

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;
            HttpContext.Current.RewritePath(PathForStylesheet(), pathInfo, HttpContext.Current.Request.QueryString.ToString());
        }

        var httpHandler = factory.GetHandler(HttpContext.Current, null, null, null);
        httpHandler.ProcessRequest(HttpContext.Current);
    }

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

Try it now

Just build the application and put http://localhost/yourapp/admin/elmah and you will get nice looking ELMAH main page.

Making it secure

AuthorizeAttribute works great for this purpose. Just put this attribute to ElmahController and now it is only Admin, who has access to it.

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

In my applications I use a custom attribute, but the idea still the same.

Allow to view results remotely

You definitely want to see results remotely, with no need to access hosting machine. By default, ELMAH do not allow this, but it is easily changed in configuration:

<elmah>
  <security allowRemoteAccess="yes" />

Code example

Full code example is located in my github repository here.


UPD:

I’ve moved out controller to separate github repostitory. You are free and very welcome to use/fork/pull changes :). Fork & fix it here - https://github.com/alexanderbeletsky/elmah.mvc.controller.

UPD2:

Instead of placing just controller I create test MVC3 application that clearly show how to use Elmah in MVC. Plese check code and README here.

UPD3:

Code placed in this blog post has been changed drastically by latest feedback I recieved for this controller. Please better refer code on github or latest blog post here Latest version of ELMAH MVC controller