Простой инжектор не может входить в зависимости от параметров в controllerах веб-API

Я пытаюсь сделать базовый конструктор DI с помощью Simple Injector, и кажется, что он не может разрешить зависимости для controllerов Web API.

  • У меня есть controller API в папке «API», которая находится за пределами папки «Контроллеры».
  • Я также попытался разместить его в папке «Контроллеры», но это, похоже, не сильно изменило ситуацию. Трассировка стека, которую я получаю, похожа на ту, что была представлена ​​в этом вопросе .
  • Я использую новую установку пакета NuGet с быстрым запуском Injector MVC Integration Quick Start (версия 2.1.0).
  • У меня есть база SimpleInjectorWebApiDependencyResolver из документации, которая также такая же, как и здесь .
  • Я использую Entity Framework и посмотрел на дискуссионную тему об изменениях для правильной загрузки контекста.

Это, похоже, не проблема, но я все еще получаю следующую ошибку:

Тип «MyProject.API.ArticleController» не имеет конструктора по умолчанию

Исправление System.ArgumentException при

System.Linq.Expressions.Expression.New (тип типа) в System.Web.Http.Internal.TypeActivator.Create [TBase] (тип instanceType) в System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator (запрос HttpRequestMessage, тип controllerType , Func`1 и активатор) в System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (запрос HttpRequestMessage, HttpControllerDescriptor controllerDescriptor, Type controllerType)

Было бы признательно, если бы кто-то мог предложить мне некоторые предложения о том, нужно ли что-либо изменить из своего текущего состояния / порядка вызова.

ArticleController (базовая структура):

 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: проблема возникает из-за неявного способа управления API-интерфейсом для разрешения типов controllerов; зарегистрируйте свои controllerы Web API явно, и вы увидите, где проблема.

    Вот шаг за шагом, что происходит под обложками:

    1. System.Web.Http.DefaultHttpControllerActivator вызывает в SimpleInjectorWebApiDependencyResolver и запрашивает создание controllerа API.
    2. SimpleInjectorWebApiDependencyResolver перенаправляет вызов на экземпляр SimpleInjector.Container .
    3. Однако этот экземпляр Container не имеет каких-либо явных регистраций для этого API-controllerа (поскольку вы предоставили пустой контейнер в преобразователь).
    4. Поскольку нет явной регистрации, контейнер пытается сделать последнюю регистрацию для этого типа.
    5. Однако этот тип controllerа зависит от интерфейсов, которые невозможно устранить, поскольку они не зарегистрированы в контейнере (помните, что ваш контейнер пуст).
    6. Хотя контейнер обычно генерирует исключение, в этом случае возвращается null, поскольку тип запрашивается с помощью метода IServiceProvider.GetService и тип не был зарегистрирован явно.
    7. Метод SimpleInjectorWebApiDependencyResolver GetService также возвращает значение null , поскольку по определению он должен возвращать значение null; Он должен возвращать null, если регистрация не существует (что в настоящее время имеет место).
    8. Поскольку DependencyResolver возвратил null, DefaultHttpControllerActivator вернется к по умолчанию, что означает создание этого типа, но для этого требуется, чтобы controller имел конструктор по умолчанию.

    Короче говоря, проблема связана с неявным способом, которым Web API обрабатывает разрешения типов controllerов.

    Итак, решение здесь:

    1. В вашем веб-приложении есть только один Container . Это предотвращает всевозможные проблемы и осложнения вашей конфигурации.
    2. Зарегистрируйте все controllerы Web API явно в контейнере. Регистрация controllerов явно гарантирует, что Simple Injector будет генерировать исключение, если controller не может быть разрешен. Кроме того, это позволяет вам вызвать container.Verify() который приведет к сбою приложения при запуске, когда конфигурация недействительна ( важна проверенная конфигурация ). И это также позволяет вам диагностировать конфигурацию, которая дает вам еще больше уверенности в правильности вашей конфигурации.

    Мой совет – разместить MVC и Web API в своем собственном проекте . Это упростит ситуацию.

    Регистрация всех controllerов Web API может быть выполнена с помощью следующего кода:

     container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 

    ОБНОВИТЬ:

    Поскольку эта ошибка настолько распространена, более новые версии classа SimpleInjectorWebApiDependencyResolver просто не будут возвращать значение null при запросе типа controllerа. Вместо этого он выдаст описательную ошибку. Из-за этого вы больше никогда не увидите ошибки, если используете официальный SimpleInjectorWebApiDependencyResolver .

    Давайте будем гением компьютера.