NancyFx ConfigureRequestContainer

I'm trying to figure out how the NancyFx request container works, so I've created a small test project.

I created this interface

public interface INancyContextWrapper
{
    NancyContext Context { get; }
}

      

With this implementation

public class NancyContextWrapper : INancyContextWrapper
{
    public NancyContext Context { get; private set; }

    public NancyContextWrapper(NancyContext context)
    {
        Context = context;
    }
}

      

Then in bootstrapper I will register it like this

protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
    base.ConfigureRequestContainer(container, context);
    container.Register<INancyContextWrapper>(new NancyContextWrapper(context));
}

      

I am using this context wrapper in a class that does nothing but returns the request url as a string.

public interface IUrlString
{
    string Resolve();
}

public class UrlString : IUrlString
{
    private readonly INancyContextWrapper _context;

    public UrlString(INancyContextWrapper context)
    {
        _context = context;
    }

    public string Resolve()
    {
        return _context.Context.Request.Url.ToString();
    }
}

      

And finally use this in a module

public class RootModule : NancyModule
{
    public RootModule(IUrlString urlString)
    {
        Get["/"] = _ => urlString.Resolve();
    }
}

      

When I do this, the request is always zero. Now I can more or less figure out that since it is IUrlString

not configured in the request container configuration, TinyIoc resolved INancyContextWrapper

on application startup before any request was made, and TinyIoc does not re-register dependencies that in the dependency graph relies on something. configured in the request container configuration.

My question is what is the best way to use the ConfigureRequestContainer? Should I register anything that is somehow directly related to the NancyContext in the request container configuration? It can get bloated very quickly and be difficult to maintain. I love the way TinyIoc does the scan build, so it's a bit unfortunate to do it.

+3


source to share


1 answer


Assuming the above example is just simplifying what you actually want - that is, something to carry around the nancy context over the lifetime of the request for some purpose, you might be better off not using a loader at all, as that is depending on the IoC container used.

Suggestions:

Change your wrapper implementation to not use a ctor but a setter property (you can always code so that the property can only be set once) :

public interface INancyContextWrapper
{
    NancyContext Context { get; set; }
}

public class NancyContextWrapper : INancyContextWrapper
{
    private NancyContext _context;
    public NancyContext Context 
    { 
           get {return _context;} 
           set {_context = value;} //do something here if you want to prevent repeated sets
    }
}

      

Instead of using container and loader, use the IRegistration implementation directly (they are used by nancy and do not depend on the container)



public class NancyContextWrapperRegistrations : IRegistrations
{
    public IEnumerable<TypeRegistration> TypeRegistrations 
    {
        get 
        { 
            return new[]
            {
                new TypeRegistration(typeof(INancyContextWrapper), typeof(NancyContextWrapper), Lifetime.PerRequest),
                new TypeRegistration(typeof(IUrlString .... per request
            };
               // or you can use AssemblyTypeScanner, etc here to find
        }    

        //make the other 2 interface properties to return null
    }
}

      

Use the IRequestStartup task (these are also automatically recognized by nancy) to set up the context

public class PrepareNancyContextWrapper : IRequestStartup
{
    private readonly INancyContextWrapper _nancyContext;
    public PrepareNancyContextWrapper(INancyContextWrapper nancyContext)
    {
        _nancyContext = nancyContext;
    }

    public void Initialize(IPipelines piepeLinse, NancyContext context)
    {
         _nancyContext.Context = context;
    }
}

      

While the above looks like overkill, it is very convenient to organize type registration in an IoC independent way (i.e. if you replace TinyIoC with something else, you don't need to touch the bootloaders, etc.)

Plus, it's a very good way to control what happens during the launch of a request (or application if you want), without overriding anything in the boot block, and it will work with whatever boot container / container you choose to leave.

+3


source







All Articles