Gestion des fonctionnalités .NET

Microsoft.FeatureManagement
Microsoft.FeatureManagement.AspNetCore

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

La bibliothèque de gestion des fonctionnalités .NET permet de développer et d’exposer les fonctionnalités d’application en fonction des indicateurs de fonctionnalité. Une fois qu’une nouvelle fonctionnalité est développée, de nombreuses applications ont des exigences particulières, par exemple quand la fonctionnalité doit être activée et dans quelles conditions. Cette bibliothèque fournit un moyen de définir ces relations et s’intègre également aux modèles de code .NET courants pour rendre l’exposition de ces fonctionnalités possible.

Les indicateurs de fonctionnalité permettent aux applications .NET et ASP.NET Core d’activer ou de désactiver dynamiquement les fonctionnalités. Les développeurs peuvent utiliser des indicateurs de fonctionnalité dans des cas d’usage simples, tels que des instructions conditionnelles, comme dans des scénarios plus avancés, comme l’ajout conditionnel d’itinéraires ou de filtres MVC. Les indicateurs de fonctionnalité sont basés sur le système de configuration .NET Core. N’importe quel fournisseur de configuration .NET Core est capable d’agir en tant qu’infrastructure principale pour les indicateurs de fonctionnalité.

Voici quelques-uns des avantages de l’utilisation de la bibliothèque de gestion des fonctionnalités .NET :

  • Une convention commune pour la gestion des fonctionnalités

  • Une prise en main rapide

    • Basé sur IConfiguration
    • Prend en charge la configuration de l’indicateur de fonctionnalité de fichier JSON
  • Gestion de la durée de vie des indicateurs de fonctionnalité

    • Les valeurs de configuration peuvent changer en temps réel ; les indicateurs de fonctionnalité peuvent être cohérents dans l’ensemble de la requête
  • Scénarios simples à complexes couverts

    • Activation/désactivation des fonctionnalités via le fichier de configuration déclaratif
    • Évaluation dynamique de l’état de la fonctionnalité en fonction de l’appel au serveur
  • Extensions d’API pour l’infrastructure ASP.NET Core et MVC

    • Routage
    • Filtres
    • Attributs d’action

    La bibliothèque de gestion des fonctionnalités .NET est open source. Pour plus d’informations, visitez le dépôt GitHub.

Indicateurs de fonctionnalité

Les indicateurs de fonctionnalité sont composés de deux parties : un nom et une liste de filtres de fonctionnalités utilisés pour activer la fonctionnalité.

Filtres de fonctionnalités

Les filtres de fonctionnalités définissent un scénario pour lequel une fonctionnalité doit être activée. Lorsque l’activation ou la désactivation d’une fonctionnalité est évaluée, sa liste de filtres de fonctionnalités est parcourue jusqu’à ce qu’un des filtres décide que la fonctionnalité doit être activée. À ce stade, la fonctionnalité est considérée comme activée et le parcours des filtres de fonctionnalités s’arrête. Si aucun filtre de fonctionnalités n’indique que la fonctionnalité doit être activée, elle est considérée comme désactivée.

Par exemple, un filtre de fonctionnalités de navigateur Microsoft Edge peut être conçu. Ce filtre de fonctionnalités active toutes les fonctionnalités auxquelles il est attaché tant qu’une requête HTTP provient de Microsoft Edge.

Configuration des indicateurs de fonctionnalité

Le système de configuration .NET Core est utilisé pour déterminer l’état des indicateurs de fonctionnalité. La base de ce système est IConfiguration. N’importe quel fournisseur pour IConfiguration peut être utilisé comme fournisseur d’état de la fonctionnalité pour la bibliothèque d’indicateurs de fonctionnalité. Ce système permet des scénarios allant d’appsettings.json à Azure App Configuration et bien plus encore.

Déclaration des indicateurs de fonctionnalité

La bibliothèque de gestion des fonctionnalités prend en charge appsettings.json en tant que source d’indicateur de fonctionnalité, car il s’agit d’un fournisseur pour le système IConfiguration de .NET Core. Vous trouverez ci-dessous un exemple de format utilisé pour configurer des indicateurs de fonctionnalité dans un fichier 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"
                    }
                }
            ]
        }
    }
}

La section FeatureManagement du document JSON est utilisée par convention pour charger les paramètres des indicateurs de fonctionnalité. Dans la section ci-dessus, nous voyons trois fonctionnalités différentes. Les fonctionnalités définissent leurs filtres de fonctionnalités à l’aide de la propriété EnabledFor. Dans les filtres de fonctionnalités pour FeatureT, nous voyons AlwaysOn. Ce filtre de fonctionnalités est intégré et active toujours la fonctionnalité lorsqu’il est spécifié. Le filtre de fonctionnalités AlwaysOn ne nécessite aucune configuration. Il possède donc uniquement la propriété Name. FeatureU n’a aucun filtre dans sa propriété EnabledFor et ne sera donc jamais activé. Toutes les fonctionnalités qui s’appuient sur l’activation de cette fonctionnalité ne seront pas accessibles tant que les filtres de fonctionnalités restent vides. Toutefois, dès qu’un filtre de fonctionnalités est ajouté pour activer la fonctionnalité, celle-ci peut commencer à fonctionner. FeatureV spécifie un filtre de fonctionnalités nommé TimeWindow. Il s’agit d’un exemple de filtre de fonctionnalités configurable. Nous pouvons voir dans l’exemple que le filtre a une propriété Parameters. Elle est utilisée pour configurer le filtre. Dans ce cas, les heures de début et de fin d’activation de la fonctionnalité sont configurées.

Le schéma détaillé de la section FeatureManagement est disponible ici.

Avancé : l’utilisation du signe deux-points (:) est interdite dans les noms d’indicateurs de fonctionnalité.

Déclaration d’activation/désactivation

L’extrait de code suivant illustre une autre façon de définir une fonctionnalité qui peut être utilisée pour l’activation/désactivation des fonctionnalités.

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

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

RequirementType

La propriété RequirementType d’un indicateur de fonctionnalité sert à déterminer si les filtres doivent utiliser la logique Any ou All lors de l’évaluation de l’état d’une fonctionnalité. Si RequirementType n’est pas spécifié, la valeur par défaut est Any.

  • Any signifie qu’un seul filtre doit être évalué sur true pour que la fonctionnalité soit activée.
  • All signifie que tous les filtres doivent être évalués sur true pour que la fonctionnalité soit activée.

Un RequirementType de All modifie le parcours. Tout d’abord, s’il n’existe aucun filtre, la fonctionnalité est désactivée. Ensuite, les filtres de fonctionnalités sont parcourus jusqu’à ce que l’un des filtres décide que la fonctionnalité doit être désactivée. Si aucun filtre n’indique que la fonctionnalité doit être désactivée, elle est considérée comme activée.

"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"
            }
        }
    ]
}

Dans l’exemple ci-dessus, FeatureW spécifie un RequirementType de All, ce qui signifie que tous ses filtres doivent être évalués sur true pour que la fonctionnalité soit activée. Dans ce cas, la fonctionnalité est activée pour 50 % des utilisateurs pendant la fenêtre de temps spécifiée.

Schéma de gestion des fonctionnalités Microsoft

La bibliothèque de gestion des fonctionnalités prend également en charge l’utilisation du Microsoft Feature Management schema pour déclarer des indicateurs de fonctionnalité. Ce schéma est indépendant du langage d’origine et est pris en charge par toutes les bibliothèques de gestion des fonctionnalités 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"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

Remarque

Si la section feature_management se trouve dans la configuration, la section FeatureManagement est ignorée.

La bibliothèque de gestion des fonctionnalités prend en charge appsettings.json en tant que source d’indicateur de fonctionnalité, car il s’agit d’un fournisseur pour le système IConfiguration de .NET Core. Les indicateurs de fonctionnalité sont déclarés à l’aide du Microsoft Feature Management schema. Ce schéma est indépendant du langage d’origine et est pris en charge par toutes les bibliothèques de gestion des fonctionnalités Microsoft.

Vous trouverez ci-dessous un exemple de déclaration d’indicateurs de fonctionnalité dans un fichier 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"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

La section feature_management du document JSON est utilisée par convention pour charger les paramètres des indicateurs de fonctionnalité. Les objets d’indicateur de fonctionnalité doivent être répertoriés dans le tableau feature_flags sous la section feature_management. Dans la section ci-dessus, nous constatons que nous avons fourni trois fonctionnalités différentes. Un indicateur de fonctionnalité a les propriétés id et enabled. Le id est le nom utilisé pour identifier et référencer l’indicateur de fonctionnalité. La propriété enabled spécifie l’état activé de l’indicateur de fonctionnalité. Une fonctionnalité est désactivée si enabled est false. Si enabled est true, l’état de la fonctionnalité dépend des conditions. S’il n’y a pas de conditions, la fonctionnalité est activée. S’il y des conditions et qu’elles sont satisfaites, la fonctionnalité est activée. S’il y des conditions et qu’elles ne sont pas satisfaites, la fonctionnalité est désactivée. La propriété conditions déclare les conditions utilisées pour activer dynamiquement la fonctionnalité. Les fonctionnalités définissent leurs filtres de fonctionnalités dans le tableau client_filters. FeatureV spécifie un filtre de fonctionnalités nommé Microsoft.TimeWindow. Il s’agit d’un exemple de filtre de fonctionnalités configurable. Nous pouvons voir dans l’exemple que le filtre a une propriété Parameters. Elle est utilisée pour configurer le filtre. Dans ce cas, les heures de début et de fin d’activation de la fonctionnalité sont configurées.

Avancé : l’utilisation du signe deux-points (:) est interdite dans les noms d’indicateurs de fonctionnalité.

RequirementType

La propriété requirement_type des conditions sert à déterminer si les filtres doivent utiliser la logique Any ou All lors de l’évaluation de l’état d’une fonctionnalité. Si requirement_type n’est pas spécifié, la valeur par défaut est Any.

  • Any signifie qu’un seul filtre doit être évalué sur true pour que la fonctionnalité soit activée.
  • All signifie que tous les filtres doivent être évalués sur true pour que la fonctionnalité soit activée.

Un requirement_type de All modifie le parcours. Tout d’abord, s’il n’existe aucun filtre, la fonctionnalité est désactivée. S’il existe des filtres, les filtres de fonctionnalités sont parcourus jusqu’à ce que l’un des filtres décide que la fonctionnalité doit être désactivée. Si aucun filtre n’indique que la fonctionnalité doit être désactivée, elle est alors considérée comme activée.

{
    "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"
                }
            }
        ]
    }
}

Dans l’exemple ci-dessus, FeatureW spécifie un requirement_type de All, ce qui signifie que tous ses filtres doivent être évalués sur true pour que la fonctionnalité soit activée. Dans ce cas, la fonctionnalité sera activée pour 50 % des utilisateurs pendant la fenêtre de temps spécifiée.

Schéma de gestion des fonctionnalités .NET

Dans les versions précédentes, le schéma principal de la bibliothèque de gestion des fonctionnalités était le .NET feature management schema. À partir de la version 4.0.0, les nouvelles fonctionnalités, notamment les variantes et les données de télémétrie, ne seront pas prises en charge pour le schéma de gestion des fonctionnalités .NET.

Remarque

Si les deux sections feature_management et FeatureManagement contiennent une déclaration d’indicateur de fonctionnalité, celle de la section feature_management sera adoptée.

Consommation

La forme de base de la gestion des fonctionnalités consiste à vérifier si un indicateur de fonctionnalité est activé, puis à effectuer des actions en fonction du résultat. Cette opération est effectuée dans IFeatureManager, par le biais de sa méthode IsEnabledAsync.

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

Inscription du service

Le gestionnaire de fonctionnalités s’appuie sur l’injection de dépendances .NET Core. Nous pouvons inscrire les services de gestion de fonctionnalités à l’aide de conventions standard.

using Microsoft.FeatureManagement;

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

Par défaut, le gestionnaire de fonctionnalités récupère la configuration des indicateurs de fonctionnalité à partir de la section « FeatureManagement » des données de configuration .NET Core. Si la section « FeatureManagement » n’existe pas, la configuration est considérée comme vide.

Remarque

Vous pouvez également spécifier que la configuration des indicateurs de fonctionnalité doit être récupérée à partir d’une autre section de configuration en passant la section à AddFeatureManagement. L’exemple suivant indique au gestionnaire de fonctionnalités de lire à partir d’une autre section nommée « MyFeatureFlags » :

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

Injection de dépendances

Lorsque vous utilisez la bibliothèque de gestion des fonctionnalités avec MVC, vous pouvez obtenir le IFeatureManager via l’injection de dépendances.

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

Services de gestion des fonctionnalités délimités

La méthode AddFeatureManagement ajoute des services de gestion des fonctionnalités en tant que singletons dans l’application, mais il existe des scénarios où il peut être nécessaire d’ajouter les services de gestion des fonctionnalités en tant que services délimités à la place. Par exemple, les utilisateurs peuvent souhaiter utiliser des filtres de fonctionnalités qui consomment des services délimités pour obtenir des informations contextuelles. Dans ce cas, la méthode AddScopedFeatureManagement doit être utilisée à la place. Cela garantit que les services de gestion des fonctionnalités, y compris les filtres de fonctionnalités, sont ajoutés en tant que services délimités.

services.AddScopedFeatureManagement();

Intégration ASP.NET Core

La bibliothèque de gestion des fonctionnalités fournit des fonctionnalités dans ASP.NET Core et MVC pour activer des scénarios d’indicateurs de fonctionnalité courants dans les applications web. Ces fonctionnalités sont disponibles en référençant le package NuGet Microsoft.FeatureManagement.AspNetCore.

Contrôleurs et actions

Le contrôleur et les actions MVC peuvent exiger qu’une fonctionnalité donnée, ou l’une de n’importe quelle liste de fonctionnalités, soit activée pour s’exécuter. Pour ce faire, utilisez un FeatureGateAttribute, qui se trouve dans l’espace de noms Microsoft.FeatureManagement.Mvc.

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

Le HomeController ci-dessus est contrôlé par « FeatureX ». « FeatureX » doit être activée avant que n’importe quelle action contenue dans le HomeController puisse être exécutée.

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

L’action MVC Index ci-dessus nécessite que « FeatureX » soit activée avant qu’elle ne puisse être exécutée.

Gestion des actions désactivées

Lorsqu’un contrôleur ou une action MVC est bloqué, car aucune des fonctionnalités spécifiées n’est activée, un IDisabledFeaturesHandler inscrit est appelé. Par défaut, un gestionnaire minimaliste est inscrit, qui retourne HTTP 404. Cela peut être remplacé à l’aide du IFeatureManagementBuilder lors de l’inscription des indicateurs de fonctionnalité.

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

Affichage

Dans les vues MVC, vous pouvez utiliser une balise <feature> pour rendre conditionnellement le contenu selon qu’une fonctionnalité est activée ou non.

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

Vous pouvez également inverser l’évaluation du tag helper pour afficher le contenu lorsqu’une fonctionnalité ou un ensemble de fonctionnalités sont désactivés. En définissant negate="true" dans l’exemple ci-dessous, le contenu est rendu uniquement si FeatureX est désactivé.

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

La balise <feature> peut référencer plusieurs fonctionnalités en spécifiant une liste séparée par des virgules des fonctionnalités dans l’attribut name.

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

Par défaut, toutes les fonctionnalités répertoriées doivent être activées pour que la balise de fonctionnalité soit rendue. Ce comportement peut être remplacé en ajoutant l’attribut requirement comme indiqué dans l’exemple ci-dessous.

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

Dans les vues MVC, vous pouvez utiliser les balises <feature> pour rendre le contenu de manière conditionnelle selon qu’une fonctionnalité est activée ou non, ou qu’une variante spécifique d’une fonctionnalité est affectée ou non. Pour plus d’informations, consultez la section Variantes.

<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>

Vous pouvez également inverser l’évaluation du tag helper pour afficher le contenu lorsqu’une fonctionnalité ou un ensemble de fonctionnalités sont désactivés. En définissant negate="true" dans l’exemple ci-dessous, le contenu est rendu uniquement si FeatureX est désactivé.

<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>

La balise <feature> peut référencer plusieurs fonctionnalités/variantes en spécifiant une liste séparée par des virgules de fonctionnalités/variantes dans l’attribut name/variant.

<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>

Remarque

Si variant est spécifié, une seule fonctionnalité doit être spécifiée.

Par défaut, toutes les fonctionnalités répertoriées doivent être activées pour que la balise de fonctionnalité soit rendue. Ce comportement peut être remplacé en ajoutant l’attribut requirement comme indiqué dans l’exemple ci-dessous.

Remarque

Si un requirement de And est utilisé conjointement avec variant, une erreur est levée, car plusieurs variantes ne peuvent jamais être affectées.

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

La balise <feature> nécessite un tag helper pour fonctionner. Pour ce faire, ajoutez le tag helper de gestion des fonctionnalités au fichier ViewImports.cshtml.

@addTagHelper *, Microsoft.FeatureManagement.AspNetCore

Filtres MVC

Des filtres d’action MVC peuvent être configurés pour s’exécuter de manière conditionnelle en fonction de l’état d’une fonctionnalité. Pour ce faire, inscrivez des filtres MVC de manière à reconnaître des fonctionnalités. Le pipeline de gestion des fonctionnalités prend en charge les filtres d’action MVC asynchrones, qui implémentent IAsyncActionFilter.

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

Le code ci-dessus ajoute un filtre MVC nommé SomeMvcFilter. Ce filtre est déclenché dans le pipeline MVC seulement si « FeatureX » est activée.

Pages Razor

Les pages Razor MVC peuvent exiger qu’une fonctionnalité donnée, ou l’une de n’importe quelle liste de fonctionnalités, soit activée pour s’exécuter. Pour ce faire, utilisez un FeatureGateAttribute, qui se trouve dans l’espace de noms Microsoft.FeatureManagement.Mvc.

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

Le code ci-dessus configure une page Razor pour exiger que « FeatureX » soit activée. Si la fonctionnalité n’est pas activée, la page génère un résultat HTTP 404 (NotFound).

Lorsqu’il est utilisé sur des pages Razor, le FeatureGateAttribute doit être placé sur le type de gestionnaire de pages. Il ne peut pas être placé sur des méthodes de gestionnaire individuelles.

Création d’application

La bibliothèque de gestion des fonctionnalités peut être utilisée pour ajouter des branches d’application et des intergiciels qui s’exécutent de manière conditionnelle en fonction de l’état des fonctionnalités.

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

Avec l’appel ci-dessus, l’application ajoute un composant intergiciel qui apparaît uniquement dans le pipeline de requête si la fonctionnalité « FeatureX » est activée. Si la fonctionnalité est activée/désactivée pendant l’exécution, le pipeline de l’intergiciel peut être modifié dynamiquement.

Cette opération repose sur la capacité plus générique qui consiste à créer une branche d’application entière en fonction d’une fonctionnalité.

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

Implémentation d’un filtre de fonctionnalités

La création d’un filtre de fonctionnalités permet d’activer des fonctionnalités en fonction des critères que vous définissez. Pour implémenter un filtre de fonctionnalités, l’interface IFeatureFilter doit être implémentée. IFeatureFilter a une méthode unique nommée EvaluateAsync. Lorsqu’une fonctionnalité spécifie qu’elle peut être activée pour un filtre de fonctionnalités, la méthode EvaluateAsync est appelée. Si EvaluateAsync retourne true, cela signifie que la fonctionnalité doit être activée.

L’extrait de code suivant montre comment ajouter un filtre de fonctionnalités personnalisé MyCriteriaFilter.

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

Les filtres de fonctionnalités sont inscrits en appelant AddFeatureFilter<T> sur le IFeatureManagementBuilder retourné par AddFeatureManagement. Ces filtres de fonctionnalités ont accès aux services qui existent dans la collection de services utilisée pour ajouter des indicateurs de fonctionnalité. L’injection de dépendances peut être utilisée pour récupérer ces services.

Remarque

Lorsque des filtres sont référencés dans les paramètres des indicateurs de fonctionnalité (par exemple, appsettings.json), la partie Filtre du nom de type doit être omise. Pour plus d’informations, consultez la section Filter Alias Attribute.

Filtres de fonctionnalités paramétrisés

Certains filtres de fonctionnalités nécessitent des paramètres pour déterminer si une fonctionnalité doit être activée ou non. Par exemple, un filtre de fonctionnalités de navigateur peut activer une fonctionnalité pour un certain ensemble de navigateurs. Il peut être souhaité que les navigateurs Edge et Chrome activent une fonctionnalité, tandis que Firefox ne le fait pas. Pour ce faire, un filtre de fonctionnalités peut être conçu pour attendre des paramètres. Ces paramètres sont spécifiés dans la configuration de la fonctionnalité et sont accessibles dans le code via le paramètre FeatureFilterEvaluationContext de 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 a une propriété nommée Parameters. Ces paramètres représentent une configuration brute que le filtre de fonctionnalités peut utiliser pour déterminer si la fonctionnalité doit être activée ou non. Pour utiliser à nouveau le filtre de fonctionnalités du navigateur comme exemple, le filtre peut utiliser Parameters pour extraire un ensemble de navigateurs autorisés qui seraient spécifiés pour la fonctionnalité, puis vérifier si la requête est envoyée à partir de l’un de ces navigateurs.

[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
    }
}

Attribut d’alias de filtre

Lorsqu’un filtre de fonctionnalités est inscrit pour un indicateur de fonctionnalité, l’alias utilisé dans la configuration est le nom du type de filtre de fonctionnalités avec le suffixe Filter, le cas échéant, supprimé. Par exemple, MyCriteriaFilter serait référencé en tant que MyCriteria dans la configuration.

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

Vous pouvez modifier ce comportement en utilisant le FilterAliasAttribute. Un filtre de fonctionnalités peut être décoré avec cet attribut pour déclarer le nom qui doit être utilisé dans la configuration pour référencer ce filtre de fonctionnalités dans un indicateur de fonctionnalité.

Filtres de fonctionnalités manquants

Si une fonctionnalité est configurée pour être activée pour un filtre de fonctionnalités spécifique et que ce filtre de fonctionnalité n’est pas inscrit, une exception est levée lorsque la fonctionnalité est évaluée. L’exception peut être désactivée à l’aide des options de gestion de la fonctionnalité.

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

Utilisation de HttpContext

Les filtres de fonctionnalités peuvent évaluer si une fonctionnalité doit être activée en fonction des propriétés d’une requête HTTP. Cette opération est effectuée en inspectant le contexte HTTP. Un filtre de fonctionnalités peut obtenir une référence au contexte HTTP en obtenant un IHttpContextAccessor via une injection de dépendances.

public class BrowserFilter : IFeatureFilter
{
    private readonly IHttpContextAccessor _httpContextAccessor;

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

Le IHttpContextAccessor doit être ajouté au conteneur d’injection de dépendances au démarrage pour qu’il soit disponible. Il peut être inscrit dans le IServiceCollection à l’aide de la méthode suivante.

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

Avancé : IHttpContextAccessor/HttpContext ne doit pas être utilisé dans les composants Razor des applications Blazor côté serveur. L’approche recommandée pour passer le contexte http dans les applications Blazor consiste à copier les données dans un service délimité. Pour les applications Blazor, vous devez utiliser AddScopedFeatureManagement pour inscrire les services de gestion des fonctionnalités. Pour plus d’informations, consultez la section Scoped Feature Management Services.

Fournir un contexte pour l’évaluation des fonctionnalités

Dans les applications console, il n’existe aucun contexte ambiant tel que HttpContext que les filtres de fonctionnalités peuvent acquérir et utiliser pour vérifier si une fonctionnalité doit être activée ou désactivée. Dans ce cas, les applications doivent fournir un objet représentant un contexte dans le système de gestion des fonctionnalités à utiliser par les filtres de fonctionnalités. Ceci est possible en utilisant IFeatureManager.IsEnabledAsync<TContext>(string featureName, TContext appContext). L’objet appContext fourni au gestionnaire de fonctionnalités peut être utilisé par les filtres de fonctionnalités pour évaluer l’état d’une fonctionnalité.

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

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

Filtres de fonctionnalités contextuels

Les filtres de fonctionnalités contextuels implémentent l’interface IContextualFeatureFilter<TContext>. Ces filtres de fonctionnalités spéciaux peuvent tirer parti du contexte passé lorsque IFeatureManager.IsEnabledAsync<TContext> est appelé. Le paramètre de type TContext dans IContextualFeatureFilter<TContext> décrit le type de contexte que le filtre est capable de gérer. Cela permet au développeur d’un filtre de fonctionnalités contextuel de décrire ce qui est requis pour ceux qui souhaitent l’utiliser. Étant donné que chaque type est un descendant d’objet, un filtre qui implémente IContextualFeatureFilter<object> peut être appelé pour n’importe quel contexte fourni. Pour illustrer un exemple de filtre de fonctionnalités contextuel plus spécifique, prenez une fonctionnalité activée si un compte se trouve dans une liste configurée de comptes activés.

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
    }
}

Nous pouvons voir que le AccountIdFilter requiert qu’un objet qui implémente IAccountContext soit fourni pour pouvoir évaluer l’état d’une fonctionnalité. Lorsqu’il utilise ce filtre de fonctionnalité, l’appelant doit s’assurer que l’objet passé implémente IAccountContext.

Remarque

Une seule interface de filtre de fonctionnalités peut être implémentée par un type unique. Tenter d’ajouter un filtre de fonctionnalités qui implémente plus d’une interface de filtre de fonctionnalités entraîne un ArgumentException.

Utilisation de filtres contextuels et non contextuels avec le même alias

Les filtres IFeatureFilter et IContextualFeatureFilter peuvent partager le même alias. Plus précisément, vous pouvez avoir un alias de filtre partagé par 0 ou 1 IFeatureFilter et 0 ou N IContextualFeatureFilter<ContextType>, tant qu’il existe au maximum un filtre applicable pour ContextType.

Le passage suivant décrit le processus de sélection d’un filtre lorsque des filtres contextuels et non contextuels du même nom sont inscrits dans une application.

Supposons que vous ayez un filtre non contextuel appelé FilterA et deux filtres contextuels FilterB et FilterC qui acceptent les contextes TypeB et TypeC respectivement. Les trois filtres partagent le même alias SharedFilterName.

Vous disposez également d’un indicateur de fonctionnalité MyFeature qui utilise le filtre de fonctionnalités SharedFilterName dans sa configuration.

Si les trois filtres sont inscrits :

  • Lorsque vous appelez IsEnabledAsync(« MyFeature »), le FilterA est utilisé pour évaluer l’indicateur de fonctionnalité.
  • Lorsque vous appelez IsEnabledAsync(« MyFeature », contexte), si le type du contexte est TypeB, FilterB est utilisé. Si le type du contexte est TypeC, FilterC est utilisé.
  • Lorsque vous appelez IsEnabledAsync(« MyFeature », contexte), si le type du contexte est TypeF, FilterA est utilisé.

Filtres de fonctionnalités intégrés

Il existe quelques filtres de fonctionnalités fournis avec le package Microsoft.FeatureManagement : PercentageFilter, TimeWindowFilter, ContextualTargetingFilter et TargetingFilter. Tous les filtres, à l’exception de TargetingFilter, sont ajoutés automatiquement lorsque la gestion des fonctionnalités est inscrite par la méthode AddFeatureManagement. Le TargetingFilter est ajouté avec la méthode WithTargeting détaillée dans la section Targeting ci-dessous.

Chacun des filtres de fonctionnalités intégrés a ses propres paramètres. Voici la liste des filtres de fonctionnalités, ainsi que des exemples.

Microsoft.Percentage

Ce filtre permet d’activer une fonctionnalité en fonction d’un pourcentage défini.

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

Microsoft.TimeWindow

Ce filtre permet d’activer une fonctionnalité en fonction d’une fenêtre de temps. Si uniquement End est spécifié, la fonctionnalité est considérée comme activée jusqu’à cette heure. Si uniquement Start est spécifié, la fonctionnalité est considérée comme activée à tous les points après cette heure.

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

La fenêtre de temps peut être configurée pour se répéter régulièrement. Cela peut être utile pour les scénarios où il peut être nécessaire d’activer une fonctionnalité pendant une période de trafic faible ou élevée d’un jour ou de certains jours d’une semaine. Pour étendre la fenêtre de temps individuelle aux fenêtres de temps périodiques, la règle de périodicité doit être spécifiée dans le paramètre Recurrence.

Remarque

Start et End doivent être tous deux spécifiés pour activer 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"
                    }
                }
            }
        }
    ]
}

Les paramètres Recurrence sont constitués de deux parties : Pattern (fréquence à laquelle la fenêtre de temps se répète) et Range (pendant combien de temps le modèle de périodicité se répète).

Critère de périodicité

Il existe deux types de modèles de périodicité possibles : Daily et Weekly. Par exemple, une fenêtre de temps peut se répéter « tous les jours », « tous les trois jours », « tous les lundis » ou « un vendredi sur deux ».

Selon le type, certains champs du Pattern sont obligatoires, facultatifs ou ignorés.

  • Daily

    Le modèle de périodicité quotidienne entraîne la répétition de la fenêtre de temps en fonction d’un certain nombre de jours entre chaque occurrence.

    Propriété Pertinence Description
    Type Requis Cette propriété doit être définie sur Daily.
    Intervalle Facultatif Spécifie le nombre de jours entre chaque occurrence. La valeur par défaut est 1.
  • Weekly

    Le modèle de périodicité hebdomadaire entraîne la répétition de la fenêtre de temps le même ou les mêmes jours de la semaine, en fonction du nombre de semaines entre chaque ensemble d’occurrences.

    Propriété Pertinence Description
    Type Requis Cette propriété doit être définie sur Weekly.
    DaysOfWeek Requis Spécifie les jours de la semaine où l’événement se produit.
    Intervalle Facultatif Spécifie le nombre de semaines entre chaque ensemble d’occurrences. La valeur par défaut est 1.
    FirstDayOfWeek Facultatif Spécifie le jour considéré comme le premier jour de la semaine. La valeur par défaut est Sunday.

    L’exemple suivant répète la fenêtre de temps un lundi et un mardi sur deux

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

Remarque

Start doit être une première occurrence valide qui correspond au modèle de périodicité. En outre, la durée de la fenêtre de temps ne peut pas être plus longue que la fréquence à laquelle elle se produit. Par exemple, il n’est pas possible d’avoir une fenêtre de temps de 25 heures qui se répète tous les jours.

Plage de périodicité

Il existe trois types de plages de périodicité possibles : NoEnd, EndDate et Numbered.

  • NoEnd

    La plage NoEnd entraîne une périodicité indéfinie.

    Propriété Pertinence Description
    Type Requis Cette propriété doit être définie sur NoEnd.
  • EndDate

    La plage EndDate entraîne l’exécution de la fenêtre de temps tous les jours qui correspondent au modèle applicable jusqu’à la date de fin.

    Propriété Pertinence Description
    Type Requis Cette propriété doit être définie sur EndDate.
    EndDate Requis Spécifie l’heure et la date auxquelles l’application du modèle s’arrête. Tant que l’heure de début de la dernière occurrence tombe avant la date de fin, l’heure de fin de cette occurrence est autorisée à s’étendre au-delà de celle-ci.

    L’exemple suivant répète la fenêtre de temps tous les jours jusqu’à ce que la dernière occurrence se produise le 1er avril 2024.

    "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

    La plage Numbered entraîne l’exécution d’une fenêtre de temps un nombre fixe d’occurrences (en fonction du modèle).

    Propriété Pertinence Description
    Type Requis Cette propriété doit être définie sur Numbered.
    NumberOfOccurrences Requis Indique le nombre d’occurrences.

    L’exemple suivant répète la fenêtre de temps le lundi et le mardi jusqu’à ce qu’il y ait trois occurrences, qui se produisent respectivement le lundi 1er avril, le mardi 2 avril et le lundi 8 avril.

    "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
        }
    }
    

Pour créer une règle de périodicité, vous devez spécifier à la fois Pattern et Range. N’importe quel type de modèle peut fonctionner avec n’importe quel type de plage.

Avancé : le décalage de fuseau horaire de la propriété Start est appliqué aux paramètres de périodicité.

Microsoft.Targeting

Ce filtre permet d’activer une fonctionnalité pour un public cible. Une explication détaillée du ciblage est expliquée dans la section sur le ciblage ci-dessous. Les paramètres de filtre incluent un objet Audience qui décrit les utilisateurs, les groupes, les utilisateurs et groupes exclus et un pourcentage par défaut de la base d’utilisateurs qui doit avoir accès à la fonctionnalité. Chaque objet de groupe répertorié dans la section Groups doit également spécifier le pourcentage des membres du groupe qui doivent avoir accès. Si un utilisateur est spécifié dans la section Exclusion, directement ou si l’utilisateur se trouve dans un groupe exclu, la fonctionnalité est désactivée. Sinon, si un utilisateur est spécifié directement dans la section Users, ou si l’utilisateur se trouve dans le pourcentage inclus de l’un des déploiements de groupe, ou si l’utilisateur tombe dans le pourcentage de déploiement par défaut, cette fonctionnalité est activée.

"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"
                        ]
                    }
                }
            }
        }
    ]
}

Espaces de noms d’alias de filtre de fonctionnalités

Tous les alias de filtre de fonctionnalités intégrés se trouvent dans l’espace de noms de filtre de fonctionnalités Microsoft. Cela permet d’éviter les conflits avec d’autres filtres de fonctionnalités qui peuvent partager le même alias. Les segments d’un espace de noms de filtre de fonctionnalités sont divisés par le caractère « . ». Un filtre de fonctionnalités peut être référencé par son alias complet, tel que Microsoft.Percentage, ou par le dernier segment qui, dans le cas de Microsoft.Percentage, est Percentage.

Ciblage

Le ciblage est une stratégie de gestion des fonctionnalités qui permet aux développeurs de déployer progressivement de nouvelles fonctionnalités sur leur base d’utilisateurs. La stratégie repose sur le concept de ciblage d’un ensemble d’utilisateurs appelé public cible. Un public est constitué d’utilisateurs, de groupes spécifiques, d’utilisateurs et de groupes exclus, et d’un pourcentage désigné de l’ensemble de la base d’utilisateurs. Les groupes inclus dans le public peuvent être divisés en pourcentages de leurs membres totaux.

Les étapes suivantes illustrent un exemple de déploiement progressif d’une nouvelle fonctionnalité « Bêta » :

  1. Les utilisateurs individuels Jeff et Alicia ont accès à la version Bêta
  2. Un autre utilisateur, Mark, demande l’inscription et est inclus.
  3. Vingt pour cent d’un groupe appelé utilisateurs « Ring1 » sont inclus dans la version Bêta.
  4. Le nombre d’utilisateurs « Ring1 » inclus dans la version bêta est passé à 100 %.
  5. Cinq pour cent de la base d’utilisateurs sont inclus dans la version Bêta.
  6. Le pourcentage de déploiement est passé à 100 % et la fonctionnalité est entièrement déployée.

Cette stratégie de déploiement d’une fonctionnalité est intégrée à la bibliothèque via le filtre de fonctionnalité Microsoft.Targeting inclus.

Ciblage dans une application web

Un exemple d’application web qui utilise le filtre de fonctionnalités de ciblage est disponible dans l’exemple de projet FeatureFlagDemo.

Pour commencer à utiliser le TargetingFilter dans une application, il doit être ajouté à la collection de services de l’application comme n’importe quel autre filtre de fonctionnalités. Contrairement à d’autres filtres intégrés, le TargetingFilter s’appuie sur un autre service à ajouter à la collection de services de l’application. Ce service est un ITargetingContextAccessor.

Microsoft.FeatureManagement.AspNetCore fournit une implémentation par défaut de ITargetingContextAccessor qui extrait les informations de ciblage du HttpContextd’une requête. Vous pouvez utiliser l’accesseur de contexte de ciblage par défaut lors de la configuration du ciblage à l’aide de la surcharge non générique WithTargeting sur le IFeatureManagementBuilder.

L’accesseur de contexte de ciblage par défaut et TargetingFilter sont inscrits en appelant WithTargeting sur le IFeatureManagementBuilder.

services.AddFeatureManagement()
        .WithTargeting();

Vous pouvez également inscrire une implémentation personnalisée pour ITargetingContextAccessor et TargetingFilter en appelant WithTargeting<T>. Voici un exemple de configuration de la gestion des fonctionnalités dans une application web pour utiliser le TargetingFilter avec une implémentation de ITargetingContextAccessor appelée ExampleTargetingContextAccessor.

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

ITargetingContextAccessor

Pour utiliser le TargetingFilter dans une application web, une implémentation de ITargetingContextAccessor est requise. En effet, lorsqu’une évaluation de ciblage est exécutée, des informations contextuelles telles que l’utilisateur en cours d’évaluation sont nécessaires. Ces informations sont appelées le TargetingContext. Différentes applications peuvent extraire ces informations à partir de différents endroits. Quelques exemples courants à partir desquels une application peut extraire le contexte de ciblage sont le contexte HTTP de la requête ou une base de données.

Un exemple qui extrait les informations de contexte de ciblage à partir du contexte HTTP de l’application est le DefaultHttpTargetingContextAccessor fourni par le package Microsoft.FeatureManagement.AspNetCore. Il extrait les informations de ciblage à partir de HttpContext.User. Les informations UserId seront extraites du champ Identity.Name et les informations Groups seront extraites des revendications de type Role. Cette implémentation s’appuie sur l’utilisation de IHttpContextAccessor, qui est abordé ici.

Ciblage dans une application console

Le filtre de ciblage s’appuie sur un contexte de ciblage pour évaluer si une fonctionnalité doit être activée. Ce contexte de ciblage contient des informations telles que l’utilisateur en cours d’évaluation et les groupes auxquels l’utilisateur appartient. Dans les applications console, il n’existe généralement aucun contexte ambiant disponible pour transmettre ces informations au filtre de ciblage. Il doit donc être transmis directement lorsque FeatureManager.IsEnabledAsync est appelé. Ceci est pris en charge à l’aide du ContextualTargetingFilter. Les applications qui doivent faire flotter le contexte de ciblage dans le gestionnaire de fonctionnalités doivent l’utiliser au lieu du TargetingFilter.

Étant donné que ContextualTargetingFilter est une IContextualTargetingFilter<ITargetingContext>, une implémentation de ITargetingContext doit être transmise à IFeatureManager.IsEnabledAsync pour qu’elle puisse évaluer et activer une fonctionnalité.

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

await fm.IsEnabledAsync(featureName, targetingContext);

Le ContextualTargetingFilter utilise toujours l’alias de filtre de fonctionnalités Microsoft.Targeting, de sorte que la configuration de ce filtre est cohérente avec ce qui est mentionné dans cette section.

Un exemple qui utilise le ContextualTargetingFilter dans une application console est disponible dans l’exemple de projet TargetingConsoleApp.

Options d’évaluation de ciblage

Des options sont disponibles pour personnaliser la façon dont l’évaluation du ciblage est effectuée sur toutes les fonctionnalités. Ces options peuvent être configurées lors de la configuration de la gestion des fonctionnalités.

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

Exclusion de ciblage

Lors de la définition d’un public, des utilisateurs et des groupes peuvent être exclus du public. Cela est utile lorsqu’une fonctionnalité est déployée sur un groupe d’utilisateurs, mais que quelques utilisateurs ou groupes doivent être exclus du déploiement. L’exclusion est définie en ajoutant une liste d’utilisateurs et de groupes à la propriété Exclusion du public.

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

Dans l’exemple ci-dessus, la fonctionnalité est activée pour les utilisateurs nommés Jeff et Alicia. Elle est également activée pour les utilisateurs du groupe nommé Ring0. Toutefois, si l’utilisateur est nommé Mark, la fonctionnalité est désactivée, qu’il se trouve dans le groupe Ring0 ou non. Les exclusions sont prioritaires sur le reste du filtre de ciblage.

Variantes

Lorsque de nouvelles fonctionnalités sont ajoutées à une application, il peut arriver qu’une fonctionnalité ait différentes options de conception proposées. Une solution courante pour décider d’une conception est une forme de test A/B, qui implique de fournir une version différente de la fonctionnalité à différents segments de la base d’utilisateurs et de choisir une version en fonction de l’interaction utilisateur. Dans cette bibliothèque, cette fonctionnalité est activée en représentant différentes configurations d’une fonctionnalité avec des variantes.

Les variantes permettent à un indicateur de fonctionnalité de devenir plus qu’un simple indicateur activé/désactivé. Une variante représente une valeur d’un indicateur de fonctionnalité qui peut être une chaîne, un nombre, une valeur booléenne ou même un objet de configuration. Un indicateur de fonctionnalité qui déclare des variantes doit définir dans quelles circonstances chaque variante doit être utilisée, ce qui est abordé plus en détail dans la section Allocation de variantes.

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; }
}

Obtention de variantes

Pour chaque fonctionnalité, une variante peut être récupérée dans le IVariantFeatureManager à l’aide de sa méthode 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

Une fois qu’une variante est récupérée, la configuration d’une variante peut être utilisée directement en tant que IConfigurationSection dans la propriété Configuration de la variante. Une autre option consiste à lier la configuration à un objet à l’aide d’un modèle de liaison de configuration .NET.

IConfigurationSection variantConfiguration = variant.Configuration;

MyFeatureSettings settings = new MyFeatureSettings();

variantConfiguration.Bind(settings);

La variante retournée dépend de l’utilisateur en cours d’évaluation, et ces informations sont obtenues à partir d’une instance de TargetingContext. Ce contexte peut être transmis lors de l’appel de GetVariantAsync ou il peut être récupéré automatiquement à partir d’une implémentation de ITargetingContextAccessor inscrite, le cas échéant.

Déclaration d’indicateur de fonctionnalité de variante

Comparés aux indicateurs de fonctionnalité normaux, les indicateurs de fonctionnalité de variante ont deux propriétés supplémentaires : variants et allocation. La propriété variants est un tableau qui contient les variantes définies pour cette fonctionnalité. La propriété allocation définit la façon dont ces variantes doivent être allouées pour la fonctionnalité. Tout comme la déclaration d’indicateurs de fonctionnalité normaux, vous pouvez configurer des indicateurs de fonctionnalité de variante dans un fichier json. Voici un exemple d’indicateur de fonctionnalité de variante.

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

Définition de variantes

Chaque variante a deux propriétés : un nom et une configuration. Le nom est utilisé pour faire référence à une variante spécifique, et la configuration est la valeur de cette variante. La configuration peut être définie à l’aide de la propriété configuration_value. configuration_value est une configuration inline qui peut être une chaîne, un nombre, une valeur booléenne ou un objet de configuration. Si configuration_value n’est spécifiée, la propriété Configuration de la variante retournée est nulle.

Une liste de toutes les variantes possibles est définie pour chaque fonctionnalité sous la propriété variants.

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

Allocation de variantes

Le processus d’allocation des variantes d’une fonctionnalité est déterminé par la propriété allocation de la fonctionnalité.

"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"
    } 
]

Le paramètre allocation d’une fonctionnalité a les propriétés suivantes :

Propriété Description
default_when_disabled Spécifie quelle variante doit être utilisée lorsqu’une variante est demandée alors que la fonctionnalité est considérée comme désactivée.
default_when_enabled Spécifie quelle variante doit être utilisée lorsqu’une variante est demandée alors que la fonctionnalité est considérée comme activée et qu’aucune autre variante n’a été affectée à l’utilisateur.
user Spécifie une variante et une liste d’utilisateurs auxquels cette variante doit être affectée.
group Spécifie une variante et une liste de groupes. La variante est affectée si l’utilisateur se trouve dans au moins un des groupes.
percentile Spécifie une variante et une plage de pourcentages dans laquelle le pourcentage calculé de l’utilisateur doit se trouver pour que cette variante soit affectée.
seed La valeur sur laquelle les calculs de pourcentage pour percentile sont basés. Le calcul du pourcentage pour un utilisateur spécifique sera le même pour toutes les fonctionnalités si la même valeur seed est utilisée. Si aucune seed n’est spécifiée, une valeur initiale par défaut est créée en fonction du nom de la fonctionnalité.

Dans l’exemple ci-dessus, si la fonctionnalité n’est pas activée, le gestionnaire de fonctionnalités affecte la variante marquée comme default_when_disabled à l’utilisateur actuel, qui est Small dans ce cas.

Si la fonctionnalité est activée, le gestionnaire de fonctionnalités vérifie les allocations user, group et percentile dans cet ordre pour affecter une variante. Pour cet exemple particulier, si l’utilisateur évalué est nommé Marsha, dans le groupe nommé Ring1, ou si l’utilisateur se trouve entre le 0 et le 10e centile, la variante spécifiée est affectée à l’utilisateur. Dans ce cas, tous ces éléments retournent la variante Big. Si aucune de ces allocations ne correspond, l’utilisateur reçoit la variante default_when_enabled, à savoir Small.

La logique d’allocation est similaire au filtre de fonctionnalités Microsoft.Targeting, mais certains paramètres sont présents dans le ciblage qui ne sont pas dans l’allocation, et inversement. Les résultats du ciblage et de l’allocation ne sont pas liés.

Remarque

Pour autoriser l’allocation de variantes de fonctionnalités, vous devez inscrire ITargetingContextAccessor. Ceci peut être fait en appelant la méthode WithTargeting<T>.

Remplacement de l’état activé par une variante

Vous pouvez utiliser des variantes pour remplacer l’état activé d’un indicateur de fonctionnalité. Cela permet aux variantes d’étendre l’évaluation d’un indicateur de fonctionnalité. Lorsque vous appelez IsEnabled sur un indicateur avec des variantes, le gestionnaire de fonctionnalités vérifie si la variante affectée à l’utilisateur actuel est configurée pour remplacer le résultat. Cette opération est effectuée à l’aide de la propriété de variante status_override facultative. Par défaut, cette propriété est définie sur None, ce qui signifie que la variante n’affecte pas si l’indicateur est considéré comme activé ou désactivé. Définir status_override sur Enabled permet à la variante, lorsqu’elle est choisie, de modifier un indicateur sur activé. Définir status_override sur Disabled a le comportement opposé, c’est-à-dire que l’indicateur est désactivé lorsque la variante est choisie. Une fonctionnalité avec un état enabled de false ne peut pas être remplacée.

Si vous utilisez un indicateur de fonctionnalité avec des variantes binaires, la propriété status_override peut être très utile. Elle vous permet de continuer à utiliser des API telles que IsEnabledAsync et FeatureGateAttribute dans votre application, tout en bénéficiant des nouvelles fonctionnalités fournies avec des variantes, telles que l’allocation de centile et les valeurs initiales.

{
    "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"
        }
    ]
}

Dans l’exemple ci-dessus, la fonctionnalité est toujours activée. Si l’utilisateur actuel se trouve dans la plage de centile calculée de 10 à 20, la variante On est retournée. Sinon, la variante Off est retournée et, car status_override est égal à Disabled, et la fonctionnalité sera désormais considérée comme désactivée.

Variantes dans l’injection de dépendances

Les indicateurs de fonctionnalité de variante peuvent être utilisés conjointement avec l’injection de dépendances pour exposer différentes implémentations d’un service pour différents utilisateurs. Pour faire cela, utilisez l’interface IVariantServiceProvider<TService>.

IVariantServiceProvider<IAlgorithm> algorithmServiceProvider;
...

IAlgorithm forecastAlgorithm = await algorithmServiceProvider.GetServiceAsync(cancellationToken); 

Dans l’extrait de code ci-dessus, le IVariantServiceProvider<IAlgorithm> récupère une implémentation de IAlgorithm à partir du conteneur d’injection de dépendances. L’implémentation choisie dépend des éléments suivants :

  • L’indicateur de fonctionnalité auprès duquel le service IAlgorithm a été inscrit.
  • La variante allouée pour cette fonctionnalité.

Le IVariantServiceProvider<T> est mis à la disposition de l’application en appelant IFeatureManagementBuilder.WithVariantService<T>(string featureName). Un exemple est donné ci-dessous.

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

L’appel ci-dessus rend IVariantServiceProvider<IAlgorithm> disponible dans la collection de services. Les implémentations de IAlgorithm doivent être ajoutées séparément via une méthode d’ajout telle que services.AddSingleton<IAlgorithm, SomeImplementation>(). L’implémentation de IAlgorithm que le IVariantServiceProvider utilise dépend de l’indicateur de fonctionnalité de variante ForecastAlgorithm. Si aucune implémentation de IAlgorithm n’est ajoutée à la collection de services, le IVariantServiceProvider<IAlgorithm>.GetServiceAsync() retourne une tâche avec un résultat null.

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

Attribut d’alias de service de variante

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

Le fournisseur de services de variante utilise les noms de types des implémentations pour correspondre à la variante allouée. Si un service de variante est décoré avec le VariantServiceAliasAttribute, le nom déclaré dans cet attribut doit être utilisé dans la configuration pour référencer ce service de variante.

Télémétrie

Lorsqu’un changement d’indicateur de fonctionnalité est déployé, il est souvent important d’analyser son effet sur une application. Par exemple, voici quelques questions qui peuvent survenir :

  • Mes indicateurs sont-ils activés/désactivés comme prévu ?
  • Les utilisateurs ciblés ont-ils accès à une certaine fonctionnalité comme prévu ?
  • Quelle variante un utilisateur particulier voit-il ?

Il est possible de répondre à ces types de questions par le biais de l’émission et de l’analyse des événements d’évaluation des indicateurs de fonctionnalité. Cette bibliothèque utilise l’API System.Diagnostics.Activity pour produire des données de télémétrie de suivi pendant l’évaluation de l’indicateur de fonctionnalité.

Activation de la télémétrie

Par défaut, les indicateurs de fonctionnalité n’émettent pas de données de télémétrie. Pour publier des données de télémétrie pour un indicateur de fonctionnalité donné, l’indicateur doit déclarer qu’il est activé pour l’émission de données de télémétrie.

Pour les indicateurs de fonctionnalité définis dans appsettings.json, cette opération est effectuée à l’aide de la propriété telemetry.

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

L’extrait de code appsettings ci-dessus définit un indicateur de fonctionnalité nommé MyFeatureFlag activé pour la télémétrie. Cela est indiqué par l’objet telemetry qui définit enabled sur true. La valeur de la propriété enabled doit être true pour publier des données de télémétrie pour l’indicateur.

La section telemetry d’un indicateur de fonctionnalité a les propriétés suivantes :

Propriété Description
enabled Spécifie si les données de télémétrie doivent être publiées pour l’indicateur de fonctionnalité.
metadata Une collection de paires clé-valeur, modélisées sous forme de dictionnaire, qui peuvent être utilisées pour attacher des métadonnées personnalisées sur l’indicateur de fonctionnalité aux événements d’évaluation.

Publication de données de télémétrie personnalisées

Le gestionnaire de fonctionnalités possède son propre ActivitySource appelé « Microsoft.FeatureManagement ». Si telemetry est activée pour un indicateur de fonctionnalité, chaque fois que l’évaluation de l’indicateur de fonctionnalité est démarrée, le gestionnaire de fonctionnalités démarre un Activity. Une fois l’évaluation de l’indicateur de fonctionnalité terminée, le gestionnaire de fonctionnalités ajoute un ActivityEvent nommé FeatureFlag à l’activité actuelle. L’événement FeatureFlag a des étiquettes qui incluent les informations relatives à l’évaluation de l’indicateur de fonctionnalité, après les champs définis dans le schéma FeatureEvaluationEvent.

Remarque

Toutes les paires clé-valeur spécifiées dans telemetry.metadata de l’indicateur de fonctionnalité seront également incluses dans les balises.

Pour activer la publication de données de télémétrie personnalisées, vous pouvez créer un ActivityListener et écouter la source d’activité Microsoft.FeatureManagement. Voici un exemple montrant comment écouter la source d’activité de gestion des fonctionnalités et ajouter un rappel lorsqu’une fonctionnalité est évaluée.

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.
        }
    }
});

Pour plus d’informations, consultez Collecter une trace distribuée.

Éditeur Application Insights Telemetry

Le package Microsoft.FeatureManagement.Telemetry.ApplicationInsights fournit un éditeur de données de télémétrie intégré qui envoie des données d’évaluation des indicateurs de fonctionnalité à Application Insights. Pour tirer parti de cela, ajoutez une référence au package et inscrivez l’éditeur de données de télémétrie Application Insights, comme indiqué ci-dessous.

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

Le package Microsoft.FeatureManagement.Telemetry.ApplicationInsights fournit un initialiseur de télémétrie qui ajoute automatiquement des balises TargetingId à tous les événements afin que les événements puissent être liés aux évaluations des indicateurs. Pour utiliser l’initialiseur de télémétrie TargetingTelemetryInitializer, ajoutez-le dans la collection de services de l’application.

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

Remarque

Pour vous assurer que TargetingTelemetryInitializer fonctionne comme prévu, le TargetingHttpContextMiddleware décrit ci-dessous doit être utilisé.

Pour activer la persistance du contexte de ciblage dans l’activité actuelle, vous pouvez utiliser le TargetingHttpContextMiddleware.

app.UseMiddleware<TargetingHttpContextMiddleware>();

Vous trouverez un cas pratique de son utilisation dans l’exemple VariantAndTelemetryDemo.

Prérequis

Pour permettre le bon fonctionnement de cet éditeur de télémétrie, Application Insights doit être configuré et inscrit au préalable en tant que service d’application. Par exemple, cela est effectué ici dans l’exemple d’application.

Cet éditeur de données de télémétrie suppose qu’Application Insights est déjà configuré et inscrit en tant que service d’application.

Mise en cache

L’état de la fonctionnalité est fourni par le système IConfiguration. N’importe quelle mise en cache et mise à jour dynamique est censée être gérée par les fournisseurs de configuration. Le gestionnaire de fonctionnalités demande à IConfiguration la dernière valeur de l’état d’une fonctionnalité chaque fois qu’une fonctionnalité est évaluée pour être activée.

Instantané

Il existe des scénarios qui nécessitent que l’état d’une fonctionnalité reste cohérent pendant la durée de vie d’une requête. Les valeurs retournées par le IFeatureManager standard peuvent changer si la source IConfiguration à partir de laquelle il effectue l’extraction est mise à jour pendant la requête. Cela peut être évité à l’aide de IFeatureManagerSnapshot. IFeatureManagerSnapshot peut être récupéré de la même manière que IFeatureManager. IFeatureManagerSnapshot implémente l’interface de IFeatureManager, mais elle met en cache le premier état évalué d’une fonctionnalité pendant une requête et retourne le même état d’une fonctionnalité pendant sa durée de vie.

Fournisseurs de fonctionnalités personnalisés

L’implémentation d’un fournisseur de fonctionnalités personnalisé permet aux développeurs d’extraire des indicateurs de fonctionnalités à partir de sources telles qu’une base de données ou un service de gestion des fonctionnalités. Le fournisseur de fonctionnalités inclus utilisé par défaut extrait les indicateurs de fonctionnalités du système de configuration de .NET Core. Cela permet de définir des fonctionnalités dans un fichier appsettings.json ou dans des fournisseurs de configuration tels qu’Azure App Configuration. Ce comportement peut être remplacé pour fournir un contrôle complet de l’emplacement à partir duquel les définitions de fonctionnalités sont lues.

Pour personnaliser le chargement des définitions de fonctionnalités, vous devez implémenter l’interface IFeatureDefinitionProvider.

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

    IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync();
}

Pour utiliser une implémentation de IFeatureDefinitionProvider, elle doit être ajoutée à la collection de services avant d’ajouter la gestion des fonctionnalités. L'exemple suivant ajoute une implémentation de IFeatureDefinitionProvider appelée InMemoryFeatureDefinitionProvider.

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

Étapes suivantes

Pour découvrir comment utiliser des indicateurs de fonctionnalité dans vos applications, passez aux guides de démarrage rapide suivants.

Pour découvrir comment utiliser des filtres de fonctionnalités, passez aux tutoriels suivants.

Pour découvrir comment exécuter des expériences avec des indicateurs de fonctionnalité de variante, passez au tutoriel suivant.