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

use*_*835 41 c# dependency-injection simple-injector asp.net-web-api

我试图用Simple Injector做一些基本的构造函数DI,似乎它无法解析Web API控制器的依赖关系.

  • 我在"API"文件夹中有一个API控制器,它位于"Controllers"文件夹之外.
  • 我也尝试将它放在"控制器"文件夹中,但这似乎并没有多大区别.我收到的堆栈跟踪与此问题中提供的类似.
  • 我正在使用全新安装的"Simple Injector MVC Integration Quick Start"NuGet Package(v.2.1.0).
  • 我有SimpleInjectorWebApiDependencyResolver文档的基础,这也是在这里找到的.
  • 我正在使用Entity Framework,并查看了有关更改以正确加载上下文的讨论主题.

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

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

System.ArgumentException at

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

如果有人可以提供一些关于是否应该从其当前状态/呼叫顺序修改任何内容的建议,将不胜感激.

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 }
}
Run Code Online (Sandbox Code Playgroud)

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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 43

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);
Run Code Online (Sandbox Code Playgroud)

更新:

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


归档时间:

查看次数:

39536 次

最近记录:

6 年 前