Khởi tạo service trong Startup ASP.NET Core

Đôi khi chúng ta cần khởi tạo các service trong giai đoạn khởi động ứng dụng của mình. Chúng ta sẽ xem nhanh nhiều cách tiếp cận khả thi dành cho nhà phát triển xây dựng ứng dụng ASP.NET Core.

Tại sao phải khởi tạo dịch vụ trong Startup ASP.NET Core?

Không có gì bí mật khi cơ sở hạ tầng ASP.NET mới nhất phụ thuộc nhiều vào dependency injection.

Khi làm việc với dependency injection, chúng ta sẽ cấu hình các service của mình một lần khi bắt đầu vòng đời của ứng dụng và sau đó gọi ASP.NET Core để khởi tạo các phụ thuộc của chúng ta.

Theo tôi, việc thiết lập một lần và sử dụng ở mọi nơi là một lợi thế lớn khi sử dụng dependency injection.

Khởi tạo service trong phương thức ConfigureServices

Vị trí đầu tiên chúng ta có thể khởi tạo một service nằm trong phương thức ConfigureServices của chúng ta. Lý do để làm điều này có thể là để khởi tạo và đăng ký một thể hiện singleton với bộ sưu tập dịch vụ (services collection) của ứng dụng.

Tôi không khuyên bạn nên khởi tạo bất kỳ service nào trong phương thức ConfigureServices. Như bạn sẽ thấy, có một số lưu ý và chi phí khi làm như vậy.

Trong phương thức ConfigureServices, chúng ta có thể tạo một thể hiện của trình cung cấp dịch vụ (service provider).

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<Dependency>();

    var provider = services.BuildServiceProvider();

    var dependency = provider.GetRequiredService<Dependency>();
    Console.WriteLine(dependency.Hello);
}

Đoạn mã sau sẽ không thành công.

public void ConfigureServices(IServiceCollection services)
{
    var provider = services.BuildServiceProvider();

    // we haven't registered Dependency yet 
    var dependency = provider.GetRequiredService<Dependency>();
    
    services.AddScoped<Dependency>();
    
    Console.WriteLine(dependency.Hello);
}

Mã trên không thành công vì chúng ta chưa đăng ký sự phụ thuộc cho lớp Dependency của mình, nhưng chúng ta lại đang cố gắng khởi tạo nó.

Khởi tạo service trong phương thức Configure

Nếu mọi người muốn chạy một số mã khi khởi động, tốt nhất nên làm điều đó trong phương thức Configure, vì tại thời điểm này, chúng ta đã đăng ký tất cả các service của mình.

Chúng ta có thể thực hiện các tác vụ như gọi một service từ xa, thực thi chuyển đổi cơ sở dữ liệu hoặc ghi nhật ký.

Lưu ý rằng bất kỳ thao tác block thread nào cũng có thể làm chậm thời gian khởi động ứng dụng của bạn và bất kỳ lỗi nào cũng sẽ khiến ứng dụng của bạn không thể khởi động.

Phương pháp khởi tạo service tốt nhất

Một cách dễ dàng, cách tốt nhất là thêm phần phụ thuộc của chúng ta vào danh sách các tham số của phương thức Configure. ASP.NET Core sẽ khởi tạo service của chúng ta từ bộ sưu tập dịch vụ (service collection).

public void Configure(
    IApplicationBuilder app, 
    IWebHostEnvironment env,
    // our dependency
    Dependency dependency
)
{
    Console.WriteLine(dependency.Hello);
    
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); });
    });
}

Ưu điểm của cách tiếp cận này là chúng ta thậm chí có thể giải quyết các phụ thuộc theo phạm vi (scope), như trong trường hợp này, phạm vi là phương thức Configure.

Phương pháp khác nhưng nên hạn chế

Một cách tiếp cận khác, mà tôi không khuyến khích, là sử dụng thuộc tính ApplicationServices của interface IApplicationBuilder. Interface IApplicationBuilder là tham số mặc định của phương thức Configure trong Startup.

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(
    IApplicationBuilder app, 
    IWebHostEnvironment env
)
{
    // cannot call Scoped dependencies
    var dependency = app
        .ApplicationServices
        .GetRequiredService<Dependency>();
    
    Console.WriteLine(dependency.Hello);
    
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); });
    });
}

Cách tiếp cận này chỉ hoạt động cho các service được đăng ký là Singleton Transient. Cố gắng khởi tạo các service Scoped sẽ dẫn đến ngoại lệ sau. ASP.NET Core sẽ ném ngoại lệ này vào một nỗ lực để tránh các phụ thuộc bị nắm bắt.

 System.InvalidOperationException: Cannot resolve scoped service 'WebApplication7.Dependency' from root provider.
         at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
         at Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
...

Điều này nằm ngoài phạm vi của bài viết này, tuy nhiên chúng ta sẽ thảo luận nhanh về các phụ thuộc bị nắm bắt. Phụ thuộc bị nắm bắt là khi một service Singleton giữ một service Scoped. Phụ thuộc bị nắm bắt đặc biệt nguy hiểm vì thể hiện đầu tiên của một service Scoped có thể có thông tin về người dùng đầu tiên yêu cầu ứng dụng của chúng ta.

Bạn bắt buộc không được sử dụng BẤT KỲ dịch vụ nào được khởi tạo trong phương thức Configure như một phần của mã đăng ký pipeline của bạn.

Phần kết luận

Chúng ta đã có một số cách để khởi tạo các service trong lớp Startup của chúng ta. Có nhiều cách để giải quyết vấn đề này. Một số thẳng thắn hơn những người khác.

Chúng ta phải xem xét chi phí để khởi tạo các service trong lớp Startup của mình và tác động của nó đối với hiệu suất khởi động. Giống như nhiều thứ, tất cả đều phụ thuộc.

Tôi hy vọng bạn tìm thấy bài viết này thú vị và vui lòng cho tôi biết nếu bạn có các cách khởi tạo service khác trong lớp Startup.

Nếu Comdy hữu ích và giúp bạn tiết kiệm thời gian làm việc

Bạn có thể vui lòng đưa Comdy vào whitelist của trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi trong việc trả tiền cho dịch vụ lưu trữ web để duy trì hoạt động của trang web.

ASP.NET Core Web APIASP.NET CoreASP.NET Core MVC
Bài Viết Liên Quan:
Cách tạo một HTTP API cơ bản với ASP.NET Core
Trung Nguyen 05/11/2021
Cách tạo một HTTP API cơ bản với ASP.NET Core

Mục đích của bài viết này là hướng dẫn những điều cơ bản về các giao thức HTTP và cách bắt đầu một HTTP API với ASP.NET Core.

Load test cho ứng dụng ASP.NET Core với Apache JMeter
Trung Nguyen 19/06/2021
Load test cho ứng dụng ASP.NET Core với Apache JMeter

Trong bài viết này, bạn sẽ tìm hiểu sâu về Apache JMeter để load test cho một ứng dụng REST API được viết bằng ASP.NET Core.

Distributed Tracing trong ASP.NET Core với Jaeger và Tye
Trung Nguyen 01/05/2021
Distributed Tracing trong ASP.NET Core với Jaeger và Tye

Trong bài viết này, chúng ta sẽ tìm hiểu về tiêu chuẩn kỹ thuật open tracing và sử dụng Jaeger để theo dõi phân tán cho các microservices viết bằng ASP.NET Core.

Cách xây dựng REST API sử dụng ASP.NET Core, Entity Framework Core và JWT
Trung Nguyen 08/04/2021
Cách xây dựng REST API sử dụng ASP.NET Core, Entity Framework Core và JWT

Trong hướng dẫn này, chúng ta sẽ học cách tạo CRUD REST API bằng ASP.NET Core, Entity Framework Core và bảo mật API bằng JWT.