简单注入器无法在 Web API 控制器中注入依赖项 [英] Simple Injector unable to inject dependencies in Web API controllers

查看:29
本文介绍了简单注入器无法在 Web API 控制器中注入依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Simple Injector 执行一些基本的构造函数 DI,但它似乎无法解析 Web API 控制器的依赖项.

I am attempting to do some basic constructor DI with Simple Injector, and it seems that it is unable to resolve the dependencies for Web API controllers.

  • 我在API"文件夹中有一个 API 控制器,位于Controllers"文件夹之外.
  • 我也尝试将它放在Controllers"文件夹中,但是这似乎没有太大区别.堆栈跟踪我收到的类似于 这个问题.
  • 我正在使用全新安装的Simple Injector MVC 集成快速入门"NuGet 包(2.1.0 版).
  • 我有文档中的基本 SimpleInjectorWebApiDependencyResolver,这也与找到的相同 此处.
  • 我正在使用实体框架,并查看了讨论线程关于正确加载上下文的更改.
  • I have an API controller in an "API" folder, that is outside the "Controllers" folder.
  • I have also tried placing it within the "Controllers" folder, but that did not seem to make much of a difference. The stack trace that I receive is similar to the one presented in this question.
  • I am using a fresh install of the "Simple Injector MVC Integration Quick Start" NuGet Package (v. 2.1.0).
  • I have the base SimpleInjectorWebApiDependencyResolver from the documentation, which is also the same as found here.
  • I am using Entity Framework, and have looked at the discussion thread about changes to correctly load the context.

这不似乎有问题,但我仍然收到以下错误:

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

类型MyProject.API.ArticleController"没有默认值构造函数

Type 'MyProject.API.ArticleController' does not have a default constructor

System.ArgumentException 在

System.ArgumentException at

System.Linq.Expressions.Expression.New(Type type) atSystem.Web.Http.Internal.TypeActivator.Create[TBase](Type实例类型)在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage请求,类型控制器类型,Func`1&活化剂)在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage请求,HttpControllerDescriptor 控制器描述符,类型控制器类型)

System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)

如果有人能就是否应修改当前状态/调用顺序的任何内容向我提供一些建议,我们将不胜感激.

It would be appreciated if someone could offer me some suggestions, on whether anything should be modified from its current state/call order.

ArticleController(基本结构):

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:

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:

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: 该问题是由 Web API 处理解析控制器类型的隐式方式引起的;显式注册您的 Web API 控制器,您就会发现问题出在哪里.

TLTR: the problem is caused by the implicit way Web API handles resolving controller types; register your Web API controllers explicitly and you'll see where the problem is.

以下是幕后发生的事情的分步说明:

Here is a step by step what is happening under the covers:

  1. System.Web.Http.DefaultHttpControllerActivator 调用 SimpleInjectorWebApiDependencyResolver 并请求创建 API 控制器.
  2. SimpleInjectorWebApiDependencyResolver 将该调用转发到 SimpleInjector.Container 实例.
  3. 但是,那个 Container 实例没有为该 API 控制器进行任何显式注册(因为您向解析器提供了一个空容器).
  4. 由于没有显式注册,容器会尝试为该类型进行最后一分钟的注册.
  5. 然而,该控制器类型依赖于无法解析的接口,因为它们未在容器中注册(请记住,您的容器是空的).
  6. 虽然容器通常会抛出异常,但在这种情况下返回 null,因为类型是通过 IServiceProvider.GetService 方法请求的,并且类型没有显式注册.
  7. SimpleInjectorWebApiDependencyResolverGetService 方法也将返回 null,因为根据定义它应该返回 null;如果不存在注册(目前是这种情况),它应该返回 null.
  8. 由于 DependencyResolver 返回 null,DefaultHttpControllerActivator 将回退到其默认行为,这意味着自己创建该类型,但这需要控制器具有默认构造函数.
  1. The System.Web.Http.DefaultHttpControllerActivator calls into the SimpleInjectorWebApiDependencyResolver and requests the creation of an API controller.
  2. SimpleInjectorWebApiDependencyResolver forwards that call to the SimpleInjector.Container instance.
  3. That Container instance however, does not have any explicit registrations for that API Controller (since you supplied an empty container to the resolver).
  4. Since there is no explicit registration, the container tries to do a last minute registration for that type.
  5. That Controller type however depends on interfaces that can't be resolved because they are not registered in the container (remember, your container is empty).
  6. Although the container would normally throw an exception, null is returned in this case, because the type is requested through the IServiceProvider.GetService method and the type was not registered explictly.
  7. The SimpleInjectorWebApiDependencyResolver's GetService method will return null as well, since it's by definition that it should return null; It should return null when no registration exists (which currently is the case).
  8. Since the DependencyResolver returned null, DefaultHttpControllerActivator will fall back to its default behavior, which means creating that type itself, but this requires the controller to have a default constructor.

长话短说,问题是由 Web API 处理解析控制器类型的隐式方式引起的.

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

所以这里的解决方案是:

So the solution here is to:

  1. 在您的 Web 应用程序中只有一个 Container.这可以防止您的配置出现各种麻烦和复杂化.
  2. 在容器中显式注册所有 Web API 控制器.显式注册控制器将确保 Simple Injector 在控制器无法解析时抛出异常.此外,这允许您调用 container.Verify() 当配置无效时,这将使应用程序在启动期间失败(a 可验证的配置很重要).这还允许您诊断配置,这让您对配置的正确性更有信心.
  1. Have only one single Container in your web application. This prevents all sorts of trouble and complication of your configuration.
  2. Register all Web API Controllers explicitly in the container. Registering controllers explicitly will ensure that Simple Injector will throw an exception when a controller can't be resolved. Besides, this allows you to call container.Verify() which will make the application fail during startup when the configuration is invalid (a verifiable configuration is important). And this also allows you to diagnose the configuration which gives you even more confidence about the correctness of your configuration.

我的建议是放置MVC和Web API 在他们自己的项目中.这会让事情变得更容易.

My advice is to place MVC and Web API in their own project. This will make things much easier.

可以使用以下代码注册所有 Web API 控制器:

Registering all Web API controllers can be done with the following code:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

更新:

由于此错误非常常见,当请求控制器类型时,SimpleInjectorWebApiDependencyResolver 类的较新版本将简单地从不返回 null.相反,它会抛出一个描述性错误.因此,只要您使用官方的 SimpleInjectorWebApiDependencyResolver,您就不会再看到错误.

Because this error is so common, newer versions of the SimpleInjectorWebApiDependencyResolver class will simply never return null when a controller type is requested. Instead it will throw a descriptive error. Because of this you should never see error anymore, as long as you use the official SimpleInjectorWebApiDependencyResolver.

这篇关于简单注入器无法在 Web API 控制器中注入依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆