A simple injector cannot enter depending on the parameters in the web API controllers

I am trying to execute a basic DI constructor using Simple Injector, and it seems that it cannot resolve dependencies for Web API controllers.

  • I have an API controller in the API folder, which is located outside the Controllers folder.
  • I also tried placing it in the Controllers folder, but that doesn't seem to matter much. The stack trace that I get is similar to the one presented in this question .
  • I am using a new installation of the NuGet package with Simple Injector MVC Integration Quick Start (version 2.1.0).
  • I have a SimpleInjectorWebApiDependencyResolver database from the documentation, which also matches the one found here .
  • I am using the Entity Framework and looked at a discussion thread about changes to properly load context.

This does not seem to be a problem, but I still get the following error:

The type "MyProject.API.ArticleController" does not have a default constructor

System.ArgumentException in

System.Linq.Expressions.Expression.New (Type Type) in System.Web.Http.Internal.TypeActivator.Create [TBase] (InstanceType Type) in System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator (HttpRequest Request , Func`1 & activator) under System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, type ControllerType)

It would be nice if someone could offer me some suggestions as to whether something needs to be changed from their current state / call order.

ArticleController (basic structure):

 public class ArticleController : ApiController { private readonly IArticleRepository articleRepository; private readonly IUserRepository userRepository; private readonly IReleaseRepository releaseRepository; public ArticleController(IArticleRepository articleRepository, IUserRepository userRepository, IReleaseRepository releaseRepository) { this.articleRepository = articleRepository; this.userRepository = userRepository; this.releaseRepository = releaseRepository; } // GET api/Article public IEnumerable<Article> GetArticles(){ // code } // GET api/Article/5 public Article GetArticle(int id){ // code } // PUT api/Article/5 public HttpResponseMessage PutArticle(int id, Article article){ // code } // POST api/Article public HttpResponseMessage PostArticle(ArticleModel article){ // code } // DELETE api/Article/5 public HttpResponseMessage DeleteArticle(int id){ // code } } 

SimpleInjectorInitializer:

 public static class SimpleInjectorInitializer { public static void Initialize() { var container = new Container(); InitializeContainer(container); container.RegisterMvcControllers(Assembly.GetExecutingAssembly()); container.RegisterMvcAttributeFilterProvider(); container.Verify(); DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container)); } private static void InitializeContainer(Container container) { container.Register<IArticleRepository, ArticleRepository>(); container.Register<IUserRepository, UserRepository>(); container.Register<IReleaseRepository, ReleaseRepository>(); } } 

Global.asax.cs:

 public class WebApiApplication : System.Web.HttpApplication { private void ConfigureApi() { // Create the container as usual. var container = new Container(); // Verify the container configuration // container.Verify(); // Register the dependency resolver. GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); } protected void Application_Start() { AreaRegistration.RegisterAllAreas(); ConfigureApi(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } } 
+40
c # dependency-injection asp.net-web-api simple-injector
Apr 09 '13 at 17:00
source share
1 answer

TLTR: the problem is caused by an implicit way of working with the API for resolving controller types; Register your Web API controllers explicitly and you will see where the problem is.

Here's a step-by-step what's happening under the covers:

  • System.Web.Http.DefaultHttpControllerActivator calls SimpleInjectorWebApiDependencyResolver and requests the creation of an API controller.
  • SimpleInjectorWebApiDependencyResolver redirect that SimpleInjector.Container instance of SimpleInjector.Container .
  • However, this Container instance does not have any explicit registrations for this API controller (since you provided an empty container to the converter).
  • Since there is no explicit registration, the container tries to do last-time registration for this type.
  • However, this type of controller depends on interfaces that cannot be resolved because they are not registered in the container (remember that your container is empty).
  • Although the container usually throws an exception, null is returned in this case, since the type is requested using the IServiceProvider.GetService method, and the type was not explicitly registered.
  • The SimpleInjectorWebApiDependencyResolver GetService method also returns null , because by definition it should return null; It should return null if registration does not exist (which is currently the case).
  • Since the DependencyResolver returned null, DefaultHttpControllerActivator will revert to default, which means creating the type itself, but this requires the controller to have a default constructor.

In short, the problem is caused by the implicit way that the Web API handles resolving controller types.

So the solution is here:

  • There is only one Container in your web application. This prevents all kinds of problems and complications of your configuration.
  • Register all Web API controllers explicitly in the container. Registering controllers explicitly guarantees that Simple Injector will throw an exception if the controller cannot be enabled. In addition, it allows you to call container.Verify() , which will cause the application to crash at startup when the configuration is invalid ( the configuration to be checked is important), and it also allows you to diagnose the configuration , which gives you even more confidence in the correctness of your configuration.

My advice is to host MVC and Web API in your own project . This will simplify the work.

All Web API controllers can be registered using the following code:

 container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 

UPDATE:

Because this error is so common, newer versions of the SimpleInjectorWebApiDependencyResolver class will simply never return null when prompted for a controller type. Instead, it will produce a descriptive error. Because of this, you will never see errors again if you use the official SimpleInjectorWebApiDependencyResolver .

+43
Apr 09 '13 at 19:24
source share



All Articles