簡體   English   中英

Autofac:解決 ApiControllers 的依賴關系

[英]Autofac: Resolving dependencies for ApiControllers

我是控制反轉和 Autofac 的新手。 瀏覽文檔,有很多 ASP.NET Web Api 概念我不完全理解或有經驗,因此很難確定我的實現中缺少什么。

我想將 Autofac 應用於具有多個 ApiControllers 的現有 ASP.NET Web Api 項目。 這些控制器都共享一個父抽象 class。 這個抽象的 class 有一個負責返回服務實例的方法。 我希望用 Autofac 的依賴注入來替換這個方法。

每個 ApiController 繼承的父抽象 class 非常簡單。

public abstract class BaseApiController
{
    public IMyService serviceClient { get; set; }

    public BaseApiController() {}

    public BaseApiController(IMyService serviceClient)
    {
        this.serviceClient = serviceClient;
    }
}

每個 controller 都繼承自上面的 class,而有些采用默認的 Get 方法,大多數有多個路由。 沒有一個 controller 指定構造函數:

public class MyController : BaseApiController
{
    public MyController() : base() {}
    public MyController(IMyService serviceClient) : base(serviceClient) {}

    [HttpGet]
    [Route("api/foo/bar")]
    [ActionName("FooBar")]
    public string FooBar()
    {
        using (serviceClient)
        {
            return serviceClient.GetFooBar() as string;
        }
    }
}

Autofac 被集成到應用程序 Glabal.asax.cs 的 Application_Start 方法中,注冊 ServerClientProvider 應該是遇到 IMyService 依賴時應該解析的提供程序:

public class Global : System.Web.HttpApplication, IContainerProviderAccessor
{
    #region AutoFac
    private static IContainerProvider _containerProvider;

    public IContainerProvider ContainerProvider => _containerProvider;
    #endregion AutoFac

    protected void Application_Start(object sender, EventArgs e)
    {

        var builder = new ContainerBuilder();

        builder.Register(x => ServiceClientProvider.GetServiceClient())
            .As<IMyService>()
            .InstancePerRequest();

        builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
        builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();

        var container = builder.Build();

        GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
        GlobalHost.DependencyResolver = new AutofacDependencyResolver(container);

        _containerProvider = new ContainerProvider(container);

    }
}

我在 web.config 中配置了 ASP.NET 應用程序:

<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web" preCondition="managedHandler" />
      <add name="PropertyInjection" type="Autofac.Integration.Web.Forms.PropertyInjectionModule, Autofac.Integration.Web" preCondition="managedHandler" />
    </modules>
  </system.webServer>
<configuration>

據我了解,當遇到具有與注冊類型(屬性注入)匹配的公共屬性的 controller 時,或者如果存在具有與任何注冊依賴項匹配的參數的構造函數,Autofac 應該自動解析提供程序。

但是,我沒有收到與我的 Autofac 配置相關的任何錯誤。 MyController嘗試調用IMyService.FooBar方法時,我收到 NullReferenceException。

我錯過了什么?

任何幫助將不勝感激。

在多次嘗試調試代碼后,我意識到項目中存在另一個啟動實現。 使用了 OWIN,並且我試圖將 Autofac 與之集成的啟動實現被實例化但從未使用過。 因此,按照https://autofac.readthedocs.io/en/latest/integration/owin.html上的說明,得到了我正在尋找的結果。

以下是啟動實現應該如何看待:

[assembly: OwinStartup(typeof(MyWebApp.Api.StartUp))]

namespace MyWebApp.Api
{
    public class StartUp
    {

        public void Configuration(IAppBuilder app)
        {
            // In OWIN you create your own HttpConfiguration rather than
            // re-using the GlobalConfiguration.
            HttpConfiguration httpconfig = new HttpConfiguration();

            httpconfig.Routes.MapHttpRoute(
                name: "ApiRouteWithAction",
                routeTemplate: "api/{controller}/{action}");

            httpconfig.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            // Autofac SignalR integration
            var builder = new ContainerBuilder();

            // Register Web API controller in executing assembly.
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            // Register SignalR hubs.
            builder.RegisterHubs(Assembly.GetExecutingAssembly());

            // Registering Deletegates
            builder.Register(x => ServiceClientProvider.GetServiceClient())
                .As<IMyService>()
                .InstancePerRequest();

            // Set the dependency resolver to be Autofac.
            var container = builder.Build();
            httpconfig.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            app.UseWebApi(httpconfig);

            // Register the Autofac middleware FIRST, then the custom middleware if any.
            app.UseAutofacMiddleware(container);
        }
    }
}

對其繼承的 controller 和抽象 class 進行了調整,刪除了無參數構造函數。

public abstract class BaseApiController
{
    public IMyService serviceClient { get; set; }

    public BaseApiController(IMyService serviceClient)
    {
        this.serviceClient = serviceClient;
    }
}

每個 controller 都繼承自上面的 class,而有些采用默認的 Get 方法,大多數有多個路由。 沒有一個 controller 指定構造函數:

public class MyController : BaseApiController
{
    public MyController(IMyService serviceClient) : base(serviceClient) {}

    [HttpGet]
    [Route("api/foo/bar")]
    [ActionName("FooBar")]
    public string FooBar()
    {
        using (serviceClient)
        {
            return serviceClient.GetFooBar() as string;
        }
    }
}

感謝您的關注,希望我的菜鳥錯誤能幫助另一個菜鳥。

暫無
暫無

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

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