DEBUG
and RELEASE
modeSometimes 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.
Can't you just register the context or request in the request container?
Wait, there is a standard way to do this 馃槄, please, where can I find examples?
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.
Wow, this actually worked, thanks a lot :heart: :pray: 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());
}
Most helpful comment
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.