HttpHandler Property Injection using Ninject retur

2019-01-26 00:54发布

问题:

I have the following httphandler:

public class NewHandler : IHttpHandler
{
    [Inject]
    public IFile FileReader
    {
        get;
        set;
    }

    public NewHandler()
    {
    }

    public void ProcessRequest(System.Web.HttpContext context)
    {
        ....
        var something = SomeMethod(FileReader);
        ....
    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }
}

This is my Ninject Module in the Global.asax.

internal class ServiceModule : NinjectModule
{
    public override void Load()
    {
        Bind<IFile>().To<FileWrapper>().InSingletonScope();
    }
}

Every time the handler fires the FileReader is NULL. Am I missing something? Is this the correct way to do property injection using Ninject?

Thanks

回答1:

This is the correct way to do property injection with Ninject, but it won't work. You are probably using something like NinjectMvcApplication class as a base class for you application, that handles dependency injection for controllers and everything controllers might use (services, repositories). But HttpHandlers are not instantiated by the ControllerFactory so nothing takes care of injecting stuff.

Maybe there's better way to do it, but i used service locator to resolve the dependency. See http://code.dortikum.net/2010/08/05/asp-net-mvc-di-with-common-service-locator-and-ninject/.

UPDATE:

Try something like this:

public class NewHandler : IHttpHandler
{
    private readonly IFile _fileReader;

    public NewHandler()
    {
        _fileReader = ServiceLocator.Current.GetInstance<IFile>();
    }

    public void ProcessRequest(System.Web.HttpContext context)
    {
        ....
        var something = SomeMethod(_fileReader);
        ....
    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }
}


回答2:

If you're using Ninject.Web.Common, you should have a NinjectWebCommon.cs in your app_start folder. That class instantiates a Bootstrapper class which contains a singleton instance of the Ninject kernel. That Ninject kernel is actually available everywhere in your app which means it's also available in HTTP factory classes.

Here's how you can continue to use Ninject in more or less the same way you're using controllers:

IHttpHandlerFactory is the composition root for IHttpHandler instances and as such you will need to create an implementation of this interface and add the necessary configuration elements to your web.config.

MyHandlerFactory.cs:

public class MyHandlerFactory : IHttpHandlerFactory
{
    public bool IsReusable => false;

    public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
    {
       // the bootstrapper class uses the singleton pattern to share the Ninject Kernel across your web app's ApplicationDomain
       var kernel = new Bootstrapper().Kernel;

       // assuming you have only one IHttpHandler binding in your NinjectWebCommon.cs
       return kernel.Get<IHttpHandler>();
    }

    public void ReleaseHandler(IHttpHandler handler)
    {
       // nothing to release
    }
}

Now, add the necessary config elements for your new handler factory...

Web.config:

  <system.web>
    <httpHandlers>
      <add verb="GET" path="*.customThingImade" type="MyNamespace.MyHandlerFactory, MyAssemblyWhereIPutMyHandlerFactory, Version=1.0.0.0, Culture=neutral" />
    </httpHandlers>
  </system.web>
  <system.webServer>
    <handlers>
      <add name="MyHandlerFactory" verb="GET" path="*.customThingImade" type="MyNamespace.MyHandlerFactory, MyAssemblyWhereIPutMyHandlerFactory, Version=1.0.0.0, Culture=neutral" preCondition="integratedMode" />
    </handlers>
  </system.webServer>

Finally, add a binding for your IHttpHandler implementation...

NinjectWebCommon.cs:

private static void RegisterServices(IKernel kernel)
{
    // other bindings you already have

    // the binding for your handler factory
    Bind<IHttpHandler>().To<NewHandler>();
}