Phần 2 - Lọc các action method với cờ tính năng

Đây là bài thứ 2 trong loạt bài: Thêm cờ tính năng vào ứng dụng ASP.NET Core.

Trong bài đầu tiên của loạt bài này, tôi đã giới thiệu thư viện Microsoft.FeatureManagement và hướng dẫn cách sử dụng nó để thêm các cờ tính năng vào ứng dụng ASP.NET Core.

Trong bài viết này, tôi giới thiệu thư viện bổ sung là Microsoft.FeatureManagement.AspNetCore. Thư viện này bổ sung các tính năng dành riêng cho ASP.NET Core để làm việc với cờ tính năng, chẳng hạn như Tag Helper và Action Filter.

ASP.NET Core tích hợp cờ tính năng

Như tôi đã mô tả trong bài trước của mình, thư viện Microsoft.FeatureManagement là một thư viện .NET Standard 2.0 được xây dựng dựa trên Microsoft.Extensions.Configuration. Nó cung cấp một cách chuẩn hóa để thêm các cờ tính năng vào một ứng dụng.

Không có chỉ định ASP.NET Core cụ thể nào trong thư viện cơ sở này, vì vậy bạn có thể thoải mái sử dụng nó trong bất kỳ ứng dụng .NET Standard 2.0 nào.

Tuy nhiên, có một thư viện bổ sung Microsoft.FeatureManagement.AspNetCore phụ thuộc vào ASP.NET Core, chứa các chức năng trợ giúp khác nhau và các phương thức mở rộng để làm việc với các cờ tính năng.

Những điều này được mô tả trong tài liệu này và bao gồm một số điều sau:

  • Action Filter để loại bỏ các action dựa trên việc một tính năng có được bật hay không.
  • Tag Helper để ẩn các phần giao diện người dùng có điều kiện dựa trên các tính năng.
  • Các phương thức mở rộng để đăng ký có điều kiện các tuyến đường, bộ lọc toàn cầu hoặc middleware, dựa trên việc một tính năng có được bật hay không.

Trong bài đăng này, tôi sẽ hướng dẫn cách sử dụng Action Filter để xóa có điều kiện các action, FeatureTagHelper ẩn các phần của giao diện người dùng và IDisabledFeaturesHandler cung cấp hành vi tùy chỉnh nếu người dùng cố gắng truy cập một action ẩn sau cờ tính năng.

Thiết lập dự án

Tôi sẽ bắt đầu với một ứng dụng ASP.NET Core đơn giản, giống như trong bài trước. Nếu bạn đã thử quy trình từ bài đăng đó, bạn chỉ có thể thay thế tham chiếu đến thư viện Microsoft.FeatureManagement bằng tham chiếu đến thư viện Microsoft.FeatureManagement.AspNetCore.

dotnet add package Microsoft.FeatureManagement.AspNetCore

Sau khi thêm nó, .csproj của bạn sẽ trông giống như sau:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
    <PackageReference Include="Microsoft.FeatureManagement.AspNetCore" Version="2.4.0" />
  </ItemGroup>

</Project>

Tiếp theo, đăng ký các dịch vụ cần thiết trong phươgn thức ConfigureServices của class Startup:

public class Startup 
{
    public void ConfigureServices(IServiceCollection services)
    {
        //...
        services.AddFeatureManagement();
    }
}

Và thêm cấu hình cần thiết cho cờ tính năng Beta boolean đơn giản vào appsettings.json:

{
  "FeatureManagement": {
    "Beta": false
  }
}

Cuối cùng, tạo một lớp trợ giúp tĩnh để tham chiếu tính năng của bạn trong mã:

public static class FeatureFlags 
{
    public const string Beta = "Beta";
}

Đó là dự án cơ bản được cấu hình, vì vậy bây giờ chúng ta sẽ sử dụng một số tính năng được cung cấp bởi Microsoft.FeatureManagement.AspNetCore.

Xóa một action bằng cách sử dụng thuộc tính [FeatureGate]

Hãy tưởng tượng bạn có một Controller MVC "truyền thống" (trái ngược với Razor Page) mà bạn chỉ muốn sử dụng khi cờ tính năng Beta được bật. Bạn có thể trang trí Controller (hoặc các action cụ thể) bằng thuộc tính [FeatureGate], cung cấp tên của tính năng cho tham số feature:

using Microsoft.AspNetCore.Mvc;
using Microsoft.FeatureManagement.Mvc;

[FeatureGate(FeatureFlags.Beta)] // Beta feature flag must be enabled
public class BetaController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

Nếu bạn cố gắng điều hướng đến trang này (/Beta) khi tính năng Beta được bật, bạn sẽ thấy View được hiển thị như mong đợi:

Xóa một action bằng cách sử dụng thuộc tính [FeatureGate]

Tuy nhiên, nếu cờ tính năng Beta bị tắt, bạn sẽ nhận được 404 khi cố gắng xem trang:

Xóa một action bằng cách sử dụng thuộc tính [FeatureGate]

Nó như thể Controller hoàn toàn không tồn tại. Đó có thể không phải là trải nghiệm tốt nhất từ ​​góc nhìn của người dùng, vì vậy chúng tôi sẽ sớm thay đổi điều này.

Thuộc tính [FeatureGate] là một Action Filter tiêu chuẩn, vì vậy bạn có thể áp dụng nó cho các action method, controller, controller cơ sở hoặc toàn cầu. Tuy nhiên, có một số điều cần lưu ý:

  • Thuộc tính [FeatureGate] nhận một mảng các cờ tính năng, ​​trong phương thức khởi tạo của nó. Nếu bất kỳ tính năng nào trong số đó được bật, controller được bật. Nói một cách khác, bộ lọc kiểm tra OR các tính năng, không phải AND. Tuy nhiên, bây giờ bạn có thể sử dụng OR  hoặc AND bằng cách truyền một RequirementType vào bộ lọc.
  • Thuộc tính [FeatureGate] là một IActionFilter không phải IPageFilter, vì vậy nó hiện không hoạt động trên các Razor Page. Đó có vẻ như là một sự thiếu sót chắc chắn sẽ được khắc phục trước khi bản phát hành cuối cùng.

Xử lý tùy chỉnh các action bị thiếu

Như đã trình bày trong phần trước, nếu một action bị xóa do tính năng bị vô hiệu hóa, thì mặc định là tạo phản hồi 404. Điều đó có thể ổn đối với một số ứng dụng, đặc biệt nếu bạn đang sử dụng middleware xử lý lỗi để tùy chỉnh phản hồi lỗi nhằm tránh 404 "thô" xấu xí.

Tuy nhiên, cũng có thể bạn muốn tạo một phản hồi khác trong tình huống này. Có thể bạn muốn chuyển hướng người dùng đến trang "ổn" hơn, như trả về màn hình "tham gia danh sách chờ" hoặc chỉ cần trả lại một phản hồi khác, chẳng hạn như lỗi 403 Forbidden.

Bạn có thể đạt được bất kỳ cách tiếp cận nào trong số này bằng cách tạo một service triển khai interface IDisabledFeaturesHandler. Service triển khai được gọi như một phần của đường dẫn bộ lọc hành động, khi một action method bị "xóa" do một tính năng bị vô hiệu hóa. Trong ví dụ bên dưới, tôi trình bày cách tạo phản hồi 403 Forbidden, nhưng bạn có quyền truy cập vào toàn bộ ActionExecutingContext trong phương thức, vì vậy bạn có thể làm bất cứ điều gì có thể trong action filter chuẩn:

using Microsoft.FeatureManagement.Mvc;

public class RedirectDisabledFeatureHandler : IDisabledFeaturesHandler
{
    public Task HandleDisabledFeatures(IEnumerable<string> features, ActionExecutingContext context)
    {
        context.Result = new ForbidResult(); // generate a 403
        return Task.CompletedTask;
    }
}

Để đăng ký trình xử lý, hãy cập nhật cuộc gọi phương thức AddFeatureManagement() của bạn tới Startup.ConfigureServices():

public class Startup 
{
    public void ConfigureServices(IServiceCollection services)
    {
        //...
        services.AddFeatureManagement()
            .UseDisabledFeaturesHandler(new RedirectDisabledFeatureHandler());
    }
}

Với trình xử lý đã đăng ký, nếu bây giờ bạn cố gắng truy cập vào một tính năng bị vô hiệu hóa, phản hồi 403 sẽ được tạo, phản hồi này bị chặn bởi middleware xử lý lỗi và bạn được chuyển hướng đến trang "Quyền truy cập bị từ chối" cho ứng dụng:

Xử lý tùy chỉnh các action bị thiếu

Với những tính năng này, bạn có thể tắt các action method dựa trên việc một tính năng có được bật hay không và có quyền kiểm soát tốt những gì xảy ra khi một tính năng bị tắt được truy cập. Tuy nhiên, lý tưởng nhất là người dùng không nên cố gắng gọi các action của các tính năng bị tắt.

Ẩn liên kết trong View đối với các tính năng bị tắt

Nói chung, bạn không muốn người dùng của mình nhìn thấy các trang kiểu "Quyền truy cập bị từ chối" do cố gắng truy cập các tính năng bị vô hiệu hóa. Thay vào đó, bạn cũng nên ẩn các liên kết của tính năng bị tắt trong giao diện người dùng.

Như với tất cả các xác thực, bạn không nên chỉ dựa vào việc ẩn mọi thứ ở phía máy khách. Luôn sử dụng kiểm tra cờ tính năng phía máy chủ; chỉ ẩn nội dung trong giao diện người dùng để mang lại trải nghiệm người dùng tốt hơn.

Một cách để ẩn các thành phần trong View là đưa dịch vụ IFeatureManager vào view bằng cách sử dụng dependency injection. Ví dụ: hãy tưởng tượng bạn muốn thêm một liên kết tới BetaController vào trong thanh điều hướng của default layout. Bạn có thể sử dụng @inject và kiểm tra tính năng theo cách thủ công:

<!-- Inject the service using DI  -->
@inject Microsoft.FeatureManagement.IFeatureManager _featureManager; 

<nav>
    <ul>
        <!-- Check if the feature is enabled  -->
        @if (_featureManager.IsEnabled(FeatureFlags.Beta))
        {
            <li class="nav-item">
                <a class="nav-link text-dark" asp-controller="Beta" asp-action="Index">Beta</a>
            </li>
        }
    </ul>
</nav>

Cách tiếp cận này hoạt động tốt, nhưng đối với ví dụ này, bạn cũng có thể sử dụng FeatureTagHelper để đạt được điều tương tự nhưng với đánh dấu rõ ràng hơn:

<nav>
    <ul>
        <!-- Check if the feature is enabled using FeatureTagHelper -->
        <feature name="@FeatureFlags.Beta">
            <li class="nav-item">
                <a class="nav-link text-dark" asp-area="" asp-controller="Beta" asp-action="Index">Beta</a>
            </li>
        </feature>
    </ul>
</nav>

FeatureTagHelper hoạt động cho trường hợp sử dụng đơn giản này, nơi bạn có một cờ tính năng duy nhất phải được bật để hiển thị một số giao diện người dùng.

Cho đến nay, tôi mới chỉ giới thiệu việc tạo các cờ tính năng đơn giản là các giá trị boolean. Trong bài đăng tiếp theo, tôi sẽ chỉ cách bạn có thể tạo các cờ đặc trưng phức tạp hơn (và thú vị hơn!) bằng cách sử dụng Feature Filter. Những điều này cho phép bạn tùy chỉnh các cờ tính năng dựa trên yêu cầu hiện tại, mở ra cánh cửa cho các tình huống nâng cao hơn.

Tóm lược

Thư viện Microsoft.FeatureManagement.AspNetCore xây dựng dựa trên các tính năng của Microsoft.FeatureManagement, thêm các trình trợ giúp ASP.NET Core để làm việc với các cờ tính năng.

Nó chứa các action filter để vô hiệu hóa các action đằng sau cờ tính năng, tag helper để ẩn các phần tử giao diện người dùng có điều kiện và các phương thức mở rộng để tùy chỉnh đường dẫn ASP.NET Core dựa trên các tính năng đã bật.

Trong bài đăng tiếp theo, tôi sẽ trình bày một số tính năng mạnh mẽ hơn của thư viện cho phép bạn sử dụng các cờ tính năng phức tạp hơn.

Series: Thêm cờ tính năng vào ứng dụng ASP.NET Core
Trong loạt bài này, tôi sẽ trình bày cách tạo các cờ tính năng vào ứng dụng ASP.NET Core sử dụng thư viện Microsoft.FeatureManagement.
ASP.NET Core.NET CoreLập Trình C#ASP.NET Core MVC
Bài Viết Liên Quan:
Phần 6 - Các lựa chọn thay thế cho Microsoft.FeatureManagement
Trung Nguyen 13/03/2022
Phần 6 - Các lựa chọn thay thế cho Microsoft.FeatureManagement

Trong bài viết này, tôi giới thiệu sơ lược về một số lựa chọn thay thế cho thư viện Microsoft.FeatureManagement và mô tả sự khác biệt của chúng

Phần 5 - Đảm bảo cờ tính năng nhất quán trên các yêu cầu
Trung Nguyen 13/03/2022
Phần 5 - Đảm bảo cờ tính năng nhất quán trên các yêu cầu

Trong bài viết này, tôi giới thiệu hai cách để cải thiện tính nhất quán của cờ tính năng cho mọi yêu cầu đối với người dùng trong ứng dụng ASP.NET Core.

Phần 4 - Tạo bộ lọc tính năng tùy chỉnh
Trung Nguyen 13/03/2022
Phần 4 - Tạo bộ lọc tính năng tùy chỉnh

Trong bài viết này, tôi sẽ chỉ cho bạn cách tạo bộ lọc tính năng tùy chỉnh của riêng mình bằng cách sử dụng IFeatureFilter trong ASP.NET Core.

Phần 3 - Tạo cờ tính năng động với bộ lọc tính năng
Trung Nguyen 12/03/2022
Phần 3 - Tạo cờ tính năng động với bộ lọc tính năng

Trong bài này, tôi sẽ hướng dẫn cách sử dụng hai bộ lọc PercentageFilter và TimeWindowFilter để tạo cờ tính năng động trong ứng dụng ASP.NET Core.