Skip to content
This repository has been archived by the owner on Jan 24, 2021. It is now read-only.

How to inject a dependency to NancyModule which itself depends on the Request? #2869

Closed
4 tasks done
Zaid-Ajaj opened this issue Feb 25, 2018 · 4 comments
Closed
4 tasks done

Comments

@Zaid-Ajaj
Copy link

Zaid-Ajaj commented Feb 25, 2018

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of Nancy
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

Description

Sometimes I need to read data from the request itself to initialize a service that a certain NancyModule depends on. Take the following example:

public interface IApiKeyProvider 
{
     string GetApiKey();
}

public class Service : IService
{
    private readonly IApiKeyProvider apiKeyProvider; 
    public Service(IApiKeyProvider apiKeyProvider) 
    {
           this.apiKeyProvider = apiKeyProvider;
    }
    
    // ... implementation
}

I would register both like this:

container.Register<IService, Service>();
container.Register<IApiKeyProvider, FromRequestApiKeyProvider>(); 

where the class FromRequestApiKeyProvider provides the api key by reading data from the request. This is what I need to be able to do:

// Hypothetical class
public class FromRequestApiKeyProvider : IApiKeyProvider
{
    private readonly NancyRequest request;
    public FromRequestApiKeyProvider(NancyRequest request)
    {
         this.request = request;
    }

    public string GetApiKey() 
    {
         return this.request.Query["apiKey"];
    }
}

Not being able to do this forces me into initializing a concrete implementation of Service inside the request handlers which in turn forbids me from unit-testing my NancyModule.

Another scenario where this popped up is where I put data into the Items of a NancyContext in the Before pipeline (in Bootstrapper -> ApplicationStartup) and then needing to read the data I put in the NancyContext to initialize some service like the above.

As an example for the latter scenario, see the Nancy.Serilog library where you have to get a contexual logger from inside the request handler i.e. var logger = this.CreateLogger(); where ideally this would be injected as a dependency to the NancyModule at the constructor level.

@khellang
Copy link
Member

Can't you just register the context or request in the request container?

@Zaid-Ajaj
Copy link
Author

Wait, there is a standard way to do this 😅, please, where can I find examples?

@khellang
Copy link
Member

khellang commented Feb 27, 2018

I don't know about standard, but I think it can be achieved by registering the context or request in the request container. Just override ConfigureRequestContainer in your bootstrapper.

@Zaid-Ajaj
Copy link
Author

Wow, this actually worked, thanks a lot ❤️ 🙏 I used this code:

protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
    Func<ILogger> getLogger = () =>
    {
        if(!context.Items.ContainsKey("RequestId"))
        {
            return Log.Logger;
        }
        
        var requestId = (string)context.Items["RequestId"];
        var contextualLogger = Log.ForContext("RequestId", requestId);
        return contextualLogger;
    };
    
    container.Register((tinyIoc, namedParams) => getLogger());
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants