Tạo liên kết đến các endpoint của ASP.NET Core

Tạo liên kết đến các endpoint của ASP.NET Core

Định tuyến là xương sống của mọi ứng dụng web và với ASP.NET Core, việc kết hợp các framework xử lý yêu cầu chưa bao giờ dễ dàng hơn thế. Chúng ta có thể chọn từ MVC, Blazor, Razor Pages, SignlaR, Carter, và nhiều hơn nữa.

Có thể nói rằng điểm mạnh của ASP.NET Core là khả năng tương tác của tất cả các phương pháp này trong một môi trường máy chủ duy nhất.

Trong bài viết này, chúng ta sẽ tìm hiểu cách đặt tên cho các phương thức Map để có thể tạo liên kết đến các endpoint (điểm cuối) từ bất kỳ đâu trong ứng dụng ASP.NET Core của chúng ta.

Tại sao nên sử dụng phương thức Map?

Với .NET 5, Microsoft đã tách định tuyến khỏi các framework MVC và WebAPI. Thay đổi này cho phép các nhà phát triển truy cập thông tin về request hiện tại ở các vị trí mới mà trước đây không có sẵn.

Kể từ phiên bản mới nhất của ASP.NET Core, chúng ta có thể bao gồm tất cả các ứng dụng web của mình bằng cách sử dụng endpoint, nhưng endpointlà gì?

Endpoint (điểm cuối) là một cấu trúc dữ liệu có thể: Được chọn để khớp với URL và phương thức HTTP. Thực thi bằng cách chạy một method delegate.

Hãy xem một ví dụ. Trong phương thức Configure chúng ta có thể gọi một số phương thức mở rộng của phương thức Map.

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

Chúng ta cũng có thể lập bản đồ các endpoint cho các framework như MVC, Blazor và SignalR bằng cách gọi phương thức tương ứng của MapControllers, MapBlazorHubMapHub<>.

ASP.NET Core có một số phương thức lập bản đồ cấp thấp phù hợp với các phương thức HTTP như: MapGet, MapPost, MapPutMapDelete. Các phương thức mở rộng này là viết tắt của phương thức Map, cùng với một số siêu dữ liệu mặc định.

public static IEndpointConventionBuilder MapMethods(
   this IEndpointRouteBuilder endpoints,
   string pattern,
   IEnumerable<string> httpMethods,
   RequestDelegate requestDelegate)
{
    if (httpMethods == null)
    {
        throw new ArgumentNullException(nameof(httpMethods));
    }

    var builder = endpoints.Map(RoutePatternFactory.Parse(pattern), requestDelegate);
    builder.WithDisplayName($"{pattern} HTTP: {string.Join(", ", httpMethods)}");
    builder.WithMetadata(new HttpMethodMetadata(httpMethods));
    
    return builder;
}

Lợi thế của việc sử dụng các phương thức mở rộng của phương thức Map là chúng ta có thể chọn các chức năng phù hợp, do đó cho phép chúng ta tinh chỉnh hiệu suất của ứng dụng web của chúng ta.

Điều này đặc biệt hữu ích khi chúng ta biết trường hợp sử dụng chính xác của mình. Ví dụ: chúng ta có thể biết rằng chúng ta sẽ xây dựng một HTTP endpoint chỉ sử dụng JSON. Chúng ta có thể tăng hiệu suất bằng cách loại bỏ mã hỗ trợ cho XML và các lệnh gọi không cần thiết đến các bước trong đường ống pipeline.

Bây giờ chúng ta đã có hiểu biết cơ bản về endpoint, hãy nói về các tuyến đường và sử dụng các định tuyến để tạo liên kết đến các endpoint khác.

Sử dụng EndpointNameMetadata và tạo liên kết

Như đã đề cập trong phần trước, hầu hết các đường dẫn vào ứng dụng ASP.NET Core của chúng ta có thể được coi là một endpoint. Điểm mạnh của việc xây dựng ứng dụng web là khả năng liên kết với các endpoint khác của chúng ta.

May mắn cho chúng ta, khi sử dụng định tuyến endpoint trong ASP.NET Core, chúng ta cũng có quyền truy cập vào lớp LinkGenerator.

Class LinkGenerator cho chúng ta khả năng để tạo ra các URI tuyệt đối và tương đối dựa trên thiết bị đầu cuối đã đăng ký trước đó. LinkGeneratorlà một tính năng quan trọng giúp chúng ta tránh những sai lầm khi tạo liên kết.

Để tận dụng tối đa các endpoint, chúng ta sẽ muốn đăng ký các endpoint bằng tên. Chúng ta thực hiện điều này bằng cách sử dụng phương thức WithMetadatasau khi khai báo endpoint của chúng ta. Đối với phương thức này, chúng ta sẽ truyền vào một instance của EndpointNameMetadata.

    // 1. Register an endpoint as you normally would
    endpoints.MapGet("hello/{name}", async context =>
    {
        var name = context.GetRouteValue("name") ?? "world";
        await context.Response.WriteAsync($"Hello {name}!");
    })
    // 2. After the declaration you need to add an 
    //    `EndpointNameMetadata` to the endpoint declaration
    .WithMetadata(new EndpointNameMetadata("hello-name"));

Để tạo liên kết đến endpoint này, chúng ta chỉ cần tham chiếu đến nó bằng tên. Trong trường hợp này, tên của endpoint của chúng ta là hello-name.

    endpoints.MapGet("/", async context =>
    {
        // 3. Pull the `LinkGenerator` from the DI container, you'll need this
        var links = context.RequestServices.GetRequiredService<LinkGenerator>();
        // 4. Generate the link with the name from above, along with route values.
        var href = links.GetUriByName(
            context, 
            "hello-name", 
            new {name = "Trung Nguyen"}
        );
        
        context.Response.ContentType = "text/html";
        // 5. Use the generated link in the code
        await context.Response.WriteAsync($"<a href="{href}">Hello?!</a>");
    });

Bây giờ chúng ta có thể liên kết đến endpoint này từ bất kỳ đâu trong ứng dụng ASP.NET Core của chúng ta. Endpoint này hiện có sẵn theo tên từ MVC, Blazor, Razor Pages, Middleware và các endpoint khác.

Trong đoạn mã trên, chúng ta sử dụng phương thức GetUriByName, điều này cho phép chúng ta có được một liên kết tuyệt đối đến endpoint của chúng ta, nhưng chúng ta cũng có thể sử dụng phương thức GetPathByNamenó sẽ cung cấp cho chúng ta một liên kết tương đối.

Đây là giải pháp hoàn chỉnh bên trong phương thức UseEndpoints của chúng ta được tìm thấy trong class Startup.

app.UseEndpoints(endpoints =>
{
    // 1. Register an endpoint as you normally would
    endpoints.MapGet("hello/{name}", async context =>
    {
        var name = context.GetRouteValue("name") ?? "world";
        await context.Response.WriteAsync($"Hello {name}!");
    })
    // 2. After the declaration you need to add an 
    //    `EndpointNameMetadata` to the endpoint declaration
    .WithMetadata(new EndpointNameMetadata("hello-name"));
    
    endpoints.MapGet("/", async context =>
    {
        // 3. Pull the `LinkGenerator` from the DI container, you'll need this
        var links = context.RequestServices.GetRequiredService<LinkGenerator>();
        // 4. Generate the link with the name from above, along with route values.
        var href = links.GetUriByName(
            context, 
            "hello-name", 
            new { name = "Trung Nguyen" }
        );
        
        context.Response.ContentType = "text/html";
        // 5. Use the generated link in the code
        await context.Response.WriteAsync($"<a href="{href}">Hello?!</a>");
    });
});

Nếu bạn thấy thông tin này hữu ích, vui lòng chia sẻ nó để các nhà phát triển ASP.NET khác cũng có thể biết kiến ​​thức tuyệt vời này.

Chúng ta cũng có thể làm cho điều này gọn gàng hơn một chút bằng cách tạo một phương thức mở rộng để thêm tên cho các endpoint của chúng ta ít dài dòng hơn.

public static class EndpointExtensions
{
    public static IEndpointConventionBuilder WithName(
        this IEndpointConventionBuilder builder, string name
    ) => builder.WithMetadata(new EndpointNameMetadata(name));
}

Phương thức mở rộng dẫn này đến một thay đổi nhỏ nhưng đáng giá trong mã đăng ký của chúng ta.

// 1. Register an endpoint as you normally would
endpoints.MapGet("hello/{name}", async context =>
{
    var name = context.GetRouteValue("name") ?? "world";
    await context.Response.WriteAsync($"Hello {name}!");
})
// 2. After the declaration you need to add an 
//    `EndpointNameMetadata` to the endpoint declaration
.WithName("hello-name");

Phần kết luận

Endpoint (điểm cuối) là một tính năng tuyệt vời của ASP.NET Core. Sử dụng các phương pháp Map này có thể giúp chúng ta tinh chỉnh ứng dụng hiệu quả và cho phép chúng ta loại bỏ khối lượng của các framework nặng nề.

Mặc dù chúng ta có thể đang hướng tới trải nghiệm được cắt giảm, nhưng chúng ta vẫn muốn sử dụng các tính năng như tạo liên kết. Bằng cách thêm một lệnh gọi đơn giản là WithMetadata vàocùng với một phiên bản mới EndpointNameMetadata, chúng ta có thể tham chiếu đến các endpoint của mình giống như chúng ta thực thi một hành động của Controller hoặc Razor Page.

Biết được sự tồn tại của phương thức WithMetadata sẽ mở ra một thế giới khả năng mới cho các nhà phát triển.

Cảm ơn bạn đã đọc và cho tôi biết trong phần bình luận nếu bạn thấy bài viết này hữu ích.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *