Khởi động ứng dụng trong ASP.NET Core

Trong bài viết này chúng ta sẽ tìm hiểu về 2 file Startup.cs và Program.cs. Program.cs tạo một webserver với phương thức Main còn Startup.cs chứa cấu hình các services và request pipeline trong ứng dụng.

Program.cs

Tất cả các ứng dụng .NET Core đều là các ứng dụng Console. Các kiểu ứng dụng khác nhau như là MVC, SPA…đều được xây dựng dựa trên ứng dụng console.

Ứng dụng Console luôn được chạy từ một file là Program.cs và phải chứa một hàm static void Main. Nó luôn được gọi khi ứng dụng khởi động.

Mở ứng dụng ở bài trước ra chúng ta sẽ xem file Program.cs. Class này chỉ có một method là Main

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
 
namespace HelloWorld
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }
 
        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}

Đây là điểm khởi đầu của ứng dụng (entry point). Phương thức chính này sẽ tạo một Host, build và run nó. Host này là một web server sẽ lắng nghe các HTTP Request.

 

 

Tạo một host

BuildWebHost

Phương thức static BuildWebHost là một phương thức tĩnh, nó cấu hình, build và trả về một đối tượng Host.

public static IWebHost BuildWebHost(string[] args) =>

    WebHost.CreateDefaultBuilder(args)

           .UseStartup<Startup>()

           .Build();

Cú pháp này được biết đến là Expression-Bodied Function Members trong C# 6. Nó tương đương với function đầy đủ như sau:

public static IWebHost BuildWebHost(string[] args) {
 
    Return WebHost.CreateDefaultBuilder(args)
                  .UseStartup<Startup>()
                  .Build();
}

Phương thức trên sử dụng class WebHost. Method CreateDefaultBuilder của class WebHost có trách nhiệm khởi tạo thể hiện WebHostBuilder với các cấu hình được yêu cầu.

CreateDefaultBuilder

Các công việc được thực hiện bởi CreateDefaultBuilder là:

  1. Cấu hình Kestrel như là web server
  2. Đặt thư mục gốc của ứng dụng sử dụng Directory.GetCurrentDirectory()
  3. Load cấu hình từ
    1. Appsettings.json
    2. Appsettings.{Environment}.json
    3. Load các cấu hình riêng (user secrets) khi chạy ứng dụng ở môi trường Development
    4. Load các biến môi trường (Environment Variables)
    5. Đọc các tham số truyền vào ứng dụng qua Command line argument
  4. Bật logging
  5. Tích hợp Kestrel chạy với IIS

Bạn có thể xem mã nguồn mở đầy đủ của WebHost tại đây:

 

public static IWebHostBuilder CreateDefaultBuilder(string[] args)
        {
            var builder = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    var env = hostingContext.HostingEnvironment;
 
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                          .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
 
                    if (env.IsDevelopment())
                    {
                        var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                        if (appAssembly != null)
                        {
                            config.AddUserSecrets(appAssembly, optional: true);
                        }
                    }
 
                    config.AddEnvironmentVariables();
 
                    if (args != null)
                    {
                        config.AddCommandLine(args);
                    }
                })
                .ConfigureLogging((hostingContext, logging) =>
                {
                    logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                    logging.AddConsole();
                    logging.AddDebug();
                })
                .UseIISIntegration()
                .UseDefaultServiceProvider((context, options) =>
                {
                    options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
                });
 
            return builder;
        }

Bạn có thể xem mã nguồn hàm đầy đủ các tính năng đó ở trên đây.

Kestrel

 .UseKestrel()

Dòng code này thể hiện việc host sử dụng Kestrel web server. Kestrel là một HTTP web server lắng nghe các HTTP request. Server này cho phép ứng dụng của bạn chạy trên các hệ điều hành khác ngoài Windows.

Content Root

 .UseContentRoot(Directory.GetCurrentDirectory())

Dòng này chỉ ra thư mục gốc của ứng dụng là thư mục hiện tại.

Load các file cấu hình

  1. Load dữ liệu các file cấu hình từ:
    1. Appsettings.json
    2. Appsettings.{Envionment}.json
    3. Sử dụng các key cấu hình cho môi trường Development (user secrets)
    4. Các biến môi trường (environment variable)
    5. Command line argruments
.ConfigureAppConfiguration((hostingContext, config) =>
{
    var env = hostingContext.HostingEnvironment;
 
    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
          .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
 
    if (env.IsDevelopment())
    {
        var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
        if (appAssembly != null)
        {
            config.AddUserSecrets(appAssembly, optional: true);
        }
    }
 
    config.AddEnvironmentVariables();
 
    if (args != null)
    {
        config.AddCommandLine(args);
    }
})

Bật logging

.ConfigureLogging((hostingContext, logging) =>
{
    logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
    logging.AddConsole();
    logging.AddDebug();
})

Đoạn này đọc cấu hình phần logging từ các file cấu hình cho việc xuất thông tin log ra console và ra cửa sổ debug.

Sử dụng tích hợp IIS

.UseIISIntegration()

Phương thức này tích hợp Kestrel với IIS

Default Service Provider

Đoạn này cài đặt DI Container có sẵn và bạn có thể tùy biến các hành động của nó

.UseDefaultServiceProvider((context, options) =>
    {
        options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
    });

Và cuối cùng trả về một đối tượng builder.

return builder;

Build

Phương thức build của WebHostBuilder build lên một đối tượng WebHost để chạy ứng dụng

Run

Phương thức run của WebHostBuilder sẽ khởi động Host và bắt đầu lắng nghe HTTP Request.

Startup.cs

Chúng ta hãy nhìn dòng cấu hình của phần Program.cs. WebHost sẽ gọi phương thức UseStartup trước khi build lên host:

.UseStartup<Startup>()

Phương thức UseStartup nói cho Host biết là class nào sẽ gọi khi start host. Và Host sẽ tìm kiếm phần cài đặt trong 2 phương thức Configure và ConfigureServices.

Startup Class là gì?

Startup class là một class đơn giản không kế thừa hay triển khai bất cứ class hay interface nào. Nó có hai chức năng chính:

  1. Cấu hình request pipeline để xử lý các request gửi đến ứng dụng.
  2. Cấu hình các services cho phần denedency injection

ConfigureServices

Phương thức ConfigureServices cho phép chúng ta thêm hoặc đăng ký các service vào ứng dụng. Phần khác của ứng dụng có thể cần đến các service này cho dependency injection. Dependency Injection là một tính năng mới trong ASP.NET Core. Nó có rất nhiều lợi ích mà chúng ta sẽ có bài riêng để nói về nó:

public void ConfigureServices(IServiceCollection services) {
 
}


Phương thức ConfigureServices cần các thể hiện của các service. Thể hiện của các service sẽ được inject (tiêm) vào phương thức ConfigureService thông qua Dependency Injection.

Configure

Phương thức Configure cho phép bạn cấu hình HTTP Request Pipeline. HTTP Request Pipeline chỉ ra cách mà ứng dụng cần phải hồi đấp các HTTP Request. Các thành phần tạo nên request pipeline được gọi là middleware.

Phương thức Configure sẽ có dạng như sau:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    { 
        app.UseDeveloperExceptionPage();
    }
 
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
}


Phương thức configure cần thể hiện của IapplicationBuilder và HostingEnvironment. Hai thể hiện này sẽ được inject vào Configure thông qua Dependency Injector.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

Chúng ta sẽ thêm các middleware vào thể hiện của IapplicationBuilder. Đoạn tiếp theo sẽ kiểm tra nếu chúng ta đang ở môi trường Development, nếu có thì sẽ đăng ký middleware DeveloperExceptionPage sử dụng extension method UseDeveloperExceptionPage.

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}


Tếp theo chúng ta sẽ sử dụng method của ứng dụng để đăng ký middleware thứ 2. Middleware này sẽ ghi ra dòng chữ "Hello World" ra đối tượng response.


Trích nguồn từ: (https://www.tektutorialshub.com/)

Lên trên