How to use Ninject bootstrapper in WebApi OwinHost

2019-03-09 20:45发布

问题:

I am migrating from IIS WebAPI to OwinHost. Utilizing the latest pre-release versions of nuget packages, I successfully used instructions here:

https://github.com/ninject/Ninject.Web.Common/wiki/Setting-up-a-OWIN-WebApi-application

Here is stub of my code:

    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();

        app.UseNinjectMiddleware(CreateKernel);
        app.UseNinjectWebApi(config);
    }

    private static StandardKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Load(Assembly.GetExecutingAssembly());
        RegisterServices(kernel);
        return kernel;
    }

    private static void RegisterServices(IKernel kernel)
    {
        ...
    }

But in my code and the documentation example, the Ninject kernel is not created until after Startup. I need Ninject DI, however, in the Startup registration process for Cors and OAuth middleware registration. Before migrating to OwinHost, I could do something like this:

public void Configuration(IAppBuilder app)
{
  _bootstrapper = new Bootstrapper();
  _bootstrapper.Initialize(CreateKernel);           

  var config = new HttpConfiguration();
  config.MapHttpAttributeRoutes();

  // USE _boostrapper.Kernel here

  app.UseNinjectMiddleware(CreateKernel);
  app.UseNinjectWebApi(config);
}

But internally, OwinBootstrapper.Execute will end up calling CreateKernel and bootstrapper.Initialize a second time, with bad consequences.

What is the right way to create and use the ninject kernel within Startup and still register the Ninject/WebAPI middleware?

回答1:

Add the following nuget-packages to your application:

  1. Install-Package Microsoft.AspNet.WebApi.Owin
  2. Install-Package Ninject

If you are using web api version 5.0.0.0 you also need to download the Ninject Resolver class from the repo to avoid compatability issues.

Create a static method that returns a Kernel object

public static class NinjectConfig
{
    public static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        //Create the bindings
        kernel.Bind<IProductsRepository>().To<ProductRepository>();
        return kernel;
    }
}

Then you can use ninject in your startup class

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();
        config.DependencyResolver = new NinjectResolver(NinjectConfig.CreateKernel());

        config.Routes.MapHttpRoute("default", "api/{controller}/{id}", new { id=RouteParameter.Optional });

        app.UseWebApi(config);
    }
}


回答2:

Create the kernel manually and then make UseNinjectMiddleware use the same one instead of creating another.

public void Configuration(IAppBuilder app)
{
  var kernel = CreateKernel()

  var config = new HttpConfiguration();
  config.MapHttpAttributeRoutes();

  // USE kernel here

  app.UseNinjectMiddleware(() => kernel);
  app.UseNinjectWebApi(config);
}


回答3:

In addition to Olif's post:

  1. install-package ninject.extensions.conventions

  2. In your startup class add: using Ninject.Extensions.Conventions;

  3. Instead of manually binding:

 public static IKernel CreateKernel()
     {
         var kernel = new StandardKernel();
         //Create the bindings
         kernel.Bind<IProductsRepository>().To ProductRepository ();
         return kernel;
     }

You can now do:

kernel.Bind(x =>
                {
                    x.FromThisAssembly()
                    .SelectAllClasses()
                    .BindDefaultInterface();
                });

This will look through your assembly, and do the binding automatically.