簡體   English   中英

簡單注入器無法在 Web API 控制器中注入依賴項

[英]Simple Injector unable to inject dependencies in Web API controllers

我正在嘗試使用 Simple Injector 執行一些基本的構造函數 DI,但它似乎無法解析 Web API 控制器的依賴關系。

  • 我在“API”文件夾中有一個 API 控制器,位於“Controllers”文件夾之外。
  • 我也嘗試將它放在“Controllers”文件夾中,但這似乎沒有太大區別。 我收到的堆棧跟蹤類似於此問題中提供的堆棧跟蹤。
  • 我正在使用全新安裝的“Simple Injector MVC 集成快速入門”NuGet 包 (v. 2.1.0)。
  • 我有文檔中的基本SimpleInjectorWebApiDependencyResolver ,它也與此處找到的相同。
  • 我正在使用實體框架,並查看了有關更改以正確加載上下文的討論線程

這似乎不是問題,但我仍然收到以下錯誤:

類型“MyProject.API.ArticleController”沒有默認構造函數

System.ArgumentException 在

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) 在 System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, 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);
    }
}

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. SimpleInjectorWebApiDependencyResolverGetService方法也將返回null ,因為根據定義它應該返回 null; 當不存在注冊時,它應該返回 null(目前是這種情況)。
  8. 由於DependencyResolver返回 null, DefaultHttpControllerActivator將回退到其默認行為,這意味着自己創建該類型,但這需要控制器具有默認構造函數。

長話短說,問題是由 Web API 處理解析控制器類型的隱式方式引起的。

所以這里的解決方案是:

  1. 在您的 Web 應用程序中只有一個Container 這可以防止您的配置出現各種麻煩和復雜化。
  2. 在容器中顯式注冊所有 Web API 控制器。 顯式注冊控制器將確保 Simple Injector 在無法解析控制器時拋出異常。 此外,這允許您調用container.Verify()當配置無效時,這將使應用程序在啟動期間失敗( 可驗證的配置很重要)。 這還允許您診斷配置,從而使您對配置的正確性更有信心。

我的建議是將 MVC 和 Web API 放在他們自己的項目中 這將使事情變得容易得多。

可以使用以下代碼注冊所有 Web API 控制器:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

更新:

由於此錯誤非常常見,因此在請求控制器類型時, SimpleInjectorWebApiDependencyResolver類的較新版本將永遠不會返回null 相反,它會拋出一個描述性錯誤。 因此,只要您使用官方SimpleInjectorWebApiDependencyResolver ,您就不會再看到錯誤了。

以下設置對我有用:

1)包括從Unity.WebAPI https://www.nuget.org/packages/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 注冊,以確保它們在請求結束時被正確處理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM