ninject / Ninject.Web.WebApi

Adds support for ASP.NET Web API to Ninject
Other
45 stars 37 forks source link

NotImplementedException when WebApi is used with NInject #20

Closed MoonStorm closed 9 years ago

MoonStorm commented 9 years ago

The problem can be easy to reproduce by creating a new MVC+WebAPI project via the standard ASP.NET project template, adding the required Owin and the Ninject packages, removing the setup logic in the global.asax.cs, creating a Startup class as the one below:

using Microsoft.Owin;
using UrlHelperWebApiTests;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Ninject;
using Ninject.Web.Common.OwinHost;
using Owin;
using Ninject.Web.WebApi.OwinHost;

[assembly: OwinStartup(typeof(Startup))]
namespace UrlHelperWebApiTests
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            GlobalConfiguration.Configure(
                config =>
                {
                    AreaRegistration.RegisterAllAreas();
                    WebApiConfig.Register(config);
                    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                    RouteConfig.RegisterRoutes(RouteTable.Routes);
                    BundleConfig.RegisterBundles(BundleTable.Bundles);

                    app.UseNinjectMiddleware(() => new StandardKernel()).UseNinjectWebApi(config);
                });
        }
    }
}

and by changing the default GET of the ValuesController to:

        // GET api/values
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" }.Select(id=> this.Url.Link("DefaultApi",new{controller="Values",id=id})).ToArray();
        }

When UseNinjectWebApi is active in the Startup, the GET will fail with a NotImplementedException.

When UseNinjectWebApi is not active, the GET will succeed. This is because HostedHttpRouteCollection.GetVirtualPath is looking for the HTTP context in the property bag of the request. This is set up by the HttpControllerHandler which attaches the context to the MS_HttpContext key.

MoonStorm commented 9 years ago

It turned out WebApi was not configured correctly in an MVC + WebApi combo. The key is to use a different HttpConfiguration than the global one:

  // initialize web pages & mvc routing first
  AreaRegistration.RegisterAllAreas();
  ConfigureRoutes(RouteTable.Routes);
  BundleConfig.RegisterBundles(BundleTable.Bundles);

  // set up IOC and configure authentication
  app.UseNinjectMiddleware(CreateKernel);
  ConfigureAuth(app);

  // finally the web api, on its own http configuration
  var webApiConfig = new HttpConfiguration();
  webApiConfig.MapHttpAttributeRoutes();
  webApiConfig.Routes.MapHttpRoute(
    name: "DefaultApi", 
    routeTemplate:api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional });
  app.UseNinjectWebApi(webApiConfig);

  // ensure all the configs are ready
  GlobalConfiguration.Configuration.EnsureInitialized();
  webApiConfig.EnsureInitialized();