8

I'm building a small Nancy web project.

In a method of one of my classes (not a nancy module), I would like to basically do:

var myThing = TinyIoC.TinyIoCContainer.Current.Resolve<IMyThing>();

However, there is only one registration in .Current (non public members, _RegisteredTypes) which is:
TinyIoC.TinyIoCContainer.TypeRegistration

Naturally, in my above code, I'm getting:

Unable to resolve type: My.Namespace.IMyThing

So, I guess I'm not getting the same container registered in my bootstrapper?

Is there a way to get at it?

EDIT

To flesh out a bit more of what I'm trying to do:

Basically, my url structure looks something like:

/{myType}/{myMethod}

So, the idea being, going to: /customer/ShowAllWithTheNameAlex would load the Customer service, and execute the showAllWithTheNameAlex method

How I do this is:

public interface IService
{
    void DoSomething();
    IEnumerable<string> GetSomeThings();
}

I then have an abstract base class, with a method GetService that returns the service.
It's here that i'm trying to use the TinyIoC.TinyIoCContainer.Current.Resolve();
In this case, it would be TinyIoC.TinyIoCContainer.Current.Resolve("typeName");

public abstract class Service : IService
{
    abstract void DoSomething();
    abstract IEnumerable<string> GetSomeThings();

    public static IService GetService(string type)
    {
        //currently, i'm doing this with reflection....
    }
}

Here's my implementation of the service.

public class CustomerService : Service
{
    public void DoSomething()
    {
        //do stuff
    }

    public IEnumerable<string> GetSomeThings()
    {
        //return stuff
    }

    public IEnumerable<Customer> ShowAllWithTheNameAlex()
    {
        //return
    }
}

Finally, I have my Nancy Module, that looks like:

public class MyModule : NancyModule
{
    public MyModule()
    {
        Get["/{typeName}/{methodName}"] = p => ExecuteMethod(p.typeName, p.methodName);
    }

    private dynamic ExecuteMethod(string typeName, string methodName)
    {
        var service = Service.GetService(typeName);

        var result = service.GetType().GetMethod(methodName).Invoke(service, null);

        //do stuff

        return result; //or whatever
    }
}
Alex
  • 37,502
  • 51
  • 204
  • 332

3 Answers3

4

@alexjamesbrown - The short answer is, you don't. Nancy was specifically designed so that you did not deal with the container directly. You mention that the class, that you want to take a dependency on IMyThing, is not a NancyModule. Well this is not an issue, as long as one of your modules has a reference to it, then those dependencies can also have their own dependencies that will be satisfied at runtime.

public interface IGreetingMessageService
{
   string GetMessage();
}

public class GreetingMessageService: IGreetingMessageService
{
   public string GetMessage()
   {
      return "Hi!";
   }
}

public interface IGreeter
{
   string Greet();
}

public class Greeter
{
   private readonly IGreetingMessageService service;

   public Greeter(IGreetingMessageService service)
   {
      this.service = service;
   }

   public string Greet()
   {
      return this.service.GetMessage();
   }
}

public class GreetingsModule : NancyModule
{
   public GreetingModule(IGreeter greeter)
   {
      Get["/"] = x => greeter.Greet();
   }
}

The above will work just fine and Greeter will have it's dependency on IGreetingMessageService satisfied at runtime

TheCodeJunkie
  • 9,378
  • 7
  • 43
  • 54
  • Thanks for your answer.... Think we're getting there I've fleshed out my question to illustrate exactly what i'm trying to do... hopefully that makes a bit more sense! – Alex Sep 26 '12 at 22:52
  • Since you cross-posted to our user group, I provided a more detailed explanation there https://groups.google.com/d/topic/nancy-web-framework/FVuM9kIiI7Q/discussion – TheCodeJunkie Sep 27 '12 at 05:33
0

I have had a very similar issue, needing to "share" the container. The reason this is an issue is that my program runs as a service using Nancy self hosting to provide a REST API. My modules have dependencies which are injected by Nancy itself, but the other parts of the app which are not referenced from modules also need dependencies injected. Multiple containers are not a sensible option here (or anywhere really), I need to share the container between Nancy and the rest of the app.

I simply did the following (I'm using Autofac but I suspect that TinyIoC in similar)

public class Bootstrapper : AutofacNancyBootstrapper
{
    private static readonly Lazy<ILifetimeScope> container = new Lazy<ILifetimeScope>(RegisterTypes);
    public static ILifetimeScope Container => container.Value;

    protected override ILifetimeScope GetApplicationContainer()
    {
        return container.Value;
    }

    // Create container and register my types
    private static ILifetimeScope RegisterTypes()
    {
        var builder = new ContainerBuilder();

        // Register all my own types.....

        return builder.Build();
    }
}

Then, in my main code, I can use the container myself

public class Program
{
    public static void Main(string[] args)
    {
        // Resolve main service with all its dependencies
        var service = Bootstrapper.Container.Resolve<Service>();
        service.Run();
    }
}

As my NancyHost is within the Service, the container is constructed (once) upon its first use in main, this static is then used when Nancy gets round to creating the Bootstrapper itself.

In an ideal world, I wouldn't really want a globally accessible container, normally it would be local to the main function.

Taoist
  • 321
  • 1
  • 4
  • 11
-1

In this particular case "not dealing with the container directly" is highly problematic:

public interface IFoo {}

public class Foo : IFoo { public Foo(string bar) {} }

Assume IFoo already is a constructor dependency of a Nancy module.

Note the Foo constructor's string dependency. I need to communicate to the container to use that constructor for an IFoo singleton, when encountered as a Nancy module dependency. I need to register that on the TinyIoC instance NancyFx uses, and pass in the actual value of bar.

Rick O'Shea
  • 1,410
  • 19
  • 15