Using Nancy + TinyIoC to inject dependencies via Quartz JobFactory

2k views Asked by At

So I'm using Nancy + TinyIoC to run a small webservice. This works. Now I need to create a Quartz job which needs some of the same dependencies and ideally I would like to use Nancy's TinyIoC to inject these, as explained in the Quartz Tutorial.

I've found an example of this using Windsor, in which they access the IoC Container directly, but appearently in Nancy this is, according to similar questions asked here, crude and unnecessary.

My question then would have to be, what is the correct way to do this? The code for my JobFactory looks like this:

public class MyJobFactory : IJobFactory
{
    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        return (IJob) TinyIoCContainer.Current.Resolve(bundle.JobDetail.JobType);
    }
}

But this doesn't return a job with the correctly injected instances, but rather a job with new instances of the dependencies. (Which are supposed to be Singletons, which leads me to believe that the TinyIoCContainer returned by TinyIoCContainer.Current is not the same container as the one Nancy uses).

Update
I'm setting up the IoC container through the Nancy Bootstrapper:

public class MyBootStrapper : DefaultNancyBootstrapper
{
    protected override void ConfigureApplicationContainer(TinyIoCContainer container)
    {
        var push = new PushService();
        // object initialization and Event Registration snipped
        container.Register(cp);
    }
}
3

There are 3 answers

1
Steven Robbins On BEST ANSWER

leads me to believe that the TinyIoCContainer returned by TinyIoCContainer.Current is not the same container as the one Nancy uses).

Got it in one :-) .Current is a static instance, and is something we should probably remove from the Nancy version of the tinyioc.cs file - it's not the same instance as the one the bootstrapper uses.

If you absolutely must use service location, and there's no way you can just use constructor injection, you can override the GetApplicationContainer method in your bootstrapper and return the .Current instance so Nancy will use that instead. We don't use that by default as it's not something we'd recommend

2
Kristof Claes On

Update

I'm sorry. I thought your Quartz job was in a separate project and that you were using it to schedule calls to your Nancy-based webservice. I know understand the Quartz job is inside the Nancy project.

I think you can disregard my original answer :-)

Original answer

Do you specify you want those dependencies registered as a singleton? You can do it like this:

TinyIoCContainer.Current.Register<SomeType>().AsSingleton();

I you are using the AutoRegister functionality and the dependencies you use aren't interfaces or abstract class types and you want all your dependencies to be singletons, you will need to the change the GetDefaultObjectFactory in TinyIoC.

The default looks like this:

private ObjectFactoryBase GetDefaultObjectFactory(Type registerType, Type registerImplementation)
{
    //#if NETFX_CORE
    //if (registerType.GetTypeInfo().IsInterface() || registerType.GetTypeInfo().IsAbstract())
    //#else
    if (registerType.IsInterface() || registerType.IsAbstract())
    //#endif
        return new SingletonFactory(registerType, registerImplementation);

    return new MultiInstanceFactory(registerType, registerImplementation);
}

As you can see it registers interface dependencies and abstract class dependencies to be resolved using a SingletonFactory. Everything else is registered using a MultiInstanceFactory.

You can then change it to this:

private ObjectFactoryBase GetDefaultObjectFactory(Type registerType, Type registerImplementation)
{
    return new SingletonFactory(registerType, registerImplementation);
}
1
Junle Li On

I think @Steven 's information is great. Then, I get another solution to expose Bootstrap IoC as a static property.

public class Bootstrapper : DefaultNancyBootstrapper
{
    public static TinyIoCContainer Container { get; private set; }

    protected override void ConfigureApplicationContainer(TinyIoCContainer container)
    {
        Container = container;
    }
}

When use...

Bootstrapper.Container.Resolve(...)