C# Cơ bản .NET Core §1) Cài đặt, chương trình C# đầu tiên §2) Biến, kiểu dữ liệu và nhập/xuất §3) Toán tử số học và gán §4) So sánh, logic và lệnh if, switch §5) Vòng lặp for, while §6) Phương thức - Method §7) Phương thức - Delegate §8) Lớp - Class §9) Kiểu vô danh và dynamic §10) Biểu thức lambda §11) Event §12) Hàm hủy - Quá tải toán tử - thành viên tĩnh - indexer §13) Lớp lồng nhau - namespace §14) null và nullable §15) Mảng §16) Chuỗi ký tự §17) Tính kế thừa §18) Tính đa hình - abstract - interface §19) Struct và Enum §20) Ngoại lệ Exeption §21) IDisposable - using §22) File cơ bản §23) FileStream §24) Generic §25) Collection - List §26) SortedList §27) Queue / Stack §28) Linkedlist §29) Dictionary - HashSet §30) Phương thức mở rộng §31) ObservableCollection §32) LINQ §33) (Multithreading) async - bất đồng bộ §34) Type §35) Attribute Annotation §36) DI Dependency Injection §37) (Multithreading) Parallel §38) (Networking) HttpClient §39) (Networking) HttpMessageHandler §40) (Networking) HttpListener §41) (Networking) Tcp TcpListenerr/TcpClient §42) (ADO.NET) SqlConnection §43) (ADO.NET) SqlCommand §44) (EF Core) Tổng quan §45) (EF Core) Tạo Model §46) (EF Core) Fluent API §47) (EF Core) Query §48) (EF Core) Scaffold §49) (EF Core) Migration §50) (ASP.NET CORE) Hello World! §51) (ASP.NET CORE) Middleware §52) (ASP.NET CORE) Map - Request - Response §53) (ASP.NET CORE) IServiceCollection - MapWhen §54) (ASP.NET CORE) Session - ISession §55) (ASP.NET CORE) Configuration §56) (ASP.NET CORE MVC) Controller - View

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. Để thực hành nhanh chóng, copy lại mã nguồn dự án ở vị dụ cũ ở bài (ASP.NET Core) Đọc và ghi Request và Response, tức copy MÃ NGUỒN đổi tên thư mục thành WebApp-v1, sau đó mở ra bằng Visual Studio Code để thực hiện.

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 sản phẩm.

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

    namespace WebApp.Services
    {
        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;

    namespace WebApp.Services
    {
        public class LaptopName : IListProductName
        {
            public LaptopName() => System.Console.WriteLine("LaptopName Create");
            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;
    namespace WebApp.Services
    {
        public class PhoneName : IListProductName
        {
            public PhoneName() => System.Console.WriteLine("PhoneName created");
            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 (cận thậ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 WebApp.Services;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using System.Text;
using System.Linq;

namespace WebApp.Controller
{
    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, ví dụ thiết lập truy cập đến địa chỉ /Product - thì điều hướng đến một phương thức dạng Action<IApplicationBuilder>

app.Map("/Product", (IApplicationBuilder appProduct) => {
        /..
    });

Hoặc viết ngắn gọn:

app.Map("/Product", (appProduct) => {
    /..
});

Cũng nhắc lại ở ví dụ trước, nếu appProduct có thiết lập một RequestDelegate qua phương thức Run, thì nó sẽ là điểm chốt cuối cùng xử lý Request gửi đến, có nghĩa là trang sẽ trả về khi gặp nó.

Áp dụng cụ thể cho ví dụ này:

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

Ngoài Map bạn cũng có thể sử dụng MapWhen để chuyển hướng xử lý Request. Phương thức này tham số đầu tiên là một delegate dạng Func<HttpContext, bool> - nếu trả về true thì Request sẽ chuyển xử lý bởi RequestDelegate của phương thức này, tham số thư 2 tương tự như của Map là RequestDelegate.

Func<HttpContext, bool> tương đương với:

(HttpContext context) => {
    /..
    return /.. true  or false
}

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);
            });
        });
        /..
    }
}
Mã Nguồn
Đăng ký theo dõi ủng hộ kênh