Tìm hiểu phương thức Build của lớp HostBuilder trong .NET Core

Trong .NET Core, khi làm việc với IHostBuilder, phương thức Build() thực hiện một loạt các tác vụ khởi tạo quan trọng để xây dựng một host hoàn chỉnh. Bài viết này sẽ phân tích chi tiết các bước mà phương thức này thực hiện.

Các trường được khởi tạo

Trước khi đi vào chi tiết phương thức Build, chúng ta cần nắm được các trường (fields) được sử dụng trong quá trình khởi tạo:

 1         private const string DiagnosticsSourceName = "Microsoft.Extensions.Hosting";
 2         private const string StartingEvent = "HostStarting";
 3         private const string CompletedEvent = "HostCompleted";
 4  
 5         private readonly List<Action<IConfigurationBuilder>> _hostConfigActions = new List<Action<IConfigurationBuilder>>();
 6         private readonly List<Action<HostBuilderContext, IConfigurationBuilder>> _appConfigActions = new List<Action<HostBuilderContext, IConfigurationBuilder>>();
  7         private readonly List<Action<HostBuilderContext, IServiceCollection>> _serviceConfigActions = new List<Action<HostBuilderContext, IServiceCollection>>();
  8         private readonly List<IConfigureContainerAdapter> _containerConfigActions = new List<IConfigureContainerAdapter>();
 9         private IServiceFactoryAdapter _serviceFactoryAdapter;
10         private bool _isBuilt;
11         private IConfiguration? _hostConfig;
12         private IConfiguration? _applicationConfig;
13         private HostBuilderContext? _builderContext;
14         private HostingEnvironment? _environment;
15         private IServiceProvider? _serviceProvider;
16         private PhysicalFileProvider? _fileProvider;

Phương thức Build() thực hiện việc kiểm tra và gọi tuần tự 5 phương thức khởi tạo chính:

 1   public IHost Build()
 2         {
 3             if (_isBuilt)
 4             {
 5                 throw new InvalidOperationException(HostingStrings.BuildCalledTwice);
 6             }
 7             _isBuilt = true;
 8  
 9             using DiagnosticListener listener = TrackHostBuilding(this);
10  
11             PrepareHostConfiguration();
12             PrepareHostingEnvironment();
13             PrepareBuilderContext();
14             PrepareApplicationConfiguration();
15             PrepareServiceProvider();
16  
17             return ResolveHost(_serviceProvider, listener);
18         }

Phân tích từng bước khởi tạo

  1. PrepareHostConfiguration - Khởi tạo cấu hình host

Phương thức này xây dựng đối tượng IConfiguration cho phần host:

 1    private IConfiguration? _hostConfig;
 2 
 3   [MemberNotNull(nameof(_hostConfig))]
 4         private void PrepareHostConfiguration()
 5         {
 6             IConfigurationBuilder builder = new ConfigurationBuilder()
 7                 .AddInMemoryCollection(); // Đảm bảo có bộ nhớ mặc định
 8  
 9             foreach (Action<IConfigurationBuilder> action in _hostConfigActions)
10             {
11                 action(builder);
12             }
13             _hostConfig = builder.Build();
14         }
  1. PrepareHostingEnvironment - Thiết lập môi trường hosting

Phương thức này tạo ra đối tượng môi trường và cung cấp file vật lý:

 1         [MemberNotNull(nameof(_fileProvider))]
 2         [MemberNotNull(nameof(_environment))]
 3         private void PrepareHostingEnvironment()
 4         {
 5             (_environment, _fileProvider) = CreateEnvironment(_hostConfig!);
 6         }
 7  
 8         internal static (HostingEnvironment, PhysicalFileProvider) CreateEnvironment(IConfiguration config)
 9         {
10             var env = new HostingEnvironment()
11             {
12                 EnvironmentName = config[HostDefaults.EnvironmentKey] ?? Environments.Production,
13                 ContentRootPath = ResolveContentRootPath(config[HostDefaults.ContentRootKey], AppContext.BaseDirectory),
14             };
15  
16             string? appName = config[HostDefaults.ApplicationKey];
17             if (string.IsNullOrEmpty(appName))
18             {
19                 appName = Assembly.GetEntryAssembly()?.GetName().Name;
20             }
21  
22             if (appName is not null)
23             {
24                 env.ApplicationName = appName;
25             }
26  
27             var fileProvider = new PhysicalFileProvider(env.ContentRootPath);
28             env.ContentRootFileProvider = fileProvider;
29  
30             return (env, fileProvider);
31         }
  1. PrepareBuilderContext - Tạo context cho builder

Phương thức này khởi tạo HostBuilderContext - context chính được truyền qua các bước tiếp theo:

 1 private HostBuilderContext? _builderContext;
 2 
 3 [MemberNotNull(nameof(_builderContext))]
 4         private void PrepareBuilderContext()
 5         {
 6             _builderContext = new HostBuilderContext(Properties)
 7             {
 8                 HostingEnvironment = _environment!,
 9                 Configuration = _hostConfig!
10             };
11         }
  1. PrepareApplicationConfiguration - Xây dựng cấu hình ứng dụng

Phương thức này tạo cấu hình cho ứng dụng dựa trên context đã có:

 1  private IConfiguration? _applicationConfig;
 2  private HostBuilderContext? _builderContext;
 3 
 4  [MemberNotNull(nameof(_applicationConfig))]
 5         private void PrepareApplicationConfiguration()
 6         {
 7             IConfigurationBuilder builder = new ConfigurationBuilder()
 8                 .SetBasePath(_environment!.ContentRootPath)
 9                 .AddConfiguration(_hostConfig!, shouldDisposeConfiguration: true);
10  
11             foreach (Action<HostBuilderContext, IConfigurationBuilder> action in _appConfigActions)
12             {
13                 action(_builderContext!, builder);
14             }
15             _applicationConfig = builder.Build();
16             _builderContext!.Configuration = _applicationConfig;
17         }
  1. PrepareServiceProvider - Khởi tạo service provider

Đây là bước quan trọng nhất - xây dựng IServiceProvider để quản lý các dịch vụ:

 1 private IServiceProvider? _serviceProvider;
 2 
 3  [MemberNotNull(nameof(_serviceProvider))]
 4         private void PrepareServiceProvider()
 5         {
 6             var services = new ServiceCollection();
 7  
 8             PopulateServices(
 9                 services,
10                 _builderContext!,
11                 _environment!,
12                 _fileProvider!,
13                 _applicationConfig!,
14                 () => _serviceProvider!);
15  
16             foreach (Action<HostBuilderContext, IServiceCollection> action in _serviceConfigActions)
17             {
18                 action(_builderContext!, services);
19             }
20  
21             object container = _serviceFactoryAdapter.CreateBuilder(services);
22  
23             foreach (IConfigureContainerAdapter containerAction in _containerConfigActions)
24             {
25                 containerAction.ConfigureContainer(_builderContext!, container);
26             }
27  
28             _serviceProvider = _serviceFactoryAdapter.CreateServiceProvider(container);
29         }

Tổng kết

Phương thức Build() thực hiện tuần tự 5 bước chính:

  1. Khởi tạo cấu hình host từ các nguồn được đăng ký
  2. Thiết lập môi trường hosting với đường dẫn gốc và tên ứng dụng
  3. Tạo context để truyền thông tin giữa các bước
  4. Xây dựng cấu hình ứng dụng kế thừa từ cấu hình host
  5. Khởi tạo ServiceProvider với tất cả các dịch vụ đã đăng ký

Hiểu được luồng hoạt động này giúp lập trình viên có thể tùy chỉnh quá trình khởi tạo host một cách hiệu quả thông qua các phương thức ConfigureHostConfiguration, ConfigureAppConfiguration, và ConfigureServices.

Thẻ: csharp dotnet-core ihostbuilder hostbuilder dependency-injection

Đăng vào ngày 27 tháng 6 lúc 08:02