Đây là bài thứ 4 trong loạt bài: Thêm cờ tính năng vào ứng dụng ASP.NET Core.
Microsoft.FeatureManagement cho phép bạn thêm các cờ tính năng vào ứng dụng ASP.NET Core được kiểm soát bởi hệ thống cấu hình. Trong bài viết trước, tôi đã giới thiệu các bộ lọc tính năng và chỉ ra cách chúng có thể được sử dụng để tạo cờ tính năng động. Tôi đã mô tả hai bộ lọc tính năng được tích hợp sẵn trong thư viện TimeWindowFilter
và PercentageFilter
.
Trong bài viết này, tôi chỉ cho bạn cách bạn có thể tạo bộ lọc tính năng tùy chỉnh của riêng mình. Ví dụ trong bài viết này tìm kiếm Claim trong ClaimsPrincipal của người dùng hiện đang đăng nhập và bật cờ tính năng nếu có. Bạn có thể sử dụng bộ lọc này để kích hoạt một tính năng cho một nhóm nhỏ người dùng của bạn.
Bài viết này giả định rằng bạn đã quen thuộc với các bộ lọc tính năng và thư viện Microsoft.FeatureManagement nói chung, vì vậy nếu chúng là người mới đối với bạn, tôi khuyên bạn nên đọc các bài viết trước trong loạt bài này.
Tạo bộ lọc tính năng tùy chỉnh yêu cầu hai điều:
IFeatureFilter
.Tôi sẽ bắt đầu với lớp cài đặt bộ lọc, vì chúng ta sẽ sử dụng lớp đó bên trong bộ lọc tính năng tùy chỉnh của mình.
Đối với ví dụ này, chúng ta muốn bật một tính năng chỉ cho những người dùng có một số xác nhận quyền sở hữu (claim) nhất định. Để đơn giản, tôi sẽ chỉ yêu cầu sự hiện diện của một loại xác nhận quyền sở hữu và bỏ qua giá trị của xác nhận quyền sở hữu, nhưng mở rộng ví dụ trong bài viết này phải đủ đơn giản. Đối tượng cài đặt chứa một loạt các loại xác nhận quyền sở hữu:
public class ClaimsFilterSettings
{
public string[] RequiredClaims { get; set; }
}
Không có gì đặc biệt về lớp cài đặt này; nó sẽ bị ràng buộc với cấu hình ứng dụng của bạn, vì vậy bạn chỉ bị hạn chế bởi các giới hạn của cấu hình ASP.NET Core / Microsoft.Extensions tiêu chuẩn.
Để tạo bộ lọc tính năng, bạn phải triển khai interface IFeatureFilter
, bao gồm một phương thức duy nhất:
public interface IFeatureFilter
{
bool Evaluate(FeatureFilterEvaluationContext context);
}
Đối số FeatureFilterEvaluationContext
được truyền vào phương thức chứa tên của đối tượng được yêu cầu và một đối tượng IConfiguration
cho phép bạn truy cập cài đặt cho đối tượng:
public class FeatureFilterEvaluationContext
{
public string FeatureName { get; set; }
public IConfiguration Parameters { get; set; }
}
Cần lưu ý rằng không có gì cụ thể cho ASP.NET Core ở đây - không cóHttpContext
và không cóIServiceProvider
. May mắn thay, lớp của bạn được inject từ DI Container, vì vậy bạn sẽ có thể nhận được mọi thứ bạn cần trong phương thức khởi tạo của bộ lọc tính năng của bạn.
Để triển khai bộ lọc tính năng tùy chỉnh, chúng ta cần biết người dùng hiện tại của yêu cầu là ai. Để làm như vậy, chúng ta cần truy cập vào HttpContext
.
Cách chính xác để làm điều đó (khi bạn không có quyền truy cập trực tiếp vào nó như khi bạn làm trong Controller MVC, v.v.) là sử dụng interface IHttpContextAccessor
.
Bên trong class ClaimsFeatureFilter
có một tham số là IHttpContextAccessor
trong hàm khởi tạo của nó và sử dụng HttpContext
để truy xuất người dùng hiện tại từ yêu cầu.
[FilterAlias("Claims")] // How we will refer to the filter in configuration
public class ClaimsFeatureFilter : IFeatureFilter
{
// Used to access HttpContext
private readonly IHttpContextAccessor _httpContextAccessor;
public ClaimsFeatureFilter(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public bool Evaluate(FeatureFilterEvaluationContext context)
{
// Get the ClaimsFilterSettings from configuration
var settings = context.Parameters.Get<ClaimsFilterSettings>();
// Retrieve the current user (ClaimsPrincipal)
var user = _httpContextAccessor.HttpContext.User;
// Only enable the feature if the user has ALL the required claims
var isEnabled = settings.RequiredClaims
.All(claimType => user.HasClaim(claim => claim.Type == claimType));
return isEnabled;
}
}
Tôi đã đặt tên cho bộ lọc tính năng này là "Claims" bằng cách sử dụng thuộc tính [FilterAlias]
. Đây là chuỗi bạn cần thêm vào cấu hình để kích hoạt bộ lọc, như bạn sẽ thấy ngay sau đây. Bạn có thể truy xuất ClaimsFilterSettings
liên kết với một instance nhất định của bộ lọc tính năng tùy chỉnh bằng cách gọi phương thức context.Parameters.Get<>()
.
Logic của bộ lọc tương đối đơn giản - nếu ClaimsPrincipal
cho yêu cầu có tất cả các xác nhận quyền sở hữu được yêu cầu, thì tính năng được liên kết sẽ được bật, nếu không thì tính năng này sẽ bị vô hiệu hóa.
Để sử dụng bộ lọc tính năng tùy chỉnh, bạn phải đăng ký nó với hệ thống quản lý tính năng trong Startup.ConfigureServices()
. Chúng ta cũng cần đảm bảo rằng interface IHttpContextAccessor
có sẵn trong DI Container:
using Microsoft.FeatureManagement;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add IHttpContextAccessor if it's not yet added
services.AddHttpContextAccessor();
services.AddFeatureManagement()
.AddFeatureFilter<ClaimsFeatureFilter>(); // add our custom filter
}
}
Tùy thuộc vào framework và các dịch vụ của bên thứ ba mà bạn đã thêm vào ứng dụng của mình,IHttpContextAccessor
có thể đã có sẵn. Tuy nhiên, nó an toàn khi gọiAddHttpContextAccessor()
nhiều lần, rất đáng để đề phòng.
Đó là tất cả cấu hình tùy chỉnh cần thiết để kích hoạt ClaimsFeatureFilter
của chúng ta. Để thực sự sử dụng nó trong một ứng dụng, chúng ta sẽ thêm một cờ tính năng có tên "Beta":
public static class FeatureFlags
{
public const string Beta = "Beta";
}
và bật bộ lọc trong cấu hình bằng cách sử dụng định dạng được mô tả trong bài trước:
{
"FeatureManagement":
{
"Beta":
{
"EnabledFor":
[
{
"Name": "Claims",
"Parameters":
{
"RequiredClaims": [ "Internal" ]
}
}
]
}
}
}
Lưu ý rằng tôi đã sử dụng giá trị "Claims" của[FilterAlias]
cho thuộc tínhName
của bộ lọc. Đối tượngParameters
tương ứng với đối tượng cài đặtClaimsFilterSettings
. Với cấu hình này, người dùng có xác nhận quyền sở hữu"Internal"
sẽ được bật cờ tính năngBeta
- người dùng khác sẽ thấy nó bị vô hiệu hóa.
Để kiểm tra bộ lọc tính năng, dễ nhất là bắt đầu với ứng dụng ASP.NET Core đã bật xác thực cá nhân. Với mục đích trình diễn, tôi đã cập nhật trang chủ Index.cshtml để hiển thị banner khi cờ tính năng Beta
được bật bằng FeatureTagHelper :
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<!-- Only visible when Beta feature flag is enabled -->
<feature name="@FeatureFlags.Beta">
<div class="alert alert-primary" role="alert">
Congratulations - You're in the Beta test!
</div>
</feature>
<!-- ... -->
Chạy lệnh di chuyển cơ sở dữ liệu cho ứng dụng bằng cách sử dụng lệnh sau:
dotnet ef database update
và sau đó chạy ứng dụng của bạn và đăng ký người dùng mới. Bạn sẽ thấy trang chủ tiêu chuẩn:
Banner "Beta" bị ẩn theo mặc định. Bộ lọc ClaimsFeatureFilter
của chúng ta đã kiểm tra xác nhận quyền sở hữu của người dùng đối với xác nhận quyền sở hữu bắt buộc "Internal"
, không có theo mặc định và được trả lại false
khi gọi phương thức IsEnabled()
của bộ lọc.
Để kích hoạt tính năng này, chúng ta cần thêm một xác nhận quyền sở hữu bổ sung cho người dùng.
Có một số cách để thêm xác nhận quyền sở hữu cho người dùng - khi người dùng được tạo, sau đó hoặc khi họ đăng nhập. Tôi đang đi theo con đường dễ dàng ở đây và chỉ cần thêm xác nhận quyền sở hữu vào cơ sở dữ liệu theo cách thủ công.
Với ASP.NET Core Identity, người dùng có thể thêm các xác nhận quyền sở hữu bổ sung tùy ý. Chúng được lưu trữ trong bảng AspNetUserClaims
(theo mặc định). Tôi đã sử dụng Server Explorer của Visual Studio để thêm một hàng mới trong bảng này được liên kết với người dùng của tôi, sử dụng loại xác nhận quyền sở hữu "Internal"
.
Nếu bạn đăng xuất và sau đó đăng nhập lại (để đảm bảo xác nhận quyền sở hữu mới được nhận), banner "Beta" sẽ hiện hiển thị - bộ lọc tính năng tùy chỉnh đã hoạt động!
Bộ lọc tính năng tùy chỉnh được ClaimsFeatureFilter
mô tả trong bài viết này chỉ nhằm mục đích làm ví dụ về bộ lọc bạn có thể sử dụng. Việc dựa vào HttpContext
mang lại cho nó một giới hạn cụ thể: nó không thể được sử dụng bên ngoài ngữ cảnh của một yêu cầu HTTP.
Cố gắng truy cập HttpContext
bên ngoài một yêu cầu HTTP có thể dẫn đến NullReferenceException
. Bạn cũng cần phải cẩn thận khi sử dụng nó trong một background thread, vì HttpContext
không an toàn cho một thread.
Một trong những tác động hơi nguy hiểm của điều này là người sử dụng (dev) cờ tính năng không biết tính năng nào là an toàn để truy vấn trong bối cảnh nào. Không có gì trong đoạn mã cho thấy nó có thể ném ra exception khi được sử dụng trong một background thread hoặc trong một dịch vụ được lưu trữ.
var isEnabled = _featureManager.IsEnabled(FeatureFlags.Beta); // may throw!
Một tùy chọn cơ bản để tránh tình huống này là sử dụng các quy ước đặt tên cho cờ đặc trưng của bạn. Ví dụ: bạn có thể sử dụng một quy ước trong đó cờ tính năng có tiền tố "UI_"
chỉ được coi là "an toàn" để truy cập khi có ngữ cảnh yêu cầu HTTP.
public static class FeatureFlags
{
// These flags are safe to access in any context
public const string NewBranding = "NewBranding";
public const string AlternativeColours = "AlternativeColours";
// These flags are only safe to access from an HttpContext-safe request
public static class Ui
{
const string _prefix = "UI_";
public const string Beta = _prefix + "Beta";
public const string NewOnboardingExperiences = _prefix + "NewOnboardingExperiences";
}
}
Điều này ít nhất cung cấp một chỉ báo cho người gọi khi cờ được sử dụng. Rõ ràng là nó yêu cầu bạn cấu hình các cờ một cách chính xác, nhưng đó là một bước đi đúng hướng!
// Flags on the main FeatureFlags class are safe to use everywhere
var isEnabled = _featureManager.IsEnabled(FeatureFlags.NewBranding);
// Flags on the nested Ui class are only safe when HttpContext is available
var isEnabled = _featureManager.IsEnabled(FeatureFlags.Ui.Beta);
Microsoft.FeatureManagement cho phép sử dụng bộ lọc tính năng để thêm hành vi động vào cờ tính năng của bạn. Trong bài viết này, tôi đã chỉ ra cách triển khai interface IFeatureFilter
tùy chỉnh của riêng bạn, sử dụng xác nhận quyền sở hữu của người dùng hiện tại để quyết định xem có nên bật cờ hay không.
Bộ lọc tính năng này hoạt động tốt trong ngữ cảnh của một yêu cầu (request), nhưng điều quan trọng là phải nhận thức được ý nghĩa của việc sử dụng HttpContext
liên quan đến việc sử dụng cờ tính năng trong background thread và bên ngoài ngữ cảnh HTTP.
Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
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
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.
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.
Trong bài này, tôi giới thiệu thư viện Microsoft.FeatureManagement.AspNetCore 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