Registering dependencies within TinyIOC for use in NancyFX

TheWeekendDeveloper picture TheWeekendDeveloper · Mar 5, 2012 · Viewed 16.7k times · Source

I have another newbie question regarding registering additional dependencies within TinyIoc for use within NancyFX.

I am continuing to get the following exceptions when running the application...

Unable to resolve type: AdvancedSearchService.Interfaces.IResponseFactory

Exception Details: TinyIoC.TinyIoCResolutionException: Unable to resolve type: AdvancedSearchService.Interfaces.IResponseFactory

Source Error: 
Line 25:             var container = TinyIoCContainer.Current;
Line 26: 
Line 27:             _responseFactory = container.Resolve<IResponseFactory>();
Line 28:           
Line 29: 

I am currently registering my dependencies incorrectly, but I cannot seem to figure out the correct way. Below is my code within my custom bootstrapper. Also note that I am not currently calling the base.ConfigureRequestContainer method because I cannot seem to figure out how to get the current context to pass into it.

protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
    container.Register<IRavenSessionManager>(new RavenSessionManager());
    base.ConfigureApplicationContainer(container);

    ConfigureRequestContainer(container);
}


protected void ConfigureRequestContainer(TinyIoCContainer applicationContainer)
{
    var requestContainer = applicationContainer.GetChildContainer();
    requestContainer.Register<ISearchRepository>(new    SearchRepository(requestContainer.Resolve<IRavenSessionManager>().GetSession()));
    requestContainer.Register<IResponseFactory>(new ResponseFactory(requestContainer.Resolve<ISearchRepository>()));
    //base.ConfigureRequestContainer(requestContainer,[I NEED THE CONTEXT])
}

Any help would really be appreciated...apparently my ignorance has no limits :)

Answer

Steven Robbins picture Steven Robbins · Mar 5, 2012

Ok, not 100% sure where to start.. you don't need the context because you're doing it wrong :-)

Firstly, why are you calling "configure request container" at all, and why are you creating a child container? You don't do that :-) There are two scopes, application scope, configured by overriding ConfigureApplicationContainer, and request scope, configured by overriding ConfigureRequestContainer, you don't call them yourself, you just override them depending on how you want to scope your objects.

Secondly, the default Nancy bootstrapper will "autoregister" everything it can in its default implementation of ConfigureApplicationContainer. By calling "base" after you've made a manual registration you are effectively copying over your original registration by autoregister. Either don't call base, or call it before you do your manual registrations. And, again, don't call ConfigureRequestContainer from your ConfigureApplicationContainer :-)

If you don't care about everything being application scoped (so singetons get the same instance for each request) then you don't need any of this, you can just rely on autoregister.

You're currently constructing your objects manually and putting them into the container, that seems a rather odd way to do it. Normally you'd just register the types and let the container handle instantiating as and when it needs to.

You're not overriding ConfigureRequestContainer, you are just creating a new method (with a different signature).

So, what you probably want is something like:

protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
    base.ConfigureApplicationContainer(container);

    // Autoregister will actually do this for us, so we don't need this line,
    // but I'll keep it here to demonstrate. By Default anything registered
    // against an interface will be a singleton instance.
    container.Register<IRavenSessionManager, RavenSessionManager>();
}

// Need to override this, not just make a new method
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
    // Get our session manager - this will "bubble up" to the parent container
    // and get our application scope singleton
    var session = container.Resolve<IRavenSessionManager>().GetSession();

    // We can put this in context.items and it will be disposed when the request ends
    // assuming it implements IDisposable.
    context.Items["RavenSession"] = session;

    // Just guessing what this type is called
    container.Register<IRavenSession>(session);

    container.Register<ISearchRepository, SearchRepository>();
    container.Register<IResponseFactory, ResponseFactory>();
}