Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I inject dependencies into an ELMAH custom ErrorLog?

Tags:

c#

elmah

ninject

I have an ELMAH custom ErrorLog that uses an EF Code-First context to store the errors:-

class EntityFrameworkElmahErrorLog
{
    public EntityFrameworkElmahErrorLog(IDictionary config) : this() { }

    public override ErrorLogEntry GetError(string id)
    {
        using (var context = new MyContext())
        {
            var intId = Int64.Parse(id, CultureInfo.InvariantCulture);
            var item = context.ErrorLog.Single(x => x.Id == intId);
            return new ErrorLogEntry(this, id, ErrorXml.DecodeString(item.Details));
        }
    }

    // etc.

}

The ErrorLog is wired up in the web.config:-

<errorLog type="MyProject.EntityFrameworkErrorLog, MyProject" />

I'm already using Ninject elsewhere in the project. I'd like to inject MyContext so that the ErrorLog isn't instantiating its own dependency, but I'm not having any luck finding a hook in the documentation. ELMAH appears to be instantiating the ErrorLog internally, so the only option I seem to have is using a ServiceLocator inside my custom ErrorLog, which I'd like to avoid if possible.

Are there any better hooks available in ELMAH that I can use to inject ?

like image 724
Iain Galloway Avatar asked Oct 16 '12 15:10

Iain Galloway


1 Answers

The Service location/Depdency injection extension point in ELMAH is the ServiceCenter.Current property where you can provide a delegate with the following signature:

public delegate IServiceProvider ServiceProviderQueryHandler(object context);

ELMAH will use the System.IServiceProvider returned by the ServiceCenter.Current to resolve the ErrorLog isntances.

So you need to do 3 things to setup it with Ninject (or any DI container)

  1. Create your own System.IServiceProvider implementation with Ninject the IKernel interface already derives from from System.IServiceProvider, so it's done.
  2. You need to register your EntityFrameworkElmahErrorLog in your container as an ErrorLog implemenation, because ELMAH will try to resolve an instance of ErrorLog.
  3. Provide your delegate to ServiceCenter.Current

So you need something like the following in your RegisterServices method:

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<ErrorLog>().To<EntityFrameworkElmahErrorLog>();
    ServiceCenter.Current = (httpContext) => kernel;
}  

Note: in in the ServiceProviderQueryHandler delegate you get the current HttpContext and with that you can fine tune how your expediencies are resolved.

You should also note that with this approach you will lose the ability to configure your ErrorLog in your config file.

ELMAH will always use the resolved instance from your container, because the built in ServiceContainer reads the config file what you override with your custom logic.

like image 133
nemesv Avatar answered Nov 15 '22 04:11

nemesv