简单的注射器无法在Web API控制器中注入相关性 [英] Simple Injector Unable to Inject Dependencies in Web API Controllers

查看:91
本文介绍了简单的注射器无法在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控制器,它位于控制器文件夹之外。

  • 我也尝试将其放在控制器文件夹中,但
    似乎没有什么区别。我收到的
    的堆栈跟踪类似于这个问题

  • 我正在使用Simple Injector MVC Integration Quick StartNuGet Package(v。2.1.0)的全新安装。

  • 我有文档中的基础 SimpleInjectorWebApiDependencyResolver ,这也与发现这里

  • 我正在使用Entity Framework,并且查看了讨论
    线程
    关于正确加载上下文的更改。

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

System.ArgumentException at

系统.Linq.Expressions.Expression.New(Type type)at
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,键入
controllerType)

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


推荐答案

strong> 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然而,对于该API控制器没有任何明确的注册。实例

  3. (因为你提供了一个空容器到解析器)。

  4. 由于没有明确的注册,容器试图对该类型进行最后一分钟的注册。

  5. 然而,该控制器类型取决于无法解析的接口,因为它们未在容器中注册(请记住,您的容器为空)。

  6. 尽管容器通常会引发异常,但在这种情况下返回null,因为该类型是通过 IServiceProvider.GetService 方法请求的,并且该类型未被明确注册。

  7. SimpleInjectorWebApiDependencyResolver GetService 方法将返回 null ,因为根据定义它应该返回null;由于 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控制器。明确注册控制器将确保当无法解析控制器时,简单注射器将抛出异常。此外,这允许您调用 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天全站免登陆