一尘不染

简单注入器无法注入Web API控制器中的依赖项

c#

我正在尝试使用Simple Injector做一些基本的构造函数DI,看来它无法解决Web API控制器的依赖关系。

  • 我在“ Controllers”文件夹之外的“ API”文件夹中有一个API控制器。
  • 我也尝试将其放置在“ Controllers”文件夹中,但这似乎并没有太大的区别。我收到的堆栈跟踪类似于此问题中介绍的跟踪。
  • 我正在使用全新安装的“ Simple Injector MVC集成快速入门” NuGet软件包(v。2.1.0)。
  • 我有SimpleInjectorWebApiDependencyResolver文档的基础,也与此处的文档相同。
  • 我正在使用Entity Framework,并且查看了有关正确加载上下文的更改的讨论线程

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

类型’MyProject.API.ArticleController’没有默认的构造函数

System.ArgumentException在

System.Web.Http.Internal.TypeActivator.System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage请求,类型controllerType的System.Web.Http.Internal.TypeActivator.Create
[TBase](Type instanceType)的System.Linq.Expressions.Expression.New(Type type)
,Func`1&activator)在System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage请求,HttpControllerDescriptor
controllerDescriptor,类型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<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);
    }
}

阅读 363

收藏
2020-05-19

共1个答案

一尘不染

TLTR: 问题是由Web API处理解析控制器类型的隐式方式引起的;显式注册您的Web API控制器,您将看到问题出在哪里。

这是逐步进行的幕后工作:

  1. 和中的System.Web.Http.DefaultHttpControllerActivator调用SimpleInjectorWebApiDependencyResolver要求创建API控制器。
  2. SimpleInjectorWebApiDependencyResolver将该调用转发到SimpleInjector.Container实例。
  3. Container但是,该实例没有对该API控制器进行任何显式注册(因为您向解析器提供了一个空容器)。
  4. 由于没有显式注册,因此容器尝试对此类型进行最后一刻的注册。
  5. 但是,该Controller类型取决于无法解析的接口,因为它们未在容器中注册(请记住,您的容器为空)。
  6. 尽管容器通常会引发异常,但是在这种情况下将返回null,因为通过该IServiceProvider.GetService方法请求了类型,并且该类型未明确注册。
  7. SimpleInjectorWebApiDependencyResolverGetService方法将返回null为好,因为它的定义,它应该返回null; 当不存在注册时(当前就是这种情况),它应该返回null。
  8. 由于DependencyResolver返回的null DefaultHttpControllerActivator将返回其默认行为,这意味着将自己创建该类型,但这需要控制器具有默认构造函数。

简而言之,问题是由Web API处理解析控制器类型的隐式方式引起的。

因此,这里的解决方案是:

  1. Container您的Web应用程序中只有一个。这样可以避免各种麻烦和配置复杂化。
  2. 在容器中显式注册所有Web API控制器。明确注册控制器将确保在无法解析控制器时,Simple Injector将引发异常。此外,这允许您调用container.Verify(),当配置无效(可验证的配置很重要)时,这将导致应用程序在启动过程中失败。而且,这还使您能够诊断配置,从而使您对配置的正确性更有信心。

我的建议是将MVC和Web API放在自己的项目中。这将使事情变得容易得多。

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

container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

更新:

由于此错误非常普遍,因此在请求控制器类型时,SimpleInjectorWebApiDependencyResolver该类的较新版本将
永远不会
返回null。相反,它将引发一个描述性错误。因此,只要您使用Official,就永远不会再看到错误SimpleInjectorWebApiDependencyResolver

2020-05-19