Inyector simple que no puede inyectar dependencias en los controladores de API web

Estoy intentando hacer un constructor básico DI con Simple Injector, y parece que no puede resolver las dependencias para los controladores de API web.

  • Tengo un controlador API en una carpeta “API”, que está fuera de la carpeta “Controladores”.
  • También intenté colocarlo dentro de la carpeta “Controladores”, pero eso no pareció marcar una gran diferencia. La traza de stack que recibo es similar a la presentada en esta pregunta .
  • Estoy utilizando una nueva instalación del paquete NuGet “Simple Injector MVC Integration Quick Start” (v. 2.1.0).
  • Tengo la base SimpleInjectorWebApiDependencyResolver de la documentación, que también es la misma que aquí .
  • Estoy usando Entity Framework, y he visto el hilo de discusión sobre los cambios para cargar correctamente el contexto.

Esto no parece ser un problema, pero aún recibo el siguiente error:

Escriba ‘MyProject.API.ArticleController’ no tiene un constructor predeterminado

System.ArgumentException at

System.Linq.Expressions.Expression.New (Tipo de tipo) en System.Web.Http.Internal.TypeActivator.Create [TBase] (Tipo instanceType) en System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator (solicitud HttpRequestMessage, Tipo controllerType , Func`1 y activador) en System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (Solicitud HttpRequestMessage, HttpControllerDescriptor controllerDescriptor, Type controllerType)

Se agradecería si alguien pudiera ofrecerme algunas sugerencias sobre si algo debe ser modificado a partir de su orden actual de estado / llamada.

ArticleController (estructura básica):

 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
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(); container.Register(); container.Register(); } } 

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); } } 

TLTR: el problema es causado por la forma implícita en que la API Web maneja la resolución de los tipos de controlador; registre sus controladores API web explícitamente y verá dónde está el problema.

Aquí hay un paso a paso de lo que está sucediendo bajo las sábanas:

  1. El System.Web.Http.DefaultHttpControllerActivator llama al SimpleInjectorWebApiDependencyResolver y solicita la creación de un controlador API.
  2. SimpleInjectorWebApiDependencyResolver reenvía esa llamada a la instancia SimpleInjector.Container .
  3. Sin embargo, esa instancia de Container no tiene ningún registro explícito para ese controlador de API (ya que proporcionó un contenedor vacío al resolver).
  4. Como no hay un registro explícito, el contenedor intenta hacer un registro de última hora para ese tipo.
  5. Sin embargo, ese tipo de controlador depende de las interfaces que no se pueden resolver porque no están registradas en el contenedor (recuerde que su contenedor está vacío).
  6. Aunque el contenedor normalmente lanzaría una excepción, en este caso se devuelve nulo, porque el tipo se solicita a través del método IServiceProvider.GetService y el tipo no se registró explícitamente.
  7. El método GetService devolverá null también, ya que es por definición que debe devolver nulo; Debería devolver nulo cuando no existe registro (que actualmente es el caso).
  8. Como DependencyResolver devolvió nulo, DefaultHttpControllerActivator volverá a su comportamiento predeterminado, lo que significa que DefaultHttpControllerActivator ese tipo en sí mismo, pero esto requiere que el controlador tenga un constructor predeterminado.

En pocas palabras, el problema es causado por la forma implícita en que la API Web maneja la resolución de los tipos de controladores.

Entonces la solución aquí es:

  1. Tener solo un Container único en su aplicación web. Esto evita todo tipo de problemas y complicaciones de su configuración.
  2. Registre todos los Controladores Web API explícitamente en el contenedor. El registro explícito de los controladores garantizará que Simple Injector arroje una excepción cuando no se pueda resolver un controlador. Además, esto le permite llamar a container.Verify() que hará que la aplicación falle durante el inicio cuando la configuración no es válida (una configuración verificable es importante ). Y esto también le permite diagnosticar la configuración que le brinda aún más confianza sobre la exactitud de su configuración.

Mi consejo es colocar MVC y Web API en su propio proyecto . Esto hará las cosas mucho más fáciles.

El registro de todos los controladores de API web se puede hacer con el siguiente código:

 container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 

ACTUALIZAR:

Debido a que este error es tan común, las versiones más nuevas de la clase SimpleInjectorWebApiDependencyResolver simplemente nunca devolverán null cuando se solicite un tipo de controlador. En su lugar arrojará un error descriptivo. Debido a esto, nunca más SimpleInjectorWebApiDependencyResolver ver el error, siempre y cuando use SimpleInjectorWebApiDependencyResolver .