Asp.net Core依賴注入(Autofac替換IOC容器)


ASP.NET Core

ASP.NET Core (previously ASP.NET 5) 改變了以前依賴注入框架集成進ASP.NET的方法. 以前, 每個功能 - MVC, Web API, 等. - 都有它自己的 "依賴解析器(dependency resolver)" 機制並且只是'鈎子'鈎住的方式有些輕微的區別. ASP.NET Core 通過 Microsoft.Extensions.DependencyInjection 引入了 conforming container 機制, 包含了請求生命周期作用域, 服務注冊等等的統一概念.

在 ASP.NET Core 3.0, 引入了 "generic app hosting" 機制, 它可以應用在非 ASP.NET Core 應用中.

Autofac

中文官網:https://autofaccn.readthedocs.io/

入門

  • Nuget引入 Autofac.Extensions.DependencyInjection 包.
  • 在你的 Program.Main 方法內, 將Autofac附加給托管機制.(見下例)
  • 在 Startup 類的 ConfigureServices 方法中用其他庫提供的擴展方法注冊東西到 IServiceCollection .
  • 在 Startup 類的 ConfigureContainer 方法中直接注冊東西到Autofac ContainerBuilder.
  • IServiceProvider 會自動替你創建, 因此你無需做任何事只要 注冊東西 即可.

ASP.NET Core 3.0+generic hosting

ASP.NET Core 1.1 - 2.2 使用方法, 你可以調用 WebHostBuilder 的 services.AddAutofac()

在ASP.NET Core 3.0托管方式發生了變化 並且需要不同的集成方式. 你不能在從 ConfigureServices 中返回 IServiceProvider, 也不能再將你的service provider factory加入到service collection.

下面是ASP.NET Core 3+ 和 .NET Core 3+ generic hosting support的集成方式:

Program類

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }

Startup類

添加方法 ConfigureContainer

public void ConfigureContainer(ContainerBuilder builder)
{
    // 在這里添加服務注冊
    builder.RegisterType<TopicService>();
}

配置方法命名約定

  • Configure, ConfigureServices, 和 ConfigureContainer 方法都支持基於你應用中 IHostingEnvironment.EnvironmentName 參數的環境特定命名約定. 默認地, 名稱為 Configure, ConfigureServices, 和 ConfigureContainer.
  • 如果你想要環境特定設置, 你可以把環境名稱放在 Configure 部分后面, 類似 ConfigureDevelopment, ConfigureDevelopmentServices, 和 ConfigureDevelopmentContainer. 如果方法並不以匹配的環境名稱顯示, 它會回到默認方法.

這意味着你不必使用 Autofac配置在生產環境和開發環境之間切換; 你可以在 Startup 中以編程形式設置.

public void ConfigureDevelopmentContainer(ContainerBuilder builder)
{

}
public void ConfigureProductionContainer(ContainerBuilder builder)
{
    // Add things to the ContainerBuilder that are only for the
    // production environment.
 }

這是ASP.NET Core應用托管的一個功能,它並不是Autofac的行為. ASP.NET Core中的StartupLoader類 是在應用啟動時定位調用方法的.

控制器作為服務

默認地, ASP.NET Core 會從容器中解析控制器參數,但不會從中解析控制器 . 這並不是個問題但它意味着:

  • 控制器 的生命周期歸框架管理, 而非請求生命周期.
  • 控制器構造方法參數 歸請求生命周期管理.
  • 在控制器注冊時做的特別的連結 (如屬性注入) 將不會生效.

通過在用service collection注冊MVC時指定 AddControllersAsServices() , 你可以改變這個行為. 這么做可以在service provider factory調用 builder.Populate(services) 時自動注冊控制器類型到 IServiceCollection.

public void ConfigureServices(IServiceCollection services)
{
    //services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
    
    //或者將Controller加入到Services中,這樣寫上面的代碼就可以省略了
    services.AddControllersWithViews().AddControllersAsServices();
}

如果需要在Controller中使用屬性注入,需要在ConfigureContainer中添加如下代碼

//如果需要在Controller中使用屬性注入,需要在ConfigureContainer中添加如下代碼
var controllerBaseType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
.PropertiesAutowired();

在Controller中使用

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly TopicService _service;
    private readonly IServiceProvider _provider;
 
    public TopicService Service { get; set; }
 
    public TestController(TopicService service, IServiceProvider provider)
    {
        _service = service;
        _provider = provider;
    }
 
    [HttpGet("{id}")]
    public async Task<Result> GetTopics(int id)
    {            
        // 構造函數注入
        return await _service.LoadWithPosts(id);
    }
 
    [HttpGet("Get/{id}")]
    public async Task<Result> GetTopics2(int id)
    {
        // 屬性注入
        return await Service.LoadWithPosts(id);
    }
}

這樣就控制器就可以使用服務了。

多租戶支持

由於ASP.NET Core想要早早地生成請求生命周期作用域, 這會導致多租戶支持無法達到開箱即用的效果. 有時用於識別租戶身份的 IHttpContextAccessor , 也無法被及時地構建. Autofac.AspNetCore.Multitenant 包就是用於解決這個問題的.

為了啟用多租戶支持:

  • 添加 Autofac.AspNetCore.Multitenant NuGet包引用.
  • 在 Program.Main 中構建web host時調用 UseServiceProviderFactory 和 AutofacMultitenantServiceProviderFactory. 提供一個配置租戶的回調.
  • 在 Startup.ConfigureServices 和 Startup.ConfigureContainer 中注冊進入 根容器(root container) 的東西(那些非租戶特有的).
  • 在回調中 (如Startup.ConfigureMultitenantContainer) 構建你的多租戶容器.

下面是Autofac給的一個示例:

public class Program
{
  public static async Task Main(string[] args)
  {
    var host = Host
      .CreateDefaultBuilder(args)
      .UseServiceProviderFactory(new AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
      .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder.UseStartup<Startup>())
      .Build();

    await host.RunAsync();
  }
}

... Startup 類似這樣:

public class Startup
{
  // Omitting extra stuff so you can see the important part...
  public void ConfigureServices(IServiceCollection services)
  {
    // This will all go in the ROOT CONTAINER and is NOT TENANT SPECIFIC.
    services.AddMvc();

    // This adds the required middleware to the ROOT CONTAINER and is required for multitenancy to work.
    services.AddAutofacMultitenantRequestServices();
  }

  public void ConfigureContainer(ContainerBuilder builder)
  {
    // This will all go in the ROOT CONTAINER and is NOT TENANT SPECIFIC.
    builder.RegisterType<Dependency>().As<IDependency>();
  }

  public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
  {
    // This is the MULTITENANT PART. Set up your tenant-specific stuff here.
    var strategy = new MyTenantIdentificationStrategy();
    var mtc = new MultitenantContainer(strategy, container);
    mtc.ConfigureTenant("a", cb => cb.RegisterType<TenantDependency>().As<IDependency>());
    return mtc;
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM