Zarządzanie funkcjami platformy .NET

Microsoft.FeatureManagement
Microsoft.FeatureManagement.AspNetCore

Microsoft.FeatureManagement
Microsoft.FeatureManagement.AspNetCore
Microsoft.FeatureManagement.Telemetry.ApplicationInsights
Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore

Biblioteka zarządzania funkcjami platformy .NET umożliwia opracowywanie i uwidacznianie funkcjonalności aplikacji na podstawie flag funkcji. Po utworzeniu nowej funkcji wiele aplikacji ma specjalne wymagania, takie jak włączenie funkcji i określenie warunków. Ta biblioteka umożliwia zdefiniowanie tych relacji, a także integruje się z typowymi wzorcami kodu platformy .NET, aby uwidocznić te funkcje.

Flagi funkcji umożliwiają aplikacjom platformy .NET i ASP.NET Core dynamiczne włączanie lub wyłączanie funkcji. Deweloperzy mogą używać flag funkcji w prostych przypadkach użycia, takich jak instrukcje warunkowe, do bardziej zaawansowanych scenariuszy, takich jak warunkowe dodawanie tras lub filtrów MVC. Flagi funkcji są oparte na systemie konfiguracji platformy .NET Core. Każdy dostawca konfiguracji platformy .NET Core może działać jako szkielet flag funkcji.

Poniżej przedstawiono niektóre korzyści wynikające z używania biblioteki zarządzania funkcjami platformy .NET:

  • Wspólna konwencja zarządzania funkcjami

  • Niski poziom bariery do wejścia

    • Zbudowany na IConfiguration
    • Obsługuje konfigurację flagi funkcji pliku JSON
  • Zarządzanie okresem istnienia flagi funkcji

    • Wartości konfiguracji mogą ulec zmianie w czasie rzeczywistym; flagi funkcji mogą być spójne w całym żądaniu
  • Scenariusze proste i złożone

    • Przełączanie/wyłączanie funkcji za pomocą deklaratywnego pliku konfiguracji
    • Dynamiczne ocenianie stanu funkcji na podstawie wywołania do serwera
  • Rozszerzenia interfejsu API dla platformy ASP.NET Core i MVC

    • Routing
    • Filtry
    • Atrybuty akcji

    Biblioteka zarządzania funkcjami platformy .NET jest typu open source. Aby uzyskać więcej informacji, odwiedź repozytorium GitHub.

Flagi funkcji

Flagi funkcji składają się z dwóch części, nazwy i listy filtrów funkcji, które są używane do włączania funkcji.

Filtry funkcji

Filtry funkcji definiują scenariusz włączania funkcji. Gdy funkcja jest oceniana pod kątem tego, czy jest włączona, czy wyłączona, jej lista filtrów funkcji jest przechodzina do momentu, aż jeden z filtrów zdecyduje, że funkcja powinna zostać włączona. W tym momencie funkcja jest uznawana za włączoną i przechodzi przez filtry funkcji. Jeśli żaden filtr funkcji nie wskazuje, że funkcja powinna być włączona, jest uważana za wyłączoną.

Na przykład można zaprojektować filtr funkcji przeglądarki Microsoft Edge. Ten filtr funkcji aktywuje wszystkie funkcje, do których jest dołączony, o ile żądanie HTTP pochodzi z przeglądarki Microsoft Edge.

Konfiguracja flagi funkcji

System konfiguracji platformy .NET Core służy do określania stanu flag funkcji. Podstawą tego systemu jest IConfiguration. Dowolny dostawca IConfiguration dla programu może służyć jako dostawca stanu funkcji dla biblioteki flag funkcji. Ten system umożliwia scenariusze od appsettings.json do aplikacja systemu Azure Konfiguracji i nie tylko.

Deklaracja flagi funkcji

Biblioteka zarządzania funkcjami obsługuje appsettings.json jako źródło flagi funkcji, ponieważ jest to dostawca systemu .NET Core IConfiguration . Poniżej przedstawiono przykład formatu używanego do konfigurowania flag funkcji w pliku json.

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },

    // Define feature flags in a json file
    "FeatureManagement": {
        "FeatureT": {
            "EnabledFor": [
                {
                    "Name": "AlwaysOn"
                }
            ]
        },
        "FeatureU": {
            "EnabledFor": []
        },
        "FeatureV": {
            "EnabledFor": [
                {
                    "Name": "TimeWindow",
                    "Parameters": {
                        "Start": "Wed, 01 May 2019 13:59:59 GMT",
                        "End": "Mon, 01 Jul 2019 00:00:00 GMT"
                    }
                }
            ]
        }
    }
}

Sekcja FeatureManagement dokumentu JSON jest używana przez konwencję do ładowania ustawień flag funkcji. W powyższej sekcji przedstawiono trzy różne funkcje. Funkcje definiują filtry funkcji przy użyciu EnabledFor właściwości . W filtrach funkcji dla FeatureTelementu widzimy wartość AlwaysOn. Ten filtr funkcji jest wbudowany i jeśli zostanie określony, zawsze włączy tę funkcję. Filtr AlwaysOn funkcji nie wymaga żadnej konfiguracji, dlatego ma Name tylko właściwość . FeatureU nie ma filtrów we właściwości i w związku z tym EnabledFor nigdy nie zostanie włączony. Wszystkie funkcje, które opierają się na tej włączonej funkcji, nie będą dostępne tak długo, jak filtry funkcji pozostaną puste. Jednak po dodaniu filtru funkcji, który umożliwia rozpoczęcie pracy funkcji. FeatureV określa filtr funkcji o nazwie TimeWindow. Jest to przykład konfigurowalnego filtru funkcji. W przykładzie widać, że filtr ma Parameters właściwość . Służy do konfigurowania filtru. W takim przypadku konfigurowane są czasy rozpoczęcia i zakończenia dla funkcji, która ma być aktywna.

Szczegółowy schemat FeatureManagement sekcji można znaleźć tutaj.

Zaawansowane: użycie dwukropka ":" jest zabronione w nazwach flag funkcji.

Deklaracja wł./wył.

Poniższy fragment kodu przedstawia alternatywny sposób definiowania funkcji, która może służyć do włączania/wyłączania funkcji.

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },

    // Define feature flags in config file
    "FeatureManagement": {
        "FeatureT": true, // On feature
        "FeatureX": false // Off feature
    }
}

Typ wymagania

Właściwość RequirementType flagi funkcji służy do określania, czy filtry powinny być używane Any , czy All logika podczas oceniania stanu funkcji. Jeśli RequirementType nie zostanie określony, wartość domyślna to Any.

  • Any oznacza, że tylko jeden filtr musi mieć wartość true, aby funkcja została włączona.
  • All oznacza, że każdy filtr musi mieć wartość true, aby funkcja została włączona.

A RequirementType zmiany All przechodzenia. Po pierwsze, jeśli nie ma filtrów, funkcja jest wyłączona. Następnie filtry funkcji są przechodzine do momentu, aż jeden z filtrów zdecyduje, że funkcja powinna zostać wyłączona. Jeśli żaden filtr nie wskazuje, że funkcja powinna być wyłączona, jest uważana za włączoną.

"FeatureW": {
    "RequirementType": "All",
    "EnabledFor": [
        {
            "Name": "TimeWindow",
            "Parameters": {
                "Start": "Mon, 01 May 2023 13:59:59 GMT",
                "End": "Sat, 01 Jul 2023 00:00:00 GMT"
            }
        },
        {
            "Name": "Percentage",
            "Parameters": {
                "Value": "50"
            }
        }
    ]
}

W powyższym przykładzie określa wartość RequirementType All, co oznacza, FeatureW że wszystkie jego filtry muszą mieć wartość true, aby funkcja została włączona. W takim przypadku funkcja jest włączona dla 50% użytkowników w określonym przedziale czasu.

Schemat zarządzania funkcjami firmy Microsoft

Biblioteka zarządzania funkcjami obsługuje również użycie Microsoft Feature Management schema funkcji do deklarowania flag funkcji. Ten schemat jest niezależny od języka pochodzenia i jest obsługiwany przez wszystkie biblioteki zarządzania funkcjami firmy Microsoft.

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "FeatureT",
                "enabled": true,
                "conditions": {
                    "client_filters": [
                        {  
                            "name": "Microsoft.TimeWindow",
                            "parameters": {
                                "Start": "Mon, 01 May 2023 13:59:59 GMT",
                                "End": "Sat, 01 Jul 2023 00:00:00 GMT"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

Uwaga

Jeśli sekcję feature_management można znaleźć w konfiguracji, FeatureManagement sekcja zostanie zignorowana.

Biblioteka zarządzania funkcjami obsługuje appsettings.json jako źródło flagi funkcji, ponieważ jest to dostawca systemu .NET Core IConfiguration . Flagi funkcji są deklarowane przy użyciu elementu Microsoft Feature Management schema. Ten schemat jest niezależny od języka pochodzenia i jest obsługiwany przez wszystkie biblioteki zarządzania funkcjami firmy Microsoft.

Poniżej przedstawiono przykład deklarowania flag funkcji w pliku json.

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },

    // Define feature flags in a json file
    "feature_management": {
        "feature_flags": [
            {
                "id": "FeatureT",
                "enabled": false
            },
            {
                "id": "FeatureU",
                "enabled": true,
                "conditions": {}
            },
            {
                "id": "FeatureV",
                "enabled": true,
                "conditions": {
                    "client_filters": [
                        {  
                            "name": "Microsoft.TimeWindow",
                            "parameters": {
                                "Start": "Mon, 01 May 2023 13:59:59 GMT",
                                "End": "Sat, 01 July 2023 00:00:00 GMT"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

Sekcja feature_management dokumentu JSON jest używana przez konwencję do ładowania ustawień flag funkcji. Obiekty flag funkcji muszą być wymienione w tablicy feature_flags w feature_management sekcji . W powyższej sekcji widzimy, że udostępniliśmy trzy różne funkcje. Flaga funkcji ma id właściwości i enabled . To id nazwa używana do identyfikowania i odwołowania się do flagi funkcji. Właściwość enabled określa stan włączonej flagi funkcji. Funkcja jest wyłączona , jeśli enabled ma wartość false. Jeśli enabled wartość ma wartość true, stan funkcji zależy od conditionswartości . Jeśli nie ma conditions , funkcja jest włączona. Jeśli istnieją conditions i są one spełnione, funkcja jest włączona. Jeśli istnieją conditions i nie są one spełnione, funkcja jest wyłączona. Właściwość conditions deklaruje warunki używane do dynamicznego włączania funkcji. Funkcje definiują filtry funkcji w tablicy client_filters . FeatureV określa filtr funkcji o nazwie Microsoft.TimeWindow. Jest to przykład konfigurowalnego filtru funkcji. W przykładzie widać, że filtr ma Parameters właściwość . Służy do konfigurowania filtru. W takim przypadku konfigurowane są czasy rozpoczęcia i zakończenia dla funkcji, która ma być aktywna.

Zaawansowane: użycie dwukropka ":" jest zabronione w nazwach flag funkcji.

Typ wymagania

Właściwość requirement_type elementu conditions służy do określania, czy filtry powinny być używane Any , czy All logika podczas oceniania stanu funkcji. Jeśli requirement_type nie zostanie określony, wartość domyślna to Any.

  • Any oznacza, że tylko jeden filtr musi mieć wartość true, aby funkcja została włączona.
  • All oznacza, że każdy filtr musi mieć wartość true, aby funkcja została włączona.

A requirement_type zmiany All przechodzenia. Najpierw, jeśli nie ma filtru, funkcja zostanie wyłączona. Jeśli istnieją filtry, filtry funkcji są przechodzine do momentu, aż jeden z filtrów zdecyduje, że funkcja powinna zostać wyłączona. Jeśli żaden filtr nie wskazuje, że funkcja powinna być wyłączona, zostanie ona uznana za włączoną.

{
    "id": "FeatureW",
    "enabled": true,
    "conditions": {
        "requirement_type": "All",
        "client_filters": [
            {
                "name": "Microsoft.TimeWindow",
                "parameters": {
                    "Start": "Mon, 01 May 2023 13:59:59 GMT",
                    "End": "Sat, 01 Jul 2023 00:00:00 GMT"
                }
            },
            {
                "name": "Microsoft.Percentage",
                "parameters": {
                    "Value": "50"
                }
            }
        ]
    }
}

W powyższym przykładzie określa wartość requirement_type All, co oznacza, FeatureW że wszystkie jego filtry muszą mieć wartość true, aby funkcja została włączona. W takim przypadku funkcja zostanie włączona dla 50% użytkowników w określonym przedziale czasu.

Schemat zarządzania funkcjami platformy .NET

W poprzednich wersjach podstawowym schematem biblioteki zarządzania funkcjami była .NET feature management schema. Począwszy od wersji 4.0.0, nowe funkcje, w tym warianty i dane telemetryczne, nie będą obsługiwane dla schematu zarządzania funkcjami platformy .NET.

Uwaga

Jeśli w sekcjach i FeatureManagement znajduje się feature_management deklaracja flagi funkcji, zostanie przyjęta ta z feature_management sekcji .

Zużycie

Podstawową formą zarządzania funkcjami jest sprawdzenie, czy flaga funkcji jest włączona, a następnie wykonuje akcje na podstawie wyniku. Odbywa się to za pomocą IFeatureManagermetody "s IsEnabledAsync ".

…
IFeatureManager featureManager;
…
if (await featureManager.IsEnabledAsync("FeatureX"))
{
    // Do something
}

Rejestracja usługi

Zarządzanie funkcjami opiera się na iniekcji zależności platformy .NET Core. Usługi zarządzania funkcjami można zarejestrować przy użyciu standardowych konwencji.

using Microsoft.FeatureManagement;

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

Domyślnie menedżer funkcji pobiera konfigurację flagi funkcji z sekcji "FeatureManagement" danych konfiguracji platformy .NET Core. Jeśli sekcja "FeatureManagement" nie istnieje, konfiguracja jest uważana za pustą.

Uwaga

Można również określić, że konfiguracja flagi funkcji powinna zostać pobrana z innej sekcji konfiguracji, przekazując sekcję do AddFeatureManagement. Poniższy przykład informuje menedżera funkcji o konieczności odczytania z innej sekcji o nazwie "MyFeatureFlags":

services.AddFeatureManagement(configuration.GetSection("MyFeatureFlags"));

Wstrzykiwanie zależności

W przypadku korzystania z biblioteki zarządzania funkcjami w programie MVC IFeatureManager można uzyskać za pomocą wstrzykiwania zależności.

public class HomeController : Controller
{
    private readonly IFeatureManager _featureManager;
    
    public HomeController(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }
}

Usługi zarządzania funkcjami w zakresie

Metoda AddFeatureManagement dodaje usługi zarządzania funkcjami jako pojedynczetony w aplikacji, ale istnieją scenariusze, w których może być konieczne dodanie usług zarządzania funkcjami jako usług o określonym zakresie. Na przykład użytkownicy mogą chcieć używać filtrów funkcji korzystających z usług o określonym zakresie na potrzeby informacji kontekstowych. W takim przypadku AddScopedFeatureManagement należy użyć metody . Dzięki temu usługi zarządzania funkcjami, w tym filtry funkcji, są dodawane jako usługi o określonym zakresie.

services.AddScopedFeatureManagement();

integracja ASP.NET Core

Biblioteka zarządzania funkcjami udostępnia funkcje w ASP.NET Core i MVC w celu włączenia typowych scenariuszy flag funkcji w aplikacjach internetowych. Te możliwości są dostępne, odwołując się do pakietu NuGet Microsoft.FeatureManagement.AspNetCore .

Kontrolery i akcje

Kontroler MVC i akcje mogą wymagać włączenia danej funkcji lub jednej z dowolnej listy funkcji w celu wykonania. Można to zrobić przy użyciu elementu FeatureGateAttribute, który można znaleźć w Microsoft.FeatureManagement.Mvc przestrzeni nazw.

[FeatureGate("FeatureX")]
public class HomeController : Controller
{
    …
}

Powyższe HomeController są bramowane przez funkcję "FeatureX". Aby można było wykonać akcję zawierającą HomeController , należy włączyć funkcję "FeatureX".

[FeatureGate("FeatureX")]
public IActionResult Index()
{
    return View();
}

Powyższa Index akcja MVC wymaga włączenia funkcji "FeatureX", zanim będzie można ją wykonać.

Wyłączona obsługa akcji

Gdy kontroler MVC lub akcja jest blokowana, ponieważ żadna z funkcji, które określa, nie jest włączona, zostanie wywołana zarejestrowana IDisabledFeaturesHandler . Domyślnie jest rejestrowana minimalna procedura obsługi, która zwraca protokół HTTP 404. Można to przesłonić przy użyciu IFeatureManagementBuilder flag funkcji podczas rejestrowania flag funkcji.

public interface IDisabledFeaturesHandler
{
    Task HandleDisabledFeature(IEnumerable<string> features, ActionExecutingContext context);
}

Widok

W widokach <feature> MVC tagi mogą służyć do warunkowego renderowania zawartości na podstawie tego, czy funkcja jest włączona, czy nie.

<feature name="FeatureX">
  <p>This can only be seen if 'FeatureX' is enabled.</p>
</feature>

Możesz również negować ocenę pomocnika tagów, aby wyświetlić zawartość, gdy funkcja lub zestaw funkcji są wyłączone. negate="true" Ustawienie w poniższym przykładzie powoduje renderowanie zawartości tylko wtedy, gdy FeatureX jest wyłączona.

<feature negate="true" name="FeatureX">
  <p>This can only be seen if 'FeatureX' is disabled.</p>
</feature>

Tag <feature> może odwoływać się do wielu funkcji, określając rozdzielaną przecinkami listę funkcji w atrybucie name .

<feature name="FeatureX,FeatureY">
  <p>This can only be seen if 'FeatureX' and 'FeatureY' are enabled.</p>
</feature>

Domyślnie wszystkie wymienione funkcje muszą być włączone, aby tag funkcji był renderowany. To zachowanie można zastąpić, dodając requirement atrybut, jak pokazano w poniższym przykładzie.

<feature name="FeatureX,FeatureY" requirement="Any">
  <p>This can only be seen if either 'FeatureX' or 'FeatureY' or both are enabled.</p>
</feature>

W widokach <feature> MVC tagi mogą służyć do warunkowego renderowania zawartości na podstawie tego, czy funkcja jest włączona, czy też jest przypisany określony wariant funkcji. Aby uzyskać więcej informacji, zobacz sekcję wariantów .

<feature name="FeatureX">
  <p>This can only be seen if 'FeatureX' is enabled.</p>
</feature>
<feature name="FeatureX" variant="Alpha">
  <p>This can only be seen if variant 'Alpha' of 'FeatureX' is assigned.</p>
</feature>

Możesz również negować ocenę pomocnika tagów, aby wyświetlić zawartość, gdy funkcja lub zestaw funkcji są wyłączone. negate="true" Ustawienie w poniższym przykładzie powoduje renderowanie zawartości tylko wtedy, gdy FeatureX jest wyłączona.

<feature negate="true" name="FeatureX">
  <p>This can only be seen if 'FeatureX' is disabled.</p>
</feature>
<feature negate="true" name="FeatureX" variant="Alpha">
  <p>This can only be seen if variant 'Alpha' of 'FeatureX' isn't assigned.</p>
</feature>

Tag <feature> może odwoływać się do wielu funkcji/wariantów, określając rozdzielaną przecinkami listę funkcji/wariantów w atrybucie/namevariant.

<feature name="FeatureX,FeatureY">
  <p>This can only be seen if 'FeatureX' and 'FeatureY' are enabled.</p>
</feature>
<feature name="FeatureX" variant="Alpha,Beta">
  <p>This can only be seen if variant 'Alpha' or 'Beta' of 'FeatureX' is assigned.</p>
</feature>

Uwaga

Jeśli variant zostanie określona, należy określić tylko jedną funkcję.

Domyślnie wszystkie wymienione funkcje muszą być włączone, aby tag funkcji był renderowany. To zachowanie można zastąpić, dodając requirement atrybut, jak pokazano w poniższym przykładzie.

Uwaga

Jeśli element requirement And jest używany w połączeniu z variant błędem, zostanie zgłoszony, ponieważ nigdy nie można przypisać wielu wariantów.

<feature name="FeatureX,FeatureY" requirement="Any">
  <p>This can only be seen if either 'FeatureX' or 'FeatureY' or both are enabled.</p>
</feature>

Tag <feature> wymaga, aby pomocnik tagu działał. Można to zrobić, dodając pomocnik tagu zarządzania funkcjami do pliku ViewImports.cshtml .

@addTagHelper *, Microsoft.FeatureManagement.AspNetCore

Filtry MVC

Filtry akcji MVC można skonfigurować do warunkowego wykonywania na podstawie stanu funkcji. Odbywa się to przez zarejestrowanie filtrów MVC w sposób świadomy funkcji. Potok zarządzania funkcjami obsługuje asynchroniczne filtry akcji MVC, które implementują IAsyncActionFilterelement .

services.AddMvc(o => 
{
    o.Filters.AddForFeature<SomeMvcFilter>("FeatureX");
});

Powyższy kod dodaje filtr MVC o nazwie SomeMvcFilter. Ten filtr jest wyzwalany tylko w potoku MVC, jeśli opcja "FeatureX" jest włączona.

Razor Pages

Strony MVC Razor mogą wymagać włączenia danej funkcji lub jednej z dowolnej listy funkcji w celu wykonania. Można to zrobić przy użyciu elementu FeatureGateAttribute, który można znaleźć w Microsoft.FeatureManagement.Mvc przestrzeni nazw.

[FeatureGate("FeatureX")]
public class IndexModel : PageModel
{
    public void OnGet()
    {
    }
}

Powyższy kod konfiguruje stronę Razor, aby wymagać włączenia funkcji "FeatureX". Jeśli funkcja nie jest włączona, strona generuje wynik HTTP 404 (NotFound).

W przypadku użycia na stronach Razor należy umieścić element FeatureGateAttribute w typie procedury obsługi strony. Nie można go umieścić w poszczególnych metodach obsługi.

Kompilowanie aplikacji

Biblioteka zarządzania funkcjami może służyć do dodawania gałęzi aplikacji i oprogramowania pośredniczącego, które są wykonywane warunkowo na podstawie stanu funkcji.

app.UseMiddlewareForFeature<ThirdPartyMiddleware>("FeatureX");

Po powyższym wywołaniu aplikacja dodaje składnik oprogramowania pośredniczącego, który jest wyświetlany tylko w potoku żądania, jeśli funkcja "FeatureX" jest włączona. Jeśli funkcja jest włączona/wyłączona w czasie wykonywania, potok oprogramowania pośredniczącego można zmienić dynamicznie.

To zwiększa ogólną możliwość rozgałęziania całej aplikacji na podstawie funkcji.

app.UseForFeature(featureName, appBuilder => 
{
    appBuilder.UseMiddleware<T>();
});

Implementowanie filtru funkcji

Tworzenie filtru funkcji umożliwia włączanie funkcji na podstawie zdefiniowanych kryteriów. Aby zaimplementować filtr funkcji, IFeatureFilter należy zaimplementować interfejs. IFeatureFilter ma jedną metodę o nazwie EvaluateAsync. Gdy funkcja określa, że można ją włączyć dla filtru funkcji, wywoływana EvaluateAsync jest metoda . Jeśli EvaluateAsync funkcja zwraca truewartość , oznacza to, że funkcja powinna być włączona.

Poniższy fragment kodu przedstawia sposób dodawania dostosowanego filtru MyCriteriaFilterfunkcji .

services.AddFeatureManagement()
        .AddFeatureFilter<MyCriteriaFilter>();

Filtry funkcji są rejestrowane przez wywołanie AddFeatureFilter<T> metody zwróconej IFeatureManagementBuilder z AddFeatureManagement. Te filtry funkcji mają dostęp do usług, które istnieją w kolekcji usług, która została użyta do dodawania flag funkcji. Wstrzykiwanie zależności może służyć do pobierania tych usług.

Uwaga

Gdy filtry są przywoływane w ustawieniach flagi funkcji (na przykład appsettings.json), część Filtr nazwy typu powinna zostać pominięta. Aby uzyskać więcej informacji, zobacz sekcję Filter Alias Attribute .

Filtry funkcji sparametryzowanych

Niektóre filtry funkcji wymagają parametrów, aby zdecydować, czy funkcja powinna być włączona, czy nie. Na przykład filtr funkcji przeglądarki może włączyć funkcję dla określonego zestawu przeglądarek. Może być pożądane, aby przeglądarki Edge i Chrome włączały funkcję, a Przeglądarka Firefox nie. W tym celu można zaprojektować filtr funkcji, aby oczekiwać parametrów. Te parametry zostaną określone w konfiguracji funkcji, a w kodzie będzie dostępny za pośrednictwem FeatureFilterEvaluationContext parametru IFeatureFilter.EvaluateAsync.

public class FeatureFilterEvaluationContext
{
    /// <summary>
    /// The name of the feature being evaluated.
    /// </summary>
    public string FeatureName { get; set; }

    /// <summary>
    /// The settings provided for the feature filter to use when evaluating whether the feature should be enabled.
    /// </summary>
    public IConfiguration Parameters { get; set; }
}

FeatureFilterEvaluationContext ma właściwość o nazwie Parameters. Te parametry reprezentują konfigurację nieprzetworzonej, której filtr funkcji może użyć, aby zdecydować, jak ocenić, czy funkcja powinna być włączona, czy nie. Aby ponownie użyć filtru funkcji przeglądarki jako przykładu, filtr może użyć Parameters do wyodrębnienia zestawu dozwolonych przeglądarek, które zostaną określone dla tej funkcji, a następnie sprawdź, czy żądanie jest wysyłane z jednej z tych przeglądarek.

[FilterAlias("Browser")]
public class BrowserFilter : IFeatureFilter
{
    …

    public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
    {
        BrowserFilterSettings settings = context.Parameters.Get<BrowserFilterSettings>() ?? new BrowserFilterSettings();

        //
        // Here we would use the settings and see if the request was sent from any of BrowserFilterSettings.AllowedBrowsers
    }
}

Filtruj atrybut aliasu

Po zarejestrowaniu filtru funkcji dla flagi funkcji alias używany w konfiguracji jest nazwą typu filtru funkcji z sufiksem Filtr , jeśli istnieje, usunięty. Na przykład MyCriteriaFilter zostanie określona jako MyCriteria w konfiguracji.

"MyFeature": {
    "EnabledFor": [
        {
            "Name": "MyCriteria"
        }
    ]
}

Można to przesłonić przy użyciu elementu FilterAliasAttribute. Filtr funkcji można dekorować za pomocą tego atrybutu, aby zadeklarować nazwę, która powinna być używana w konfiguracji do odwołowania się do tego filtru funkcji w ramach flagi funkcji.

Brakujące filtry funkcji

Jeśli funkcja jest skonfigurowana do włączenia dla określonego filtru funkcji i ten filtr funkcji nie jest zarejestrowany, podczas oceny funkcji jest zgłaszany wyjątek. Wyjątek można wyłączyć przy użyciu opcji zarządzania funkcjami.

services.Configure<FeatureManagementOptions>(options =>
{
    options.IgnoreMissingFeatureFilters = true;
});

Korzystanie z obiektu HttpContext

Filtry funkcji mogą ocenić, czy funkcja powinna być włączona na podstawie właściwości żądania HTTP. Jest to wykonywane przez sprawdzenie kontekstu HTTP. Filtr funkcji może uzyskać odwołanie do kontekstu HTTP, uzyskując IHttpContextAccessor wstrzyknięcie zależności.

public class BrowserFilter : IFeatureFilter
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public BrowserFilter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
    }
}

Należy dodać element IHttpContextAccessor do kontenera wstrzykiwania zależności podczas uruchamiania, aby był dostępny. Można go zarejestrować w metodzie IServiceCollection przy użyciu następującej metody.

public void ConfigureServices(IServiceCollection services)
{
    …
    services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    …
}

Zaawansowane: IHttpContextAccessor/HttpContext nie należy używać w składnikach Razor aplikacji Blazor po stronie serwera. Zalecaną metodą przekazywania kontekstu http w aplikacjach Platformy Blazor jest skopiowanie danych do usługi o określonym zakresie. W przypadku aplikacji AddScopedFeatureManagement Platformy Blazor należy używać do rejestrowania usług zarządzania funkcjami. Aby uzyskać więcej informacji, zobacz sekcję Scoped Feature Management Services .

Podawanie kontekstu oceny funkcji

W aplikacjach konsolowych nie ma kontekstu otoczenia, takiego jak HttpContext filtry funkcji, które mogą uzyskać i wykorzystać, aby sprawdzić, czy funkcja powinna być włączona lub wyłączona. W takim przypadku aplikacje muszą podać obiekt reprezentujący kontekst w systemie zarządzania funkcjami do użycia przez filtry funkcji. Odbywa się to przy użyciu polecenia IFeatureManager.IsEnabledAsync<TContext>(string featureName, TContext appContext). Obiekt appContext udostępniany menedżerowi funkcji może służyć przez filtry funkcji do oceny stanu funkcji.

MyAppContext context = new MyAppContext
{
    AccountId = current.Id;
}

if (await featureManager.IsEnabledAsync(feature, context))
{
…
}

Filtry funkcji kontekstowych

Filtry funkcji kontekstowych implementują IContextualFeatureFilter<TContext> interfejs. Te specjalne filtry funkcji mogą korzystać z kontekstu przekazywanego, gdy IFeatureManager.IsEnabledAsync<TContext> jest wywoływany. Parametr TContext typu w temacie IContextualFeatureFilter<TContext> opisuje typ kontekstu, który filtr może obsługiwać. Dzięki temu deweloper filtru funkcji kontekstowych może opisać, co jest wymagane dla tych, którzy chcą z niego korzystać. Ponieważ każdy typ jest elementem potomnym obiektu, filtr, który implementuje, może być wywoływany IContextualFeatureFilter<object> dla dowolnego dostarczonego kontekstu. Aby zilustrować przykład bardziej szczegółowego filtru funkcji kontekstowych, należy rozważyć funkcję włączoną, jeśli konto znajduje się na skonfigurowanej liście włączonych kont.

public interface IAccountContext
{
    string AccountId { get; set; }
}

[FilterAlias("AccountId")]
class AccountIdFilter : IContextualFeatureFilter<IAccountContext>
{
    public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext featureEvaluationContext, IAccountContext accountId)
    {
        //
        // Evaluate if the feature should be on with the help of the provided IAccountContext
    }
}

Widzimy, że AccountIdFilter wymagany jest obiekt, który implementuje IAccountContext , aby móc ocenić stan funkcji. W przypadku korzystania z tego filtru funkcji obiekt wywołujący musi upewnić się, że przekazany obiekt implementuje IAccountContextelement .

Uwaga

Tylko jeden interfejs filtru funkcji może być implementowany przez jeden typ. Próba dodania filtru funkcji, który implementuje więcej niż jeden interfejs filtru funkcji, powoduje wyświetlenie elementu ArgumentException.

Używanie kontekstowych i nie kontekstowych filtrów z tym samym aliasem

Filtry elementów IFeatureFilter i IContextualFeatureFilter mogą współużytkować ten sam alias. W szczególności można mieć jeden alias filtru współużytkowany przez 0 lub 1 IFeatureFilter i 0 lub N IContextualFeatureFilter<ContextType>, o ile istnieje co najwyżej jeden odpowiedni filtr dla ContextType.

W poniższym fragmencie opisano proces wybierania filtru, gdy kontekstowe i nie kontekstowe filtry o tej samej nazwie są rejestrowane w aplikacji.

Załóżmy, że masz filtr nie kontekstowy o nazwie FilterA i dwa filtry FilterB kontekstowe i FiltrC, które akceptują TypeB i TypeC konteksty odpowiednio. Wszystkie trzy filtry mają ten sam alias SharedFilterName.

Masz również flagę MyFeature funkcji, która używa filtru SharedFilterName funkcji w jego konfiguracji.

Jeśli wszystkie trzy filtry są zarejestrowane:

  • Podczas wywoływania metody IsEnabledAsync("MyFeature"), FilterA element jest używany do oceny flagi funkcji.
  • Podczas wywoływania metody IsEnabledAsync("MyFeature", kontekstu), jeśli typ kontekstu to TypeB, FilterB jest używany. Jeśli typ kontekstu to TypeC, FilterC jest używany.
  • Podczas wywoływania metody IsEnabledAsync("MyFeature", kontekstu), jeśli typ kontekstu to TypeF, FilterA jest używany.

Wbudowane filtry funkcji

Istnieje kilka filtrów funkcji, które są dostarczane z pakietemMicrosoft.FeatureManagement: PercentageFilter, TimeWindowFilterContextualTargetingFilter i TargetingFilter. Wszystkie filtry, z wyjątkiem TargetingFilter, są dodawane automatycznie , gdy zarządzanie funkcjami jest rejestrowane za pomocą AddFeatureManagement metody. Element TargetingFilter jest dodawany przy użyciu WithTargeting metody, która jest szczegółowa w poniższej Targeting sekcji.

Każdy z wbudowanych filtrów funkcji ma własne parametry. Oto lista filtrów funkcji wraz z przykładami.

Microsoft.Percentage

Ten filtr zapewnia możliwość włączenia funkcji na podstawie ustawionej wartości procentowej.

"EnhancedPipeline": {
    "EnabledFor": [
        {
            "Name": "Microsoft.Percentage",
            "Parameters": {
                "Value": 50
            }
        }
    ]
}

Microsoft.TimeWindow

Ten filtr zapewnia możliwość włączenia funkcji na podstawie przedziału czasu. End Jeśli tylko zostanie określona, funkcja jest rozważana do tego czasu. Start Jeśli tylko zostanie określona, funkcja jest uwzględniana we wszystkich punktach po tym czasie.

"EnhancedPipeline": {
    "EnabledFor": [
        {
            "Name": "Microsoft.TimeWindow",
            "Parameters": {
                "Start": "Wed, 01 May 2019 13:59:59 GMT",
                "End": "Mon, 01 Jul 2019 00:00:00 GMT"
            }
        }
    ]
}

Przedział czasu można skonfigurować do okresowego powtarzania. Może to być przydatne w scenariuszach, w których może być konieczne włączenie funkcji w okresie niskiego lub dużego ruchu w ciągu dnia lub w określonych dniach tygodnia. Aby rozwinąć poszczególne przedziały czasu do okresów cyklicznych, reguła cyklu powinna być określona w parametrze Recurrence .

Uwaga

Start i End muszą być określone, aby włączyć Recurrence.

"EnhancedPipeline": {
    "EnabledFor": [
        {
            "Name": "Microsoft.TimeWindow",
            "Parameters": {
                "Start": "Fri, 22 Mar 2024 20:00:00 GMT",
                "End": "Sat, 23 Mar 2024 02:00:00 GMT",
                "Recurrence": {
                    "Pattern": {
                        "Type": "Daily",
                        "Interval": 1
                    },
                    "Range": {
                        "Type": "NoEnd"
                    }
                }
            }
        }
    ]
}

Ustawienia Recurrence składają się z dwóch części: Pattern (jak często powtarza się przedział czasu) i Range (jak długo powtarza się wzorzec cyklu).

Wzorzec cyklu

Istnieją dwa możliwe typy wzorców cyklu: Daily i Weekly. Na przykład przedział czasu może powtarzać "codziennie", "co trzy dni", "każdy poniedziałek" lub "co drugi piątek".

W zależności od typu niektóre pola Pattern są wymagane, opcjonalne lub ignorowane.

  • Daily

    Wzorzec cyklu dziennego powoduje powtarzanie przedziału czasu na podstawie liczby dni między poszczególnymi wystąpieniami.

    Właściwości Stopień zgodności opis
    Type Wymagania Musi być ustawiona wartość Daily.
    Interwał Opcjonalnie Określa liczbę dni między poszczególnymi wystąpieniami. Wartość domyślna to 1.
  • Weekly

    Wzorzec cyklu tygodniowego powoduje powtórzenie przedziału czasu w tym samym dniu lub dniach tygodnia na podstawie liczby tygodni między poszczególnymi zestawami wystąpień.

    Właściwości Stopień zgodności opis
    Type Wymagania Musi być ustawiona wartość Weekly.
    DaysOfWeek Wymagania Określa dni tygodnia, w których występuje zdarzenie.
    Interwał Opcjonalnie Określa liczbę tygodni między poszczególnymi zestawami wystąpień. Wartość domyślna to 1.
    FirstDayOfWeek Opcjonalnie Określa, który dzień jest uważany za pierwszy dzień tygodnia. Wartość domyślna to Sunday.

    Poniższy przykład powtarza przedział czasu co drugi poniedziałek i wtorek

    "Pattern": {
        "Type": "Weekly",
        "Interval": 2,
        "DaysOfWeek": ["Monday", "Tuesday"]
    }
    

Uwaga

Start musi być prawidłowym pierwszym wystąpieniem, które pasuje do wzorca cyklu. Ponadto czas trwania przedziału czasu nie może być dłuższy niż częstotliwość jego wystąpienia. Na przykład jest nieprawidłowe, aby codziennie powtarzać 25-godzinne okno czasu.

Zakres cyklu

Istnieją trzy możliwe typy zakresów cykli: NoEnd, EndDate i Numbered.

  • NoEnd

    Zakres NoEnd powoduje, że cykl występuje w nieskończoność.

    Właściwości Stopień zgodności opis
    Type Wymagania Musi być ustawiona wartość NoEnd.
  • EndDate

    Zakres EndDate powoduje, że przedział czasu występuje we wszystkich dniach, które pasują do odpowiedniego wzorca do daty zakończenia.

    Właściwości Stopień zgodności opis
    Type Wymagania Musi być ustawiona wartość EndDate.
    EndDate Wymagania Określa datę zakończenia stosowania wzorca. O ile godzina rozpoczęcia ostatniego wystąpienia spadnie przed datą zakończenia, czas zakończenia tego wystąpienia może wykraczać poza nią.

    Poniższy przykład będzie powtarzał przedział czasu każdego dnia do czasu ostatniego wystąpienia 1 kwietnia 2024 r.

    "Start": "Fri, 22 Mar 2024 18:00:00 GMT",
    "End": "Fri, 22 Mar 2024 20:00:00 GMT",
    "Recurrence":{
        "Pattern": {
            "Type": "Daily",
            "Interval": 1
        },
        "Range": {
            "Type": "EndDate",
            "EndDate": "Mon, 1 Apr 2024 20:00:00 GMT"
        }
    }
    
  • Numbered

    Zakres Numbered powoduje, że przedział czasu występuje stałą liczbę razy (na podstawie wzorca).

    Właściwości Stopień zgodności opis
    Type Wymagania Musi być ustawiona wartość Numbered.
    NumberOfOccurrences Wymagania Określa liczbę wystąpień.

    Poniższy przykład powtórzy przedział czasu w poniedziałek i wtorek do trzech wystąpień, które mają miejsce odpowiednio 1 kwietnia (Mon), 2 kwietnia (wt) i 8 kwietnia (Mon).

    "Start": "Mon, 1 Apr 2024 18:00:00 GMT",
    "End": "Mon, 1 Apr 2024 20:00:00 GMT",
    "Recurrence":{
        "Pattern": {
            "Type": "Weekly",
            "Interval": 1,
            "DaysOfWeek": ["Monday", "Tuesday"]
        },
        "Range": {
            "Type": "Numbered",
            "NumberOfOccurrences": 3
        }
    }
    

Aby utworzyć regułę cyklu, należy określić wartości i Pattern Range. Dowolny typ wzorca może pracować z dowolnym typem zakresu.

Zaawansowane: przesunięcie strefy czasowej Start właściwości jest stosowane do ustawień cyklu.

Microsoft.Targeting

Ten filtr zapewnia możliwość włączenia funkcji dla odbiorców docelowych. Szczegółowe wyjaśnienie określania wartości docelowej zostało wyjaśnione w poniższej sekcji określania wartości docelowej . Parametry filtru obejmują obiekt opisujący Audience użytkowników, grupy, wykluczonych użytkowników/grup oraz domyślny procent bazy użytkowników, który powinien mieć dostęp do funkcji. Każdy obiekt grupy wymieniony w Groups sekcji musi również określić, jaki procent członków grupy powinien mieć dostęp. Jeśli użytkownik jest określony w Exclusion sekcji , bezpośrednio lub jeśli użytkownik znajduje się w wykluczonej grupie, funkcja jest wyłączona. W przeciwnym razie, jeśli użytkownik jest określony bezpośrednio w Users sekcji lub jeśli użytkownik znajduje się w uwzględnionych procentach dowolnego wdrożenia grupy, lub jeśli użytkownik mieści się w domyślnym procentu wdrożenia, ten użytkownik będzie miał włączoną funkcję.

"EnhancedPipeline": {
    "EnabledFor": [
        {
            "Name": "Microsoft.Targeting",
            "Parameters": {
                "Audience": {
                    "Users": [
                        "Jeff",
                        "Alicia"
                    ],
                    "Groups": [
                        {
                            "Name": "Ring0",
                            "RolloutPercentage": 100
                        },
                        {
                            "Name": "Ring1",
                            "RolloutPercentage": 50
                        }
                    ],
                    "DefaultRolloutPercentage": 20,
                    "Exclusion": {
                        "Users": [
                            "Ross"
                        ],
                        "Groups": [
                            "Ring2"
                        ]
                    }
                }
            }
        }
    ]
}

Przestrzenie nazw aliasu filtru funkcji

Wszystkie wbudowane aliasy filtru funkcji znajdują się w Microsoft przestrzeni nazw filtru funkcji. Zapobiega to konfliktom z innymi filtrami funkcji, które mogą współużytkować ten sam alias. Segmenty przestrzeni nazw filtru funkcji są dzielone przez znak "". Filtr funkcji można odwoływać się do jego w pełni kwalifikowanego aliasu, takiego jak Microsoft.Percentage lub ostatniego segmentu Microsoft.Percentage , który w przypadku elementu to Percentage.

Określanie celu

Określanie wartości docelowej to strategia zarządzania funkcjami, która umożliwia deweloperom stopniowe wdrażanie nowych funkcji w bazie użytkowników. Strategia jest oparta na koncepcji określania celu grupy użytkowników znanej jako docelowa grupa odbiorców. Grupa odbiorców składa się z określonych użytkowników, grup, wykluczonych użytkowników/grup oraz wyznaczonego procentu całej bazy użytkowników. Grupy, które są uwzględnione w grupie odbiorców, można podzielić dalej na wartości procentowe ich całkowitej liczby członków.

W poniższych krokach przedstawiono przykład progresywnego wdrożenia nowej funkcji "Beta":

  1. Indywidualni użytkownicy Jeff i Alicia otrzymują dostęp do wersji beta
  2. Inny użytkownik, Mark, prosi o wyrażenie zgody i jest uwzględniony.
  3. Dwadzieścia procent grupy znanej jako "Ring1" użytkowników jest uwzględnionych w wersji beta.
  4. Liczba użytkowników "Ring1" uwzględnionych w wersji beta wzrosła do 100 procent.
  5. Pięć procent bazy użytkowników jest uwzględnionych w wersji beta.
  6. Procent wdrożenia jest wyprzedzony do 100 procent, a funkcja jest całkowicie wdrażana.

Ta strategia wdrażania funkcji jest wbudowana w bibliotekę za pomocą dołączonego filtru funkcji Microsoft.Targeting .

Określanie wartości docelowej w aplikacji internetowej

Przykładowa aplikacja internetowa korzystająca z filtru funkcji określania wartości docelowej jest dostępna w przykładowym projekcie FeatureFlagDemo .

Aby rozpocząć korzystanie z TargetingFilter elementu w aplikacji, należy dodać go do kolekcji usług aplikacji tak samo jak każdy inny filtr funkcji. W przeciwieństwie do innych wbudowanych filtrów funkcja TargetingFilter opiera się na innej usłudze, która ma zostać dodana do kolekcji usług aplikacji. Ta usługa jest usługą ITargetingContextAccessor.

Microsoft.FeatureManagement.AspNetCoreUdostępnia domyślną implementację ITargetingContextAccessor, z której będą wyodrębniać informacje dotyczące określania HttpContextwartości docelowej z żądania . Domyślne metody określania kontekstu określania wartości docelowej można użyć podczas konfigurowania określania wartości docelowej przy użyciu przeciążenia niegenerycznego WithTargeting w obiekcie IFeatureManagementBuilder.

Domyślna metoda dostępu kontekstu określania wartości docelowej i TargetingFilter jest rejestrowana przez wywołanie WithTargeting metody IFeatureManagementBuilder.

services.AddFeatureManagement()
        .WithTargeting();

Możesz również zarejestrować niestandardową implementację dla ITargetingContextAccessor elementu i TargetingFilter przez wywołanie metody WithTargeting<T>. Oto przykład konfigurowania zarządzania funkcjami w aplikacji internetowej do użycia z TargetingFilter implementacją ITargetingContextAccessor o nazwie ExampleTargetingContextAccessor.

services.AddFeatureManagement()
        .WithTargeting<ExampleTargetingContextAccessor>();

ITargetingContextAccessor

Aby można było używać TargetingFilter elementu w aplikacji internetowej, wymagana jest implementacja ITargetingContextAccessor . Dzieje się tak dlatego, że w przypadku przeprowadzenia oceny docelowej potrzebne są informacje kontekstowe, takie jak aktualnie oceniany użytkownik. Te informacje są nazywane .TargetingContext Różne aplikacje mogą wyodrębniać te informacje z różnych miejsc. Niektóre typowe przykłady, w których aplikacja może ściągać kontekst określania wartości docelowej, to kontekst HTTP żądania lub baza danych.

Przykład wyodrębniania informacji kontekstowych z kontekstu HTTP aplikacji jest DefaultHttpTargetingContextAccessor dostarczany przez Microsoft.FeatureManagement.AspNetCore pakiet. Spowoduje to wyodrębnienie informacji o określaniu wartości docelowej z elementu HttpContext.User. UserId informacje zostaną wyodrębnione z Identity.Name pola, a Groups informacje zostaną wyodrębnione z oświadczeń typu Role. Ta implementacja opiera się na użyciu IHttpContextAccessorelementu , który został omówiony tutaj.

Określanie wartości docelowej w aplikacji konsolowej

Filtr określania wartości docelowej opiera się na kontekście określania wartości docelowej, aby ocenić, czy funkcja powinna być włączona. Ten kontekst określania wartości docelowej zawiera informacje, takie jak aktualnie oceniany użytkownik i grupy użytkowników. W aplikacjach konsoli zwykle nie ma dostępnego kontekstu otoczenia, aby przekazać te informacje do filtru określania wartości docelowej, dlatego należy przekazać je bezpośrednio po FeatureManager.IsEnabledAsync wywołaniu. Jest to obsługiwane przy użyciu elementu ContextualTargetingFilter. Aplikacje, które muszą umieścić kontekst docelowy w menedżerze funkcji, powinny używać tego elementu zamiast TargetingFilter.

Ponieważ ContextualTargetingFilter element jest elementem IContextualTargetingFilter<ITargetingContext>, należy przekazać do niej implementację ITargetingContext , aby IFeatureManager.IsEnabledAsync można było ocenić i włączyć funkcję.

IFeatureManager fm;
…
// userId and groups defined somewhere earlier in application
TargetingContext targetingContext = new TargetingContext
{
   UserId = userId,
   Groups = groups
};

await fm.IsEnabledAsync(featureName, targetingContext);

Nadal ContextualTargetingFilter używa aliasu filtru funkcji Microsoft.Targeting, więc konfiguracja tego filtru jest zgodna z tym, co zostało wymienione w tej sekcji.

Przykład użycia ContextualTargetingFilter elementu w aplikacji konsolowej jest dostępny w przykładowym projekcie TargetConsoleApp .

Opcje oceny określania wartości docelowej

Dostępne są opcje dostosowywania sposobu oceny określania wartości docelowej we wszystkich funkcjach. Te opcje można skonfigurować podczas konfigurowania zarządzania funkcjami.

services.Configure<TargetingEvaluationOptions>(options =>
{
    options.IgnoreCase = true;
});

Wykluczanie określania wartości docelowej

Podczas definiowania grupy odbiorców można wykluczyć użytkowników i grupy z odbiorców. Jest to przydatne, gdy funkcja jest wdrażana w grupie użytkowników, ale kilka użytkowników lub grup musi zostać wykluczonych z wdrożenia. Wykluczenie jest definiowane przez dodanie listy użytkowników i grup do Exclusion właściwości odbiorców.

"Audience": {
    "Users": [
        "Jeff",
        "Alicia"
    ],
    "Groups": [
        {
            "Name": "Ring0",
            "RolloutPercentage": 100
        }
    ],
    "DefaultRolloutPercentage": 0
    "Exclusion": {
        "Users": [
            "Mark"
        ]
    }
}

W powyższym przykładzie funkcja jest włączona dla użytkowników o nazwach Jeff i Alicia. Jest ona również włączona dla użytkowników w grupie o nazwie Ring0. Jeśli jednak użytkownik ma nazwę Mark, funkcja jest wyłączona, niezależnie od tego, czy znajdują się w grupie Ring0 , czy nie. Wykluczenia mają priorytet nad resztą filtru określania wartości docelowej.

Warianty

Po dodaniu nowych funkcji do aplikacji może dojść do czasu, gdy funkcja ma wiele różnych proponowanych opcji projektowania. Typowym rozwiązaniem do podejmowania decyzji o projekcie jest pewna forma testowania A/B, która polega na udostępnieniu innej wersji funkcji różnym segmentom bazy użytkowników i wybraniu wersji na podstawie interakcji użytkownika. W tej bibliotece ta funkcja jest włączona przez reprezentowanie różnych konfiguracji funkcji z wariantami.

Warianty umożliwiają flagę funkcji stać się bardziej niż prostą flagą włączania/wyłączania. Wariant reprezentuje wartość flagi funkcji, która może być ciągiem, liczbą, wartością logiczną, a nawet obiektem konfiguracji. Flaga funkcji, która deklaruje warianty, powinna określać, w jakich okolicznościach należy używać każdego wariantu, co zostało szczegółowo omówione w sekcji Przydzielanie wariantów .

public class Variant
{
    /// <summary>
    /// The name of the variant.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// The configuration of the variant.
    /// </summary>
    public IConfigurationSection Configuration { get; set; }
}

Pobieranie wariantów

Dla każdej funkcji można pobrać wariant przy użyciu IVariantFeatureManagermetody "s GetVariantAsync ".

…
IVariantFeatureManager featureManager;
…
Variant variant = await featureManager.GetVariantAsync(MyFeatureFlags.FeatureU, CancellationToken.None);

IConfigurationSection variantConfiguration = variant.Configuration;

// Do something with the resulting variant and its configuration

Po pobraniu wariantu można użyć konfiguracji wariantu bezpośrednio jako IConfigurationSection właściwości wariantu Configuration . Inną opcją jest powiązanie konfiguracji z obiektem przy użyciu polecenia . Wzorzec powiązania konfiguracji platformy NET.

IConfigurationSection variantConfiguration = variant.Configuration;

MyFeatureSettings settings = new MyFeatureSettings();

variantConfiguration.Bind(settings);

Zwrócony wariant jest zależny od aktualnie ocenianego użytkownika, a informacje te są uzyskiwane z wystąpienia klasy TargetingContext. Ten kontekst można przekazać podczas wywoływania GetVariantAsync lub można go automatycznie pobrać z implementacji ITargetingContextAccessor , jeśli jest zarejestrowany.

Deklaracja flagi funkcji wariantu

W porównaniu z flagami funkcji normalnych flagi funkcji wariantu mają dwie dodatkowe właściwości: variants i allocation. Właściwość variants jest tablicą zawierającą warianty zdefiniowane dla tej funkcji. Właściwość allocation definiuje sposób przydzielania tych wariantów dla funkcji. Podobnie jak deklarowanie flag funkcji normalnych, można skonfigurować flagi funkcji wariantu w pliku json. Oto przykład flagi funkcji wariantu.

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyVariantFeatureFlag",
                "enabled": true,
                "allocation": {
                    "default_when_enabled": "Small",
                    "group": [
                        {
                            "variant": "Big",
                            "groups": [
                                "Ring1"
                            ]
                        }
                    ]
                },
                "variants": [
                    { 
                        "name": "Big"
                    },  
                    { 
                        "name": "Small"
                    } 
                ]
            }
        ]
    }
}

Definiowanie wariantów

Każdy wariant ma dwie właściwości: nazwę i konfigurację. Nazwa jest używana do odwoływania się do określonego wariantu, a konfiguracja jest wartością tego wariantu. Konfigurację można ustawić przy użyciu configuration_value właściwości . configuration_value jest konfiguracją śródliniową, która może być ciągiem, liczbą, wartością logiczną lub obiektem konfiguracji. Jeśli configuration_value nie zostanie określony, zwrócona właściwość wariantu Configuration będzie mieć wartość null.

Lista wszystkich możliwych wariantów jest zdefiniowana dla każdej funkcji w variants ramach właściwości .

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyVariantFeatureFlag",
                "variants": [
                    { 
                        "name": "Big", 
                        "configuration_value": {
                            "Size": 500
                        }
                    },  
                    { 
                        "name": "Small", 
                        "configuration_value": {
                            "Size": 300
                        }
                    } 
                ]
            }
        ]
    }
}

Przydzielanie wariantów

Proces przydzielania wariantów funkcji zależy od allocation właściwości funkcji.

"allocation": { 
    "default_when_enabled": "Small", 
    "default_when_disabled": "Small",  
    "user": [ 
        { 
            "variant": "Big", 
            "users": [ 
                "Marsha" 
            ] 
        } 
    ], 
    "group": [ 
        { 
            "variant": "Big", 
            "groups": [ 
                "Ring1" 
            ] 
        } 
    ],
    "percentile": [ 
        { 
            "variant": "Big", 
            "from": 0, 
            "to": 10 
        } 
    ], 
    "seed": "13973240" 
},
"variants": [
    { 
        "name": "Big", 
        "configuration_value": "500px"
    },  
    { 
        "name": "Small", 
        "configuration_value": "300px"
    } 
]

Ustawienie allocation funkcji ma następujące właściwości:

Właściwości opis
default_when_disabled Określa, który wariant ma być używany, gdy jest wymagany wariant, gdy funkcja jest uznawana za wyłączoną.
default_when_enabled Określa, który wariant ma być używany, gdy jest wymagany wariant, gdy funkcja jest uznawana za włączoną i żaden inny wariant nie został przypisany do użytkownika.
user Określa wariant i listę użytkowników, do których należy przypisać ten wariant.
group Określa wariant i listę grup. Wariant zostanie przypisany, jeśli użytkownik znajduje się w co najmniej jednej grupie.
percentile Określa wariant i zakres procentowy, do którego ma zostać przypisana wartość procentowa obliczona przez użytkownika.
seed Wartość, na podstawie której są obliczane percentile wartości procentowe. Obliczanie procentowe dla określonego użytkownika będzie takie samo we wszystkich funkcjach, jeśli jest używana ta sama seed wartość. Jeśli nie seed zostanie określony, zostanie utworzony domyślny inicjator na podstawie nazwy funkcji.

W powyższym przykładzie, jeśli funkcja nie jest włączona, menedżer funkcji przypisze wariant oznaczony jako default_when_disabled do bieżącego użytkownika, który jest Small w tym przypadku.

Jeśli funkcja jest włączona, menedżer funkcji sprawdzi userw tym celu alokacje , groupi percentile w celu przypisania wariantu. W tym konkretnym przykładzie, jeśli oceniany użytkownik ma nazwę Marsha, w grupie o nazwie Ring1lub użytkownik może spaść między 0 a 10. percentylem, określony wariant zostanie przypisany do użytkownika. W takim przypadku wszystkie te elementy zwróciłyby Big wariant. Jeśli żadna z tych alokacji nie jest zgodna default_when_enabled , użytkownik ma przypisany wariant , czyli Small.

Logika alokacji jest podobna do filtru funkcji Microsoft.Targeting, ale istnieją pewne parametry, które znajdują się w określaniu wartości docelowej, które nie znajdują się w alokacji i na odwrót. Wyniki określania wartości docelowej i alokacji nie są powiązane.

Uwaga

Aby zezwolić na przydzielanie wariantów funkcji, należy zarejestrować element ITargetingContextAccessor. Można to zrobić, wywołując metodę WithTargeting<T> .

Zastępowanie stanu włączonego z wariantem

Można użyć wariantów, aby zastąpić włączony stan flagi funkcji. Daje to wariantom możliwość rozszerzenia oceny flagi funkcji. Jeśli obiekt wywołujący sprawdza, czy flaga zawierająca warianty jest włączona, menedżer funkcji sprawdzi, czy wariant przypisany do bieżącego użytkownika został skonfigurowany w celu zastąpienia wyniku. Odbywa się to przy użyciu opcjonalnej właściwości status_overridewariantu . Domyślnie ta właściwość jest ustawiona na None, co oznacza, że wariant nie ma wpływu na to, czy flaga jest uznawana za włączoną, czy wyłączoną. Ustawienie status_override zezwala na Enabled włączenie wariantu, po wybraniu, przesłonięcia flagi. Ustawienie status_override na Disabled wartość zapewnia przeciwną funkcjonalność, dlatego wyłączenie flagi po wybraniu wariantu. Nie można zastąpić funkcji ze stanem enabled false .

Jeśli używasz flagi funkcji z wariantami binarnymi, status_override właściwość może być bardzo pomocna. Umożliwia to kontynuowanie korzystania z interfejsów API, takich jak IsEnabledAsync i FeatureGateAttribute w aplikacji, a jednocześnie korzystanie z nowych funkcji, które są dostępne z wariantami, takimi jak alokacja percentylu i inicjowanie.

{
    "id": "MyVariantFeatureFlag",
    "enabled": true,
    "allocation": {
        "percentile": [
            {
                "variant": "On",
                "from": 10,
                "to": 20
            }
        ],
        "default_when_enabled":  "Off",
        "seed": "Enhanced-Feature-Group"
    },
    "variants": [
        {
            "name": "On"
        },
        {
            "name": "Off",
            "status_override": "Disabled"
        }
    ]
}

W powyższym przykładzie funkcja jest zawsze włączona. Jeśli bieżący użytkownik znajduje się w obliczonym zakresie percentylu od 10 do 20, On zwracany jest wariant. Off W przeciwnym razie zwracany jest wariant i ponieważ status_override jest równy Disabled, funkcja zostanie teraz uznana za wyłączoną.

Warianty iniekcji zależności

Flagi funkcji wariantu mogą być używane w połączeniu z iniekcją zależności, aby wyświetlić różne implementacje usługi dla różnych użytkowników. Jest to realizowane przy użyciu interfejsu IVariantServiceProvider<TService> .

IVariantServiceProvider<IAlgorithm> algorithmServiceProvider;
...

IAlgorithm forecastAlgorithm = await algorithmServiceProvider.GetServiceAsync(cancellationToken); 

W powyższym IVariantServiceProvider<IAlgorithm> fragmencie kodu pobiera implementację IAlgorithm z kontenera wstrzykiwania zależności. Wybrana implementacja jest zależna od:

  • Flaga funkcji zarejestrowana w IAlgorithm usłudze.
  • Przydzielony wariant dla tej funkcji.

Element IVariantServiceProvider<T> jest udostępniany aplikacji przez wywołanie metody IFeatureManagementBuilder.WithVariantService<T>(string featureName). Zobacz przykład poniżej.

services.AddFeatureManagement() 
        .WithVariantService<IAlgorithm>("ForecastAlgorithm");

Powyższe wywołanie udostępnia IVariantServiceProvider<IAlgorithm> w kolekcji usług. Implementacje IAlgorithm programu muszą być dodawane oddzielnie za pomocą metody add, takiej jak services.AddSingleton<IAlgorithm, SomeImplementation>(). Implementacja IAlgorithm tej IVariantServiceProvider funkcji zależy od flagi funkcji wariantu ForecastAlgorithm . Jeśli do kolekcji usług nie zostanie dodana żadna IAlgorithm implementacja, IVariantServiceProvider<IAlgorithm>.GetServiceAsync() funkcja zwraca zadanie z wynikiem null .

{
    // The example variant feature flag
    "id": "ForecastAlgorithm",
    "enabled": true,
    "variants": [
        { 
            "Name": "AlgorithmBeta" 
        },
        ...
    ] 
}

Atrybut aliasu usługi wariantu

[VariantServiceAlias("Beta")]
public class AlgorithmBeta : IAlgorithm
{
    ...
}

Dostawca usług wariantu będzie używać nazw typów implementacji do dopasowania przydzielonego wariantu. Jeśli usługa wariantu jest ozdobiona wartością , nazwa zadeklarowana w tym atrybucie VariantServiceAliasAttributepowinna być używana w konfiguracji do odwołowania się do tej usługi wariantu.

Telemetria

Po wdrożeniu zmiany flagi funkcji często ważne jest analizowanie jej wpływu na aplikację. Oto na przykład kilka pytań, które mogą wystąpić:

  • Czy moje flagi są włączone/wyłączone zgodnie z oczekiwaniami?
  • Czy docelowi użytkownicy uzyskują dostęp do określonej funkcji zgodnie z oczekiwaniami?
  • Który wariant jest widoczny dla określonego użytkownika?

Odpowiedzi na te typy pytań można uzyskać za pośrednictwem emisji i analizy zdarzeń oceny flag funkcji. Ta biblioteka używa interfejsu System.Diagnostics.Activity API do tworzenia danych telemetrycznych śledzenia podczas oceny flagi funkcji.

Włączanie telemetrii

Domyślnie flagi funkcji nie mają emitowanych danych telemetrycznych. Aby opublikować dane telemetryczne dla danej flagi funkcji, flaga MUSI zadeklarować , że jest włączona dla emisji telemetrii.

W przypadku flag funkcji zdefiniowanych w appsettings.jsonprogramie jest to wykonywane przy użyciu telemetry właściwości .

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyFeatureFlag",
                "enabled": true,
                "telemetry": {
                    "enabled": true
                }
            }
        ]
    }
}

Powyższy fragment kodu appsettings definiuje flagę funkcji o nazwie MyFeatureFlag , która jest włączona dla telemetrii. Jest to wskazywane przez telemetry obiekt, który ustawia wartość enabled true. Wartość enabled właściwości musi być true publikowania danych telemetrycznych dla flagi.

Sekcja telemetry flagi funkcji ma następujące właściwości:

Właściwości opis
enabled Określa, czy dane telemetryczne mają być publikowane dla flagi funkcji.
metadata Kolekcja par klucz-wartość, modelowana jako słownik, która może służyć do dołączania niestandardowych metadanych dotyczących flagi funkcji do zdarzeń oceny.

Publikowanie niestandardowych danych telemetrycznych

Menedżer funkcji ma własną ActivitySource nazwę "Microsoft.FeatureManagement". Jeśli telemetry flaga funkcji jest włączona, za każdym razem, gdy zostanie uruchomiona ocena flagi funkcji, menedżer funkcji uruchomi element Activity. Po zakończeniu oceny flagi funkcji menedżer funkcji doda ActivityEvent nazwę "FeatureFlag" do bieżącego działania. Zdarzenie "FeatureFlag" będzie zawierać tagi zawierające informacje o ocenie flagi funkcji. W szczególności tagi będą zawierać następujące pola:

Tag opis
FeatureName Nazwa flagi funkcji.
Enabled Czy flaga funkcji jest oceniana jako włączona.
Variant Przypisany wariant.
VariantAssignmentReason Przyczyna przypisania wariantu.
TargetingId Identyfikator użytkownika używany do określania wartości docelowej.

Uwaga

Wszystkie pary wartości klucza określone w telemetry.metadata flagi funkcji zostaną również uwzględnione w tagach.

Aby włączyć publikowanie niestandardowych danych telemetrycznych, możesz utworzyć ActivityListener źródło działań i nasłuchiwać go Microsoft.FeatureManagement . Oto przykład pokazujący, jak nasłuchiwać źródła działań zarządzania funkcjami i dodawać wywołanie zwrotne po ocenie funkcji.

ActivitySource.AddActivityListener(new ActivityListener()
{
    ShouldListenTo = (activitySource) => activitySource.Name == "Microsoft.FeatureManagement",
    Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllData,
    ActivityStopped = (activity) =>
    {
        ActivityEvent? evaluationEvent = activity.Events.FirstOrDefault((activityEvent) => activityEvent.Name == "FeatureFlag");

        if (evaluationEvent.HasValue && evaluationEvent.Value.Tags.Any())
        {
            // Do something.
        }
    }
});

Aby uzyskać więcej informacji, zobacz Zbieranie rozproszonego śledzenia.

Wydawca telemetrii usługi Application Insights

Pakiet Microsoft.FeatureManagement.Telemetry.ApplicationInsights udostępnia wbudowanego wydawcę telemetrii, który wysyła dane oceny flag funkcji do usługi Application Insights. Aby skorzystać z tego celu, dodaj odwołanie do pakietu i zarejestruj wydawcę telemetrii usługi Application Insights, jak pokazano poniżej.

builder.services
    .AddFeatureManagement()
    .AddApplicationInsightsTelemetryPublisher();

Pakiet Microsoft.FeatureManagement.Telemetry.ApplicationInsights udostępnia inicjator telemetrii, który automatycznie taguje wszystkie zdarzenia za pomocą TargetingId polecenia , aby zdarzenia mogły być połączone z ocenami flag. Aby użyć inicjatora telemetrii, TargetingTelemetryInitializerdodaj go do kolekcji usług aplikacji.

builder.Services.AddSingleton<ITelemetryInitializer, TargetingTelemetryInitializer>();

Uwaga

Aby upewnić się, że TargetingTelemetryInitializer działa zgodnie z oczekiwaniami, należy użyć opisanego TargetingHttpContextMiddleware poniżej.

Aby włączyć trwałość kontekstu określania wartości docelowej w bieżącym działaniu, możesz użyć elementu TargetingHttpContextMiddleware.

app.UseMiddleware<TargetingHttpContextMiddleware>();

Przykład użycia można znaleźć w przykładzie EvaluationDataToApplicationInsights .

Warunek wstępny

Ten wydawca danych telemetrycznych zależy od tego, czy usługa Application Insights jest już skonfigurowana i zarejestrowana jako usługa aplikacji. Można to zrobić na przykład w przykładowej aplikacji.

Buforowanie

Stan funkcji jest dostarczany przez IConfiguration system. Wszelkie buforowanie i dynamiczne aktualizowanie powinny być obsługiwane przez dostawców konfiguracji. Menedżer funkcji prosi o IConfiguration najnowszą wartość stanu funkcji za każdym razem, gdy zostanie sprawdzona opcja włączenia funkcji.

Snapshot

Istnieją scenariusze, które wymagają, aby stan funkcji pozostał spójny w okresie istnienia żądania. Wartości zwrócone ze standardu IFeatureManager mogą ulec zmianie, jeśli IConfiguration źródło, z którego jest pobierane, zostanie zaktualizowane podczas żądania. Można temu zapobiec za pomocą polecenia IFeatureManagerSnapshot. IFeatureManagerSnapshot można pobrać w taki sam sposób, jak IFeatureManager. IFeatureManagerSnapshot implementuje interfejs IFeatureManagerelementu , ale buforuje pierwszy oceniany stan funkcji podczas żądania i zwraca ten sam stan funkcji w okresie jego istnienia.

Dostawcy funkcji niestandardowych

Implementowanie niestandardowego dostawcy funkcji umożliwia deweloperom ściąganie flag funkcji ze źródeł, takich jak baza danych lub usługa zarządzania funkcjami. Dołączony dostawca funkcji, który jest używany domyślnie ściąga flagi funkcji z systemu konfiguracji platformy .NET Core. Umożliwia to zdefiniowanie funkcji w pliku appsettings.json lub u dostawców konfiguracji, takich jak aplikacja systemu Azure Configuration. To zachowanie można zastąpić, aby zapewnić pełną kontrolę nad tym, skąd są odczytywane definicje funkcji.

Aby dostosować ładowanie definicji funkcji, należy zaimplementować IFeatureDefinitionProvider interfejs.

public interface IFeatureDefinitionProvider
{
    Task<FeatureDefinition> GetFeatureDefinitionAsync(string featureName);

    IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync();
}

Aby można było użyć implementacji IFeatureDefinitionProviderprogramu , należy ją dodać do kolekcji usług przed dodaniem zarządzania funkcjami. Poniższy przykład dodaje implementację IFeatureDefinitionProvider o nazwie InMemoryFeatureDefinitionProvider.

services.AddSingleton<IFeatureDefinitionProvider, InMemoryFeatureDefinitionProvider>()
        .AddFeatureManagement()

Następne kroki

Aby dowiedzieć się, jak używać flag funkcji w aplikacjach, przejdź do następujących przewodników Szybki start.

Aby dowiedzieć się, jak używać filtrów funkcji, przejdź do następujących samouczków.

Aby dowiedzieć się, jak uruchamiać eksperymenty z flagami funkcji wariantu, przejdź do następującego samouczka.