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:
@trailmax There’s a another & better way to get #ELMAH to use a custom connection string. See http://t.co/1u1hZLWwt7 thread for ideas.
— Atif Aziz (@raboof)
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()