简单的喷油器无法在注入API网络控制器依赖 [英] Simple Injector Unable to Inject Dependencies in Web API Controllers

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

问题描述

我试图做简单的喷油器的一些基本构造DI,这似乎是无法解决的Web API控制器的依赖关系。


  • 我在API文件夹中的API控制器,​​那就是控制器文件夹之外。

  • 我也曾尝试将其置于控制器文件夹中,但
    这似乎并没有太大的差别。该堆栈跟踪
    我收到类似于一个presented在<一个href=\"http://stackoverflow.com/questions/11347152/simpleinjector-injection-does-not-work-with-mvc-4-asp-net-web-api\">this问题。

  • 我使用的是全新安装简单注射器MVC集成快速启动的NuGet包的(第2.1.0)。

  • 我有基 SimpleInjectorWebApiDependencyResolver 从文档,这也是一样的发现<一个href=\"http://stackoverflow.com/questions/11254292/does-simple-injector-supports-mvc-4-asp-net-web-api\">here.

  • 我使用实体框架,并看了看讨论
    螺纹了解
    更改正确加载的上下文。

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


  

键入MyProject.API.ArticleController'没有默认
  构造


  
  

System.ArgumentException
  
  

System.Linq.Ex pressions.Ex pression.New(类型类型)在
  System.Web.Http.Internal.TypeActivator.Create [TBASE](类型
  instanceType)在
  System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HTT prequestMessage
  要求,类型controllerType,Func`1&安培;激活剂)在
  System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HTT prequestMessage
  要求,HttpControllerDescriptor controllerDescriptor,类型
  controllerType)


这将是AP preciated如果有人可以给我一些建议,是否有什么要从其当前状态/调用顺序进行修改。

ArticleController(基本结构):

 公共类ArticleController:ApiController
{
    私人只读IArticleRepository articleRepository;
    私人只读IUserRepository userRepository;
    私人只读IReleaseRepository releaseRepository;    公共ArticleController(IArticleRepository articleRepository,IUserRepository userRepository,IReleaseRepository releaseRepository)
    {
        this.articleRepository = articleRepository;
        this.userRepository = userRepository;
        this.releaseRepository = releaseRepository;
    }    //获取API /条
    公共IEnumerable的&lt;物品&GT; GetArticles(){// code}    //获取API /条/ 5
    公共物品GetArticle(INT ID){// code}    // PUT API /条/ 5
    公众的Htt presponseMessage PutArticle(INT ID,文章文章){// code}    // POST API /条
    公众的Htt presponseMessage PostArticle(ArticleModel文章){// code}    //删除API /条/ 5
    公众的Htt presponseMessage DeleteArticle(INT ID){// code}
}

SimpleInjectorInitializer:

 公共静态类SimpleInjectorInitializer
{
    公共静态无效初始化()
    {
        VAR集装箱=​​新容器();
        InitializeContainer(容器);
        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
        container.RegisterMvcAttributeFilterProvider();
        container.Verify();        DependencyResolver.SetResolver(新SimpleInjectorDependencyResolver(容器));
    }    私有静态无效InitializeContainer(集装箱货柜)
    {
        container.Register&LT; IArticleRepository,ArticleRepository&GT;();
        container.Register&LT; IUserRepository,UserRepository&GT;();
        container.Register&LT; IReleaseRepository,ReleaseRepository&GT;();
    }
}

的Global.asax.cs:

 公共类WebApiApplication:System.Web.HttpApplication
{
    私人无效ConfigureApi()
    {
        //创建容器如常。
        VAR集装箱=​​新容器();        //验证容器配置
        // container.Verify();        //注册的依赖解析器。
        GlobalConfiguration.Configuration.DependencyResolver =
                新SimpleInjectorWebApiDependencyResolver(容器);
    }    保护无效的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的控制器,你会看到问题出在哪里。

下面是一步步什么在幕后发生的事情:


  1. System.Web.Http.DefaultHttpControllerActivator 调用到 SimpleInjectorWebApiDependencyResolver 并请求API控制器的创建。

  2. SimpleInjectorWebApiDependencyResolver 调用到 SimpleInjector.Container 实例前锋。

  3. 集装箱实例但是,不具有该API控制器任何明确的注册(因为你提供给解析器一个空的容器)。

  4. 由于没有明确的登记,容器试图为该类型做最后一分钟的登记

  5. 该控制器类型但要看,因为他们没有在容器中注册的无法解析接口(请记住,你的容器是空的)。

  6. 虽然容器通常会抛出异常,则返回null在这种情况下,因为该类型通过 IServiceProvider.GetService 法要求和类型没有显式登记

  7. 的的 SimpleInjectorWebApiDependencyResolver 的GetService 方法将返回为好,因为它是根据定义,它应该返回null;在没有登记的情况下,它应该返回空值(目前是这样)。

  8. 因为 DependencyResolver 返回null, DefaultHttpControllerActivator 将回落到其默认行为,这意味着创建类型本身,但是这需要控制器有一个默认的构造函数。

长话短说,这个问题是由隐性方式的Web API造成的手柄控制器解决类型。

所以这里的解决方案是:


  1. 只有一个单一的集装箱在你的Web应用程序。这prevents各种配置的麻烦和复杂性。

  2. 注册的所有Web API控制器明确地在容器中。明确注册控制器将确保简单喷油器将抛出一个异常时,控制器不能得到解决。此外,这允许你调用 container.Verify()这将使得启动时应用程序出现故障时的配置是无效的(A <一个href=\"https://simpleinjector.readthedocs.org/en/latest/howto.html#verify-the-container-s-configuration\"相对=nofollow>核实的配置是非常重要的)。这也可以让您诊断配置这给了你更多的信心配置的正确性。

我的<一个href=\"https://stackoverflow.com/questions/15494920/what-is-the-difference-between-dependencyresolver-setresolver-and-httpconfigurat/15495934#15495934\">advice是把MVC和Web API在自己的项目。这将使事情变得更加简单。

注册所有网页API控制器可以用下面的code来完成:

  container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

更新:

由于这个错误是如此普遍,在 SimpleInjectorWebApiDependencyResolver 类的新版本将简单的从不返回当请求控制器类型。相反,它会抛出一个描述性的错误。正因为如此,你永远不应该看到的错误了,只要您使用官方的 SimpleInjectorWebApiDependencyResolver

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.

  • 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:

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

System.ArgumentException at

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

解决方案

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. 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.

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

So the solution here is to:

  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.

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

Registering all Web API controllers can be done with 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 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.

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

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