C# cơ bản .NET Core

Asp.net Core tích hợp sẵn một DI Container để đăng ký và sử dụng các dịch vụ với kỹ thuật DI, Đối tượng này thuộc kiểu IServiceCollection mà đã tìm hiểu ở mục Sử dụng ServiceCollection. Phần này sẽ sử dụng IServiceCollection tích hợp sẵn trong ASP.NET CORE

Tạo ra dự án mẫu, tạo thư mục chứa code dự án 04.ServiceCollection vào thư mục đó gõ lệnh

dotnet new web

Sau đó mở ra bằng VSC, trong ví dụ trước (ASP.NET Core) Đọc và ghi Request và Response, đã tạo ra một lớp tĩnh tiện ích là HtmlHelper để phát sinh mã HTML nhanh hơn, hãy lấy file nguồn về và đưa vào dự án để sử dụng ngay, file nguồn HtmlHelper.cs

Đồng thời bạn cũng tích hợp thư viện CSS Bootstrap vào theo hướng dẫn tại: Webpack đóng gói CSS, JS với ASP.NET Core , sau đó cũng thiết lập sử dụng truy cập file tĩnh app.UseStaticFiles();

Kiến thức phần này áp dụng Dependency injection (DI), nên cần phải thành thạo nó trước, nếu chưa chắc chắn hãy đọc tại Dependency injection (DI) , đặc biệt chú ý mục DI Container

Tạo các lớp dịch vụ để thực hành

Định nghĩa interface có tên IListProductName, có phương thức để lấy danh sách chuỗi - tên các sản phẩm.

Services/IListProductName.cs
using System.Collections.Generic;
using System.Collections;

public interface IListProductName
{
    // Trả về danh sách các tên
    IEnumerable<string> GetNames();
}

Triển khai giao diện IListProductName với hai lớp dịch vụ gồm LaptopNamePhoneName

Services/LaptopName.cs
using System.Collections.Generic;
using System.Collections;

public class LaptopName : IListProductName
{
  public LaptopName() => System.Console.WriteLine("LaptopName Created");
  // Mảng tên sản phẩm
  string[] laptops = new string[]  {
      "Apple MacBook Pro 13 inch", "HP Spectre X360", "Samsung Chromebook Pro"};

  public IEnumerable<string> GetNames()
  {
      return laptops;
  }
}
Services/PhoneName.cs
using System.Collections.Generic;
using System.Collections;

public class PhoneName : IListProductName
{
    public PhoneName() => System.Console.WriteLine("PhoneName created");
    // Mảng tên các điện thoại
    private List<string> phone_names =  new List<string> {
        "Iphone 7", "Samsung Galaxy", "Nokia 123"
    };
    public IEnumerable<string> GetNames()
    {
        return phone_names;
    }
}

Đăng ký dịch vụ cho ứng dụng ASP.NET Core

Ứng dụng ASP.NET Core cung cấp sẵn một DI Container có kiểu IServiceCollection, đối tượng này để đăng ký các dịch vụ vào ứng dụng. Các đăng ký sẽ thực hiện ở phương thức ConfigureServices của lớp Startup

Vậy hãy cập nhật phương thức đó - đăng ký dịch vụ như sau:

    /..
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IListProductName, PhoneName>();          //  đăng ký dịch vụ, đối tượng chỉ tạo một lần
        services.AddTransient<LaptopName, LaptopName>();               //  đăng ký dịch vụ, tạo mới  mỗi lần  triệu gọi
    }
    /..
    

Như vậy đã đăng ký được dịch vụ vào ứng dụng, để triệu gọi ra các dịch vụ này trực tiếp thì sử dụng đối tượng kiểu IApplicationBuilder có trong phương thức Configure của lớp Startup, ví dụ:

    /..
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        /..
        var myservice = app.ApplicationServices.GetService<IListProductName>();
        /..
    }
    /..
    

Hoặc có thể lấy thông qua HttpContext

var myservice = context.RequestServices.GetService<IListProductName>();

Inject các dịch vụ

Các đối dịch vụ đăng ký vào ứng dụng, được Inject vào các dịch vụ khác khi cần thiết, ví dụ sau - tạo ra lớp có tên ProductController sử dụng dịch vụ IListProductNameLaptopName, hai dịch vụ này Inject vào ProductController qua phương thức khởi tạo của nó.

Controller/ProductController.cs
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using System.Text;
using System.Linq;

namespace _04.ServiceCollection
{
    public class ProductController
    {
        IListProductName lsPhone;
        IListProductName lsLaptop;

        // Inject hai dịch vụ qua phương thức khởi tạo
        public ProductController(IListProductName lsphone, LaptopName lslaptop) {
            Console.WriteLine(this.GetType().Name + " created");
            this.lsPhone  = lsphone;
            this.lsLaptop = lslaptop;
        }

        // Xuất danh sách sản phẩm cho Response
        public async Task List(HttpContext context) {

            var sb = new StringBuilder();
            string lsPhoneHTML  = string.Join("", lsPhone.GetNames().Select(name  => name.HtmlTag("li"))).HtmlTag("ul");
            string lsLaptopHTML = string.Join("", lsLaptop.GetNames().Select(name => name.HtmlTag("li"))).HtmlTag("ul");
            sb.Append("Danh sách điện thoại".HtmlTag("h2"));
            sb.Append(lsPhoneHTML);

            sb.Append("Danh sách Laptop".HtmlTag("h2"));
            sb.Append(lsLaptopHTML);

            string menu         = HtmlHelper.MenuTop(HtmlHelper.DefaultMenuTopItems(), context.Request);
            string html         = HtmlHelper.HtmlDocument("DS Sản phẩm", menu + sb.ToString().HtmlTag("div", "container"));

            context.Response.StatusCode = 200;
            await context.Response.WriteAsync(html);
        }
    }
}

Tiếp tục đăng ký ProductController như là dịch vụ của ứng dụng

/..
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IListProductName, PhoneName>();
    services.AddTransient<LaptopName, LaptopName>();
    services.AddTransient<ProductController, ProductController>();

}
/..

Với cách đăng ký dịch vụ như vậy, khi lấy ra dịch vụ ProductController thì dịch vụ IListProductNameLaptopName đã tự động Inject vào nó.

Map, MapWhen và sử dụng dịch vụ

Phương thức Map thuộc lớp IApplicationBuilder để routing Url một cách đơn giản - nó tạo ra một điểm rẽ nhánh trên pipeline. Bài trước đã trình bày về nó: xem tại IApplicationBuilder Map

Ví dụ, tạo ra điểm rẽ nhánh trên pipeline khi truy vấn với Url là /Product

app.Map("/Product", app => {
    app.Run(async (context) => {
        // Gọi đến dịch vụ ProductController
        var productcontroller = app.ApplicationServices.GetService<ProductController>();
        await productcontroller.List(context);
    });
});

MapWhen

Ý nghĩa của MapWhen giống Map, tạo ra một điểm rẽ nhánh trên pipeline - điểm khác là MapWhen không trực tiếp tạo mẫu route để so sánh với Url gửi đến rồi rẽ nhánh mà MapWhen lại thực hiện với một điều kiện logic bất kỳ nào đó. Cú pháp là:

MapWhen(Func<HttpContext, bool> predicate, Action<IApplicationBuilder> configuration);

Nếu predicate trả về true thì thực hiện configuration (trong nó thường tạo điểm cuối với RequestDelegate). Về Func và Action thì xem chi tiết tại: Delegate Func và Action

Ví dụ, thực hiện điều hướng Request - nếu url truy vấn (path) bắt đầu bởi Abcxyz

app.MapWhen(
    (context)  =>  {
        return context.Request.Path.Value.StartsWith("/Abcxyz");
    },

    appProduct => {
        appProduct.Run(async (context) => {
            await appProduct.ApplicationServices.GetService<ProductController>().List(context);
        });
});

Như vậy có thể truy cập với địa chỉ http://localhost:5000/Abcxyz123, http://localhost:5000/Abcxyz ...

Kiểm tra các dịch vụ đã đăng ký

Một ứng dụng ASP.NET có nhiều dịch vụ đăng ký vào DI Container, để xem ứng dụng đang có dịch vụ nào chúng ta liệt kê hết ra bằng cách sau:

public class Startup
{
    IServiceCollection  _services;

    public void ConfigureServices(IServiceCollection services)
    {
        /..
       _services = services;

    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        /..
        app.Map("/allservice", app01 => {
            app01.Run(async (context) => {

                var stringBuilder = new StringBuilder();
                stringBuilder.Append("<tr><th>Tên</th><th>Lifetime</th><th>Tên đầy đủ</th></tr>");
                foreach (var service in _services)
                {
                    string tr = service.ServiceType.Name.ToString().HtmlTag("td") +
                    service.Lifetime.ToString().HtmlTag("td") +
                    service.ServiceType.FullName.HtmlTag("td");
                    stringBuilder.Append(tr.HtmlTag("tr"));
                }

                string htmlallservice  = stringBuilder.ToString().HtmlTag("table", "table table-bordered table-sm");
                string html           = HtmlHelper.HtmlDocument("Các dịch vụ", (htmlallservice));

                await context.Response.WriteAsync(html);
            });
        });
        /..
    }
}

Tham khảo mã nguồn hoặc tải về


Đăng ký nhận bài viết mới