Elmah Shinangiens. Part 2.

In my last post I talked about ELMAH and how you can override connection string. But Atif Aziz (ELMAH author) pointed out that there is a better way to do that:


Fair enough, I thought. I did see that solution when originally needed to fix this problem. But I did not manage to quickly reproduce the code, so I went with a hacky way. This time I’ve spent a couple hours for that and did get what I wanted without dirty hacks.

Here is my implementation:

using System.ComponentModel.Design;
using Elmah;
using MyApplication.Domain.Services.Configuration;


namespace MyApplication.Web.App_Start
{
    public class ElmahConfig
    {
        public static void Configure()
        {
            ServiceCenter.Current = EnclosedServiceProviderQueryHandler.Create(ServiceCenter.Current);
        }
    }


    public class EnclosedServiceProviderQueryHandler
    {
        private readonly ServiceProviderQueryHandler parent;


        public EnclosedServiceProviderQueryHandler(ServiceProviderQueryHandler parent)
        {
            this.parent = parent;
        }

        private ServiceProviderQueryHandler Query(object context)
        {
            return result =>
            {
                var container = new ServiceContainer(parent(context));

                // provides the connection string here
                var log = new SqlErrorLog(ConfigurationContext.Current.GetDatabaseConnectionString()) 
                              {
                                  ApplicationName = "MyApplication",
                              };
                container.AddService(typeof(ErrorLog), log);
                return container;
            };
        }

        public static ServiceProviderQueryHandler Create(ServiceProviderQueryHandler parent)
        {
            var queryHandler = new EnclosedServiceProviderQueryHandler(parent);
            return queryHandler.Query(parent);
        }
    }
}

This creates a delegate that in its turn provide a SqlErrorLog that takes a connection string from your Ambient Context. And to hook in this, in your Global.asax.cs, into Application_Start() you need to add the following:

protected void Application_Start()
{
    // other configurations here...

    ElmahConfig.Configure();
}

And in web.config you don’t need to provide any type of class in <elmah> section:

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

And usual

<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />

must be removed, as we already do the same in Application_Start()