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

时间:2013-04-09 17:00:52

标签: c# asp.net-web-api dependency-injection simple-injector

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

  • 我在“API”文件夹中有一个API控制器,它位于“Controllers”文件夹之外。
  • 我也尝试将其放在“Controllers”文件夹中,但是 这似乎并没有多大区别。堆栈跟踪即 我收到的内容类似于this question中提供的内容。
  • 我正在全新安装“Simple Injector MVC Integration Quick Start”NuGet Package(v.2.1.0)。
  • 我有来自文档的基础SimpleInjectorWebApiDependencyResolver,它与找到的here相同。
  • 我正在使用Entity Framework,并查看了有关更改的discussion thread以正确加载上下文。

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

  

类型'MyProject.API.ArticleController'没有默认值   构造

     

的System.ArgumentException      

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

2 个答案:

答案 0 :(得分:42)

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

以下是幕后发生的一步一步:

  1. System.Web.Http.DefaultHttpControllerActivator调用SimpleInjectorWebApiDependencyResolver并请求创建API控制器。
  2. SimpleInjectorWebApiDependencyResolver将该调用转发给SimpleInjector.Container个实例。
  3. 然而,Container实例没有为该API控制器进行任何显式注册(因为您向解析器提供了一个空容器)。
  4. 由于没有明确的注册,容器会尝试为该类型进行最后一分钟的注册。
  5. 然而,控制器类型依赖于无法解析的接口,因为它们未在容器中注册(请记住,您的容器是空的)。
  6. 虽然容器通常会抛出异常,但在这种情况下会返回null,因为通过IServiceProvider.GetService方法请求了类型,并且类型未明确注册。
  7. SimpleInjectorWebApiDependencyResolver的{​​{1}}方法也会返回GetService,因为根据定义,它应该返回null;如果不存在注册(当前就是这种情况),它应该返回null。
  8. 由于null返回null,DependencyResolver将回退到其默认行为,这意味着自己创建该类型,但这需要控制器具有默认构造函数。
  9. 长话短说,问题是由Web API处理解析控制器类型的隐式方式引起的。

    所以这里的解决方案是:

    1. 您的网络应用程序中只有一个DefaultHttpControllerActivator。这可以防止各种麻烦和配置复杂化。
    2. 在容器中显式注册所有Web API控制器。显式注册控制器将确保Simple Injector在无法解析控制器时抛出异常。此外,这允许您调用Container,这会在配置无效时启动应用程序失败(verifiable configuration is important)。这也允许您diagnose the configuration,这使您对配置的正确性更有信心。
    3. 我的advice is to place MVC and Web API in their own project。这将使事情变得更容易。

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

      container.Verify()

      <强>更新

      由于此错误非常常见,因此在请求控制器类型时,container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 类的较新版本只会从不返回SimpleInjectorWebApiDependencyResolver。相反,它会引发描述性错误。因此,只要您使用官方null

      ,就不应再看到错误了

答案 1 :(得分:0)

以下设置对我有用:

1)包含https://www.nuget.org/packages/Unity.WebAPI/中的 Unity.WebAPI 2)在 UnityConfig

public static class UnityConfig
    {
        public static void RegisterComponents()
        {
            var container = new UnityContainer();
            // **** Important note -----
            // register all your components with the container here
            // e.g. container.RegisterType<ITestService, TestService>();


            DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));

            GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
        }
    }

3)在 Global.asax 文件

 public class MvcApplication : System.Web.HttpApplication
        {
            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
                UnityConfig.RegisterComponents();
                GlobalConfiguration.Configure(WebApiConfig.Register);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
            }
        }

Unity.WebAPI入门

要开始使用,只需在Global.asax.cs的Application_Start方法中添加对UnityConfig.RegisterComponents()的调用 然后Web API框架将使用Unity.WebAPI DependencyResolver来解析您的组件。

例如

public class WebApiApplication : System.Web.HttpApplication
{
  protected void Application_Start()
  {
    AreaRegistration.RegisterAllAreas();
    UnityConfig.RegisterComponents();                           // <----- Add this line
    GlobalConfiguration.Configure(WebApiConfig.Register);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
  }           
}  

在UnityConfig类的RegisterComponents方法中添加您的Unity注册。实现IDisposable的所有组件都应 向HierarchicalLifetimeManager注册,以确保在请求结束时正确处理它们。