Inject dependency into DelegatingHandler
Asked Answered
O

4

13

I am new to dependency injection, but happy with Ninject and Ninject.Extensions.Logging to [Inject] my ILogger wherever i need it.

However some DelegatingHandlers are spoiling all the fun.

public class HttpsHandler : DelegatingHandler
{
    [Inject]
    public ILogger Logger { get; set; }

    protected override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (!string.Equals(request.RequestUri.Scheme, "https", StringComparison.OrdinalIgnoreCase))
            {
                Logger.Info(String.Format("{0}: is using HTTP", request.RemoteAddress());
                return
                    Task.Factory.StartNew(
                        () =>
                        new HttpResponseMessage(HttpStatusCode.BadRequest)
                        {
                            Content = new StringContent("HTTPS Required")
                        });
            }

            return base.SendAsync(request, cancellationToken);
        }
 }

Could anyone point me in the right direction on how to Inject Ninject.Extensions.Logger.Nlog2 into Ilogger inside the delegatinghandlers?

Update

I think Pete got me in the right direction in the comments (thanks!). I added the following constructor to the HttpsHandler:

public HttpsHandler()
        {
            var kernel = new StandardKernel();

            var logfactory = kernel.Get<ILoggerFactory>();
            this.Logger = logfactory.GetCurrentClassLogger();
        }

and now i've got the Logger working!

My only question left, is this the right way to do it, or is it a anti-pattern?

Othaothe answered 7/2, 2013 at 16:52 Comment(5)
What's creating HttpsHandler instances? If it's not being created by NInject, then that's going to be a problem.Scalf
@Scalf Thanks for your answer, I think you got me in the right direction, could you maybe have a look at my updated question?Othaothe
If you "Inject [your] ILogger wherever [you] need it", please take a look at this stackoverflow q/a.Primogenitor
@Primogenitor thanks for the interesting read. It's some nice thinking food and I'll certainly make use off it, now I just need to figure out the best way to do so.Othaothe
@JosVinke: It can be hard to implement these patterns in an existing (or legacy) code base, but in my experience, it usually pays off (but always do it one step at the time). Good luck.Primogenitor
E
26

DelegatingHandlers are only initialized once in Web API, at application start.

This is a known issue/design feature of Web API (I presume for performance reasons) - see the bug report here http://aspnetwebstack.codeplex.com/workitem/62.

Using a constructor initialization like you suggested yourself, would only work if you have singleton-type dependencies (that' why you logger works). Regardless, if you want to delegate the resolution to Web API DependencyResolver you have to use GetDependencyScope(), which can be called off the HttpRequestMessage, as a workaround.

I posted a walkthrough on doing that with Ninject a while ago. You should use this approach to resolve your deendency, because with your current solution you have coupled Ninject & your handler, which is far from desired.

Entopic answered 7/2, 2013 at 22:32 Comment(4)
Thanks I think i've got your solution working (nice blog!), I just can't verify because I get a null reference when the dependency is resolved in the GetService method. ( at Ninject.Extensions.Logging.LoggerFactoryBase.GetLogger(IContext context) in c:\Projects\Ninject\ninject.extensions.logging\src\Ninject.Extensions.Logging\LoggerFactoryBase.cs:line 61). Could you confirm this is a bug in Ninject.Extensions.Logging or did I do something wrong?Othaothe
Well GetService is simply resolving from kernel.Get. SO you need to register the logger at application startup - something like kernel.Bind<X>().To<Y>(). I am not familiar with ninject.extensions.logging so not sure how exactly you do that, but it has to be defined at application startup, where you register all dependencies. GetDependencyScope() is simply a shortcut to resolve something from your Ninject kernel, without explicitly specifying it (without coupling yourself to the Ninject kernel, since you can easily change DI provider and this code will still work).Entopic
The service is registered and it also gets to the LoggerFactory (see the trace) also if i register it (again) i get a exception that multiple ILoggers are registered. For now I'll mark your answer as accepted and i'll give it a shot with another dependency when i've got a little more time on my hands. Thanks for the help.Othaothe
I just wanted to let you know that I had another scenario where this came really handy and that your solution worked great, thanks!Othaothe
Z
4

I am using this:

 protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 {
    var service = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IFooService)) as IFooService;
    // Other stuff
 }
Zachar answered 18/10, 2016 at 8:46 Comment(1)
I was trying to use this from within my own NuGet package that didn't know about GlobalConfiguration. I was able to find it in the Microsoft.AspNet.WebApi.WebHost package.Incoordination
S
1

I think what you need is this.

It's the Ninject dependency resolver for MVC. Then I believe you need to use:

GlobalConfiguration.Configuration.ServiceResolver.SetResolver()

And pass in the NInject dependency resolver.

Scalf answered 7/2, 2013 at 17:25 Comment(3)
I have tried your solution, but I can't really figure it out. I'm using Asp.Net WebApi (updated tags) and ServiceResolver doesn't exist, it is DependencyResolver in Web Api. I tried a custom DependencyResolver but without any luck. Any other suggestions? Thanks anyway +1 for the help so far.Othaothe
Ah, don't really know, then. Your initial tag said asp.net MVC, so that was the solution I knew. Sorry. maybe someone else can help you.Scalf
Yeah I tagged it with MVC because it's a MVC delegatinghandler and not a HTTP delegatinghandler. Like HTTP Controllers vs MVC Controllers which are both used in a Web Api application. Confuse them and you're up for a fun time solving things. That's why I tagged MVC but sorry for the inconvenience and thanks for the time spend :)Othaothe
R
0

I had a similar situation and taking hints from this post and related links, I came up with following constructor injection solution that seems to work ok for me:

using Ninject.Extensions.Logging;

public static void Register(HttpConfiguration config) {

ILoggerFactory loggerFactory =
   config.DependencyResolver.GetService(typeof(ILoggerFactory))
   as ILoggerFactory;
config.MessageHandlers.Add(
   new HttpsHandler(loggerFactory.GetLogger(typeof(HttpsHandler))));

// Other codes ...

}

I am though using Ninject for WebAi 2/log4net and have installed all pertinent nuget packages

Refurbish answered 19/7, 2015 at 14:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.