Gestione delle funzionalità .NET
La libreria di gestione delle funzionalità .NET consente di sviluppare ed esporre funzionalità dell'applicazione in base ai flag di funzionalità. Una volta sviluppata una nuova funzionalità, molte applicazioni hanno requisiti speciali, ad esempio relativamente a quando la funzionalità deve essere abilitata e in quali condizioni. Questa libreria consente di definire queste relazioni e si integra anche in criteri di codice .NET comuni per consentire l'esposizione di queste funzionalità.
I flag di funzionalità consentono alle applicazioni .NET e ASP.NET Core di attivare o disattivare dinamicamente le funzionalità. Gli sviluppatori possono usare flag di funzionalità in casi d'uso semplici, ad esempio istruzioni condizionali, o in scenari più avanzati, ad esempio l'aggiunta condizionale di route o filtri MVC. I flag di funzionalità si basano sul sistema di configurazione .NET Core. Qualsiasi provider di configurazione .NET Core è in grado di fungere da backbone per i flag di funzionalità.
Ecco alcuni dei vantaggi dell'uso della libreria di gestione delle funzionalità .NET:
Una convenzione comune per la gestione delle funzionalità
Bassa barriera all'ingresso
- Basato su
IConfiguration
- Supporta la configurazione del flag di funzionalità file JSON
- Basato su
Gestione della durata dei flag di funzionalità
- I valori di configurazione possono cambiare in tempo reale; i flag di funzionalità possono essere coerenti nell'intera richiesta
Scenari semplici e complessi trattati
- Attivare/disattivare le funzionalità tramite il file di configurazione dichiarativo
- Surface diverse varianti di una funzionalità a utenti diversi
- Valutare dinamicamente lo stato della funzionalità in base alla chiamata al server
Estensioni API per ASP.NET Core e framework MVC
- Definizione dei percorsi di trasferimento
- Filtri
- Attributi azione
La libreria di gestione delle funzionalità .NET è open source. Per altre informazioni, visitare il repository GitHub.
Flag di funzionalità
I flag di funzionalità possono essere abilitati o disabilitati. Lo stato di un flag può essere reso condizionale tramite l'uso di filtri di funzionalità.
Filtri di funzionalità
I filtri di funzionalità definiscono uno scenario per il momento in cui è necessario abilitare una funzionalità. Quando una funzionalità viene valutata come attivata o disattivata, il relativo elenco di filtri di funzionalità viene attraversato fino a quando uno dei filtri non determina l'abilitazione della funzionalità. A questo punto, attraversamento attraverso i filtri di funzionalità si arresta. Se nessun filtro di funzionalità indica che la funzionalità deve essere abilitata, viene considerata disabilitata.
Ad esempio, è possibile progettare un filtro di funzionalità del browser Microsoft Edge. Questo filtro di funzionalità attiverà tutte le funzionalità associate a finché una richiesta HTTP proviene da Microsoft Edge.This feature filter would activate any features it is attached to long as a http request is coming from Microsoft Edge.
Configurazione del flag di funzionalità
Il sistema di configurazione di .NET Core viene usato per determinare lo stato dei flag di funzionalità. La base di questo sistema è IConfiguration
. È possibile usare qualsiasi provider per IConfiguration
come provider di stato della funzionalità per la libreria dei flag di funzionalità. Questo sistema consente scenari che vanno da appsettings.json a Configurazione app di Azure e altro ancora.
Dichiarazione dei flag di funzionalità
La libreria di gestione delle funzionalità supporta appsettings.json come origine del flag di funzionalità poiché è un provider per il sistema IConfiguration
di .NET Core. I flag di funzionalità vengono dichiarati tramite Microsoft Feature Management schema
. Questo schema è indipendente dal linguaggio di origine ed è supportato in tutte le librerie di gestione delle funzionalità Microsoft.
L'esempio seguente dichiara i flag di funzionalità in un file 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 sezione feature_management
del documento JSON viene usata per convenzione per caricare le impostazioni dei flag di funzionalità. Gli oggetti flag di funzionalità devono essere elencati nell'array feature_flags
nella sezione feature_management
. Nella sezione precedente si noterà che sono state fornite tre diverse funzionalità. Un flag di funzionalità ha proprietà id
e enabled
. id
è il nome utilizzato per identificare il flag di funzionalità e farvi riferimento. La proprietà enabled
specifica lo stato abilitato del flag di funzionalità. Una funzionalità è OFF se enabled
è falso. Se enabled
è vero, lo stato della funzionalità dipende da conditions
. Se non conditions
sono presenti , la funzionalità è attivata. Se sono conditions
presenti e vengono soddisfatti, la funzionalità è ON. Se sono presenti conditions
e non vengono soddisfatti, la funzionalità è OFF. La proprietà conditions
dichiara le condizioni utilizzate per abilitare dinamicamente la funzionalità. Le funzionalità definiscono i relativi filtri di funzionalità nell'array client_filters
. FeatureV
specifica un filtro di funzionalità denominato Microsoft.TimeWindow
. Questo filtro è un esempio di filtro di funzionalità configurabile. Nell'esempio è possibile osservare che il filtro ha una proprietà Parameters
. Questa proprietà viene utilizzata per configurare il filtro. In questo caso, vengono configurati gli orari di inizio e fine per la funzionalità da attivare.
Avanzate: l'utilizzo dei due punti ':' non è consentito nei nomi dei flag di funzionalità.
RequirementType
La proprietà requirement_type
di conditions
viene utilizzata per determinare se i filtri devono usare la logica Any
o All
durante la valutazione dello stato di una funzionalità. Se requirement_type
non è specificato, il valore predefinito è Any
.
Any
significa che, per abilitare la funzionalità, è necessario che un solo filtro venga valutato come vero.All
indica che ogni filtro deve essere valutato come vero per abilitare la funzionalità.
Un oggetto requirement_type
di All
modifica l'attraversamento. In primo luogo, se non è presente alcun filtro, la funzionalità è disabilitata. Se sono presenti filtri, i filtri di funzionalità vengono quindi attraversati fino a quando uno dei filtri non decide che la funzionalità deve essere disabilitata. Se nessun filtro indica che la funzionalità deve essere disabilitata, viene considerata abilitata.
{
"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"
}
}
]
}
}
In questo esempio, FeatureW
specifica un requirement_type
valore di All
, ovvero tutti i relativi filtri devono restituire true per abilitare la funzionalità. In questo caso, la funzionalità è abilitata per il 50% degli utenti durante l'intervallo di tempo specificato.
Schema di gestione delle funzionalità .NET
Nelle versioni precedenti lo schema primario per la libreria di gestione delle funzionalità era .NET feature management schema
. A partire dalla versione 4.0.0, le nuove funzionalità, incluse le varianti e i dati di telemetria, non sono supportate per lo schema di gestione delle funzionalità .NET.
Nota
Se è presente una dichiarazione di flag di funzionalità che è possibile trovare in entrambe le sezioni feature_management
e FeatureManagement
, verrà adottata quella della sezione feature_management
.
Consumo
La forma di base di gestione delle funzionalità consiste nel verificare se un flag di funzionalità è abilitato ed eseguire azioni in base al risultato. Questo controllo viene eseguito tramite il IVariantFeatureManager
metodo del IsEnabledAsync
.
…
IVariantFeatureManager featureManager;
…
if (await featureManager.IsEnabledAsync("FeatureX"))
{
// Do something
}
Registrazione del servizio
La gestione delle funzionalità si basa sull'inserimento delle dipendenze di .NET Core. È possibile registrare i servizi di gestione di funzionalità usando le convenzioni standard.
using Microsoft.FeatureManagement;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddFeatureManagement();
}
}
Per impostazione predefinita, la gestione funzionalità recupera la configurazione dei flag di funzionalità dalla sezione "FeatureManagement" dei dati di configurazione di .NET Core. Se la sezione "FeatureManagement" non esiste, la configurazione viene considerata vuota.
Nota
È anche possibile specificare che la configurazione del flag di funzionalità deve essere recuperata da una sezione di configurazione differente passando la sezione a AddFeatureManagement
. L'esempio seguente indica invece la lettura da un'altra sezione chiamata "MyFeatureFlags":
services.AddFeatureManagement(configuration.GetSection("MyFeatureFlags"));
Inserimento delle dipendenze
Quando si usa la libreria di gestione delle funzionalità con MVC, è possibile ottenere IVariantFeatureManager
tramite l'inserimento delle dipendenze.
public class HomeController : Controller
{
private readonly IVariantFeatureManager _featureManager;
public HomeController(IVariantFeatureManager featureManager)
{
_featureManager = featureManager;
}
}
Servizi di gestione delle funzionalità con ambito
Il metodo AddFeatureManagement
aggiunge i servizi di gestione delle funzionalità come singleton all'interno dell'applicazione, ma esistono scenari in cui potrebbe essere necessario aggiungere i servizi di gestione delle funzionalità come servizi con ambito. Ad esempio, gli utenti possono voler usare filtri di funzionalità che utilizzano servizi con ambito per informazioni di contesto. In questo caso, è consigliabile usare il metodo AddScopedFeatureManagement
. Questo metodo garantisce che i servizi di gestione delle funzionalità, inclusi i filtri delle funzionalità, vengano aggiunti come servizi con ambito.
services.AddScopedFeatureManagement();
Integrazione ASP.NET Core
La libreria di gestione delle funzionalità offre funzionalità in ASP.NET Core e MVC per abilitare scenari comuni di flag di funzionalità nelle applicazioni Web. Queste funzionalità sono disponibili facendo riferimento al pacchetto NuGet Microsoft.FeatureManagement.AspNetCore.
Controller e azioni
Il controller e le azioni MVC possono richiedere l'abilitazione di una determinata funzionalità, o di un qualsiasi elenco di funzionalità, per l'esecuzione. Questo requisito può essere eseguito usando un FeatureGateAttribute
oggetto , disponibile nello spazio dei Microsoft.FeatureManagement.Mvc
nomi .
[FeatureGate("FeatureX")]
public class HomeController : Controller
{
…
}
In questo esempio, l'oggetto HomeController
viene gestito da "FeatureX". "FeatureX" deve essere abilitato prima di poter eseguire qualsiasi azione contenuta in HomeController
.
[FeatureGate("FeatureX")]
public IActionResult Index()
{
return View();
}
In questo esempio, l'azione MVC richiede l'abilitazione Index
di "FeatureX" prima che possa essere eseguita.
Gestione delle azioni disabilitata
Quando un controller o un'azione MVC viene bloccata perché nessuna delle funzionalità specificate è abilitata, viene richiamato un oggetto registrato IDisabledFeaturesHandler
. Per impostazione predefinita, viene registrato un gestore minimalista che restituisce HTTP 404. Questo gestore può essere sottoposto a override usando quando IFeatureManagementBuilder
si registrano flag di funzionalità.
public interface IDisabledFeaturesHandler
{
Task HandleDisabledFeature(IEnumerable<string> features, ActionExecutingContext context);
}
Visualizza
Nelle viste MVC, è possibile usare i tag <feature>
per eseguire il rendering condizionato del contenuto in base allo stato di attivazione del flag di funzionalità o dell'attivazione di una variante specifica di una funzionalità. Per altre informazioni, vedere la sezione sulle varianti.
<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>
È anche possibile negare la valutazione dell'helper tag per visualizzare il contenuto quando una funzionalità o un set di funzionalità sono disabilitate. negate="true"
Impostando nell'esempio seguente, il rendering del contenuto viene eseguito solo se FeatureX
è disabilitato.
<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>
Il tag <feature>
può fare riferimento a più funzionalità/varianti specificando un elenco delimitato da virgole di funzionalità/varianti nell'attributo 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>
Nota
Se variant
è specificato, è necessario specificare una sola funzionalità.
Per impostazione predefinita, per il rendering del tag di funzionalità è necessario abilitare tutte le funzionalità elencate. Questo comportamento può essere sottoposto a override aggiungendo l'attributo requirement
come illustrato nell'esempio seguente.
Nota
Se un requirement
di And
viene usato insieme a variant
, verrà generato un errore, poiché non è mai possibile assegnare più varianti.
<feature name="FeatureX,FeatureY" requirement="Any">
<p>This can only be seen if either 'FeatureX' or 'FeatureY' or both are enabled.</p>
</feature>
Il tag <feature>
richiede il funzionamento di un helper tag. Per usare il tag, aggiungere l'helper tag di gestione delle funzionalità al file ViewImports.cshtml .
@addTagHelper *, Microsoft.FeatureManagement.AspNetCore
Filtri MVC
I filtri di azione MVC possono essere configurati per l'esecuzione condizionale in base allo stato di una funzionalità. Questa operazione viene eseguita registrando i filtri MVC in modo compatibile con le funzionalità.
La pipeline di gestione delle funzionalità supporta filtri di azione MVC asincroni, che implementano IAsyncActionFilter
.
services.AddMvc(o =>
{
o.Filters.AddForFeature<SomeMvcFilter>("FeatureX");
});
Questo codice aggiunge un filtro MVC denominato SomeMvcFilter
. Questo filtro viene attivato solo all'interno della pipeline MVC se "FeatureX" è attivato.
Razor Pages
Le pagine Razor MVC possono richiedere l'abilitazione di una determinata funzionalità, o di un qualsiasi elenco di funzionalità, per l'esecuzione. Questo requisito può essere aggiunto usando un FeatureGateAttribute
oggetto , disponibile nello spazio dei Microsoft.FeatureManagement.Mvc
nomi .
[FeatureGate("FeatureX")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Il codice precedente configura una pagina Razor per richiedere l'abilitazione di "FeatureX". Se la funzionalità non è abilitata, la pagina genera un risultato HTTP 404 (NotFound).
Se usato nelle pagine Razor, FeatureGateAttribute
deve essere inserito nel tipo di gestore di pagina. Non può essere inserito in singoli metodi del gestore.
Compilazione dell'applicazione
La libreria di gestione delle funzionalità può essere usata per aggiungere rami dell'applicazione e middleware che vengono eseguiti in modo condizionale in base allo stato della funzionalità.
app.UseMiddlewareForFeature<ThirdPartyMiddleware>("FeatureX");
Con la chiamata precedente, l'applicazione aggiunge un componente middleware visualizzato solo nella pipeline di richiesta se la funzionalità "FeatureX" è abilitata. Se la funzionalità è abilitata/disabilitata durante il runtime, la pipeline middleware può essere modificata in modo dinamico.
Ciò produce la capacità più generica di creare rami nell'intera applicazione in base alla funzionalità.
app.UseForFeature(featureName, appBuilder =>
{
appBuilder.UseMiddleware<T>();
});
Implementazione di un filtro di funzionalità
La creazione di un filtro di funzionalità consente di abilitare le funzionalità in base ai criteri definiti dall'utente. Per implementare un filtro di funzionalità, è necessario implementare l'interfaccia IFeatureFilter
. IFeatureFilter
ha un solo metodo denominato EvaluateAsync
. Quando una funzionalità specifica che può essere abilitata per un filtro di funzionalità, viene chiamato il metodo EvaluateAsync
. Se EvaluateAsync
restituisce true
, significa che la funzionalità deve essere abilitata.
Il frammento di codice seguente illustra come aggiungere un filtro di funzionalità MyCriteriaFilter
personalizzato.
services.AddFeatureManagement()
.AddFeatureFilter<MyCriteriaFilter>();
I filtri delle funzionalità vengono registrati chiamando AddFeatureFilter<T>
sull'oggetto IFeatureManagementBuilder
restituito da AddFeatureManagement
. Questi filtri di funzionalità hanno accesso ai servizi esistenti all'interno della raccolta di servizi usata per aggiungere flag di funzionalità. È possibile usare l'inserimento delle dipendenze per recuperare questi servizi.
Nota
Quando si fa riferimento ai filtri nelle impostazioni del flag di funzionalità (ad esempio, appsettings.json), la parte Filtro del nome del tipo deve essere omessa. Per altre informazioni, vedere la sezione Filter Alias Attribute
.
Filtri di funzionalità con parametri
Alcuni filtri di funzionalità richiedono parametri per decidere se una funzionalità deve essere attivata o meno. Ad esempio, un filtro di funzionalità del browser può attivare una funzionalità per un determinato set di browser. Potrebbe essere necessario che i browser Edge e Chrome abilitino una funzionalità, mentre per Firefox non è così. A tale scopo, è possibile progettare un filtro di funzionalità per prevedere parametri. Questi parametri verranno specificati nella configurazione della funzionalità e nel codice sarebbero accessibili tramite il parametro FeatureFilterEvaluationContext
di 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
ha una proprietà denominata Parameters
. Questi parametri rappresentano una configurazione non elaborata che il filtro delle funzionalità può usare per decidere come valutare se la funzionalità deve essere abilitata o meno. Per usare nuovamente il filtro delle funzionalità del browser come esempio, il filtro può usare Parameters
per estrarre un set di browser consentiti che verrebbero specificati per la funzionalità e controllare se la richiesta viene inviata da uno di questi browser.
[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
}
}
Attributo alias filtro
Quando un filtro di funzionalità viene registrato per un flag di funzionalità, l'alias usato nella configurazione è il nome del tipo di filtro delle funzionalità con il suffisso Filtro, se presente, rimosso. Ad esempio, si farà riferimento a MyCriteriaFilter
come MyCriteria nella configurazione.
"MyFeature": {
"EnabledFor": [
{
"Name": "MyCriteria"
}
]
}
Questo nome può essere sottoposto a override tramite .FilterAliasAttribute
Un filtro di funzionalità può essere decorato con questo attributo per dichiarare il nome che deve essere usato nella configurazione per fare riferimento a questo filtro di funzionalità all'interno di un flag di funzionalità.
Filtri delle funzionalità mancanti
Se una funzionalità è configurata per essere abilitata per un filtro di funzionalità specifico e tale filtro di funzionalità non viene registrato, viene generata un'eccezione quando viene valutata la funzionalità. L'eccezione può essere disabilitata usando le opzioni di gestione delle funzionalità.
services.Configure<FeatureManagementOptions>(options =>
{
options.IgnoreMissingFeatureFilters = true;
});
Uso di HttpContext
I filtri di funzionalità possono valutare se una funzionalità deve essere abilitata in base alle proprietà di una richiesta HTTP. Questa operazione viene eseguita esaminando il contesto HTTP. Un filtro di funzionalità può ottenere un riferimento al contesto HTTP ottenendo un oggetto IHttpContextAccessor
tramite l'inserimento delle dipendenze.
public class BrowserFilter : IFeatureFilter
{
private readonly IHttpContextAccessor _httpContextAccessor;
public BrowserFilter(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
}
}
IHttpContextAccessor
deve essere aggiunto al contenitore di inserimento delle dipendenze all'avvio perché sia disponibile. Può essere registrato in IServiceCollection
utilizzando il metodo seguente.
public void ConfigureServices(IServiceCollection services)
{
…
services.AddHttpContextAccessor();
…
}
Avanzate: IHttpContextAccessor
/HttpContext
non deve essere usato nei componenti Razor delle app Blazor sul lato server. L'approccio consigliato per passare il contesto HTTP nelle app Blazor consiste nel copiare i dati in un servizio con ambito. Per le app Blazor, AddScopedFeatureManagement
deve essere usato per registrare i servizi di gestione delle funzionalità. Per altre informazioni, vedere la sezione Scoped Feature Management Services
.
Fornire un contesto per la valutazione delle funzionalità
Nelle applicazioni console non esiste alcun contesto ambientale, ad esempio HttpContext
, che i filtri di funzionalità possono acquisire e usare per verificare se una funzionalità deve essere attivata o disattivata. In questo caso, le applicazioni devono fornire un oggetto che rappresenta un contesto nel sistema di gestione delle funzionalità per l'uso da parte dei filtri delle funzionalità. Questo contesto può essere fornito usando IVariantFeatureManager.IsEnabledAsync<TContext>(string featureName, TContext appContext)
. È possibile usare l'oggetto appContext fornito alla gestione funzionalità dai filtri delle funzionalità per valutare lo stato di una funzionalità.
MyAppContext context = new MyAppContext
{
AccountId = current.Id;
}
if (await featureManager.IsEnabledAsync(feature, context))
{
…
}
Filtri delle funzionalità contestuali
I filtri delle funzionalità contestuali implementano l'interfaccia IContextualFeatureFilter<TContext>
. Questi filtri di funzionalità speciali possono sfruttare il contesto passato quando viene chiamato IVariantFeatureManager.IsEnabledAsync<TContext>
. Il parametro di tipo TContext
in IContextualFeatureFilter<TContext>
descrive il tipo di contesto che il filtro è in grado di gestire. Ciò consente allo sviluppatore di un filtro di funzionalità contestuale di descrivere ciò che è necessario per coloro che desiderano usarlo. Poiché ogni tipo è un discendente dell'oggetto, è possibile chiamare un filtro che implementi IContextualFeatureFilter<object>
per qualsiasi contesto specificato. Per illustrare un esempio di filtro di funzionalità contestuale più specifico, prendere in considerazione una funzionalità abilitata se un account si trova in un elenco configurato di account abilitati.
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
}
}
È possibile notare che AccountIdFilter
richiede che sia disponibile un oggetto che implementa IAccountContext
per poter valutare lo stato di una funzionalità. Quando si usa questo filtro di funzionalità, il chiamante deve assicurarsi che l'oggetto passato implementi IAccountContext
.
Nota
È possibile implementare un'unica interfaccia di filtro funzionalità solo da un singolo tipo. Se si tenta di aggiungere un filtro di funzionalità che implementa più di un'unica interfaccia filtro funzionalità, viene restituito un oggetto ArgumentException
.
Uso di filtri contestuali e non contestuali con lo stesso alias
I filtri di IFeatureFilter
e IContextualFeatureFilter
possono condividere lo stesso alias. In particolare, è possibile avere un alias di filtro condiviso da 0 o 1 IFeatureFilter
e 0 o N IContextualFeatureFilter<ContextType>
, purché sia presente al massimo un filtro applicabile per ContextType
.
Il passaggio seguente descrive il processo di selezione di un filtro quando i filtri contestuali e non contestuali con lo stesso nome vengono registrati in un'applicazione.
Si supponga di avere un filtro non contestuale denominato FilterA
e due filtri contestuali FilterB
e FilterC che accettano rispettivamente contesti TypeB
e TypeC
. Tutti e tre i filtri condividono lo stesso alias SharedFilterName
.
È disponibile anche un flag di funzionalità MyFeature
che usa il filtro di funzionalità SharedFilterName
nella relativa configurazione.
Se vengono registrati tutti e tre i filtri:
- Quando si chiama IsEnabledAsync("MyFeature"), viene usato
FilterA
per valutare il flag di funzionalità. - Quando si chiama IsEnabledAsync("MyFeature", context), se il tipo di contesto è
TypeB
, viene usatoFilterB
. Se il tipo di contesto èTypeC
, viene usatoFilterC
. - Quando si chiama IsEnabledAsync("MyFeature", context), se il tipo di contesto è
TypeF
, viene usatoFilterA
.
Filtri di funzionalità predefiniti
Esistono alcuni filtri di funzionalità disponibili con il pacchetto Microsoft.FeatureManagement
: PercentageFilter
, TimeWindowFilter
, ContextualTargetingFilter
e TargetingFilter
. Tutti i filtri, ad eccezione di TargetingFilter
, vengono aggiunti automaticamente quando la gestione delle funzionalità viene registrata dal metodo AddFeatureManagement
. Viene TargetingFilter
aggiunto con il WithTargeting
metodo descritto in dettaglio nella Targeting
sezione .
Ognuno dei filtri di funzionalità predefiniti ha i propri parametri. Ecco l'elenco dei filtri delle funzionalità insieme agli esempi.
Microsoft.Percentage
Questo filtro offre la possibilità di abilitare una funzionalità in base a una percentuale impostata.
"EnhancedPipeline": {
"EnabledFor": [
{
"Name": "Microsoft.Percentage",
"Parameters": {
"Value": 50
}
}
]
}
Microsoft.TimeWindow
Questo filtro offre la possibilità di abilitare una funzionalità in base a una finestra temporale. Se viene specificato solo End
, la funzionalità viene considerata fino a quel momento. Se viene specificato solo Start
, la funzionalità viene considerata in tutti i punti dopo tale periodo.
"EnhancedPipeline": {
"EnabledFor": [
{
"Name": "Microsoft.TimeWindow",
"Parameters": {
"Start": "Wed, 01 May 2019 13:59:59 GMT",
"End": "Mon, 01 Jul 2019 00:00:00 GMT"
}
}
]
}
L'intervallo di tempo può essere configurato per la ricorsione periodica. Può essere utile per gli scenari in cui potrebbe essere necessario attivare una funzionalità durante un periodo di traffico basso o elevato di un giorno o di determinati giorni di una settimana. Per espandere la singola finestra temporale in intervalli di tempo ricorrenti, è necessario specificare la regola di ricorrenza nel parametro Recurrence
.
Nota
Start
e End
devono essere entrambi specificati per abilitare 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"
}
}
}
}
]
}
Le impostazioni Recurrence
sono costituite da due parti: Pattern
(con quale frequenza si ripete l'intervallo di tempo) e Range
(per quanto tempo il criterio di ricorrenza viene ripetuto).
Criterio ricorrenza
Esistono due possibili tipi di criteri di ricorrenza: Daily
e Weekly
. Ad esempio, un intervallo di tempo potrebbe ripetere "ogni giorno", "ogni tre giorni", "ogni lunedì" o "ogni altro venerdì".
A seconda del tipo, alcuni campi di Pattern
sono obbligatori, facoltativi o ignorati.
Daily
Il criterio di ricorrenza giornaliera determina la ripetizione dell'intervallo di tempo in base a un numero di giorni tra ogni occorrenza.
Proprietà Pertinenza Descrizione Tipo Obbligatorio Deve essere impostato su Daily
.Intervallo Facoltativo Specifica il numero di giorni tra ciascuna occorrenza. Il valore predefinito è 1. Weekly
Il criterio di ricorrenza settimanale fa sì che l'intervallo di tempo si ripeta nello stesso giorno o negli stessi giorni della settimana, in base al numero di settimane tra ogni set di occorrenze.
Proprietà Pertinenza Descrizione Tipo Obbligatorio Deve essere impostato su Weekly
.DaysOfWeek Richiesto Specifica in quali giorni della settimana si verifica l'evento. Intervallo Facoltativo Specifica il numero di settimane tra ciascuna serie di occorrenze. Il valore predefinito è 1. FirstDayOfWeek Facoltativo Specifica quale giorno viene considerato il primo giorno della settimana. Il valore predefinito è Sunday
.L'esempio seguente ripete l'intervallo di tempo ogni lunedì e martedì
"Pattern": { "Type": "Weekly", "Interval": 2, "DaysOfWeek": ["Monday", "Tuesday"] }
Nota
Start
deve essere una prima occorrenza valida che si adatta al criterio di ricorrenza. Inoltre, la durata dell'intervallo di tempo non può essere più lunga della frequenza con cui si verifica. Ad esempio, non è valido avere un intervallo di 25 ore ogni giorno.
Intervallo ricorrenza
Esistono tre possibili tipi di intervallo di ricorrenza: NoEnd
, EndDate
e Numbered
.
NoEnd
L'intervallo
NoEnd
fa sì che la ricorrenza venga eseguita per un periodo illimitato.Proprietà Pertinenza Descrizione Tipo Obbligatorio Deve essere impostato su NoEnd
.EndDate
L'intervallo
EndDate
fa sì che l'intervallo di tempo si verifichi in tutti i giorni che soddisfano il criterio applicabile fino alla data di fine.Proprietà Pertinenza Descrizione Tipo Obbligatorio Deve essere impostato su EndDate
.EndDate Richiesto Specifica l'ora della data in cui interrompere l'applicazione del criterio. Fino a quando l'ora di inizio dell'ultima occorrenza cade prima della data di fine, l'ora di fine di tale occorrenza può essere estesa. L'esempio seguente ripeterà l'intervallo di tempo ogni giorno fino all'ultima occorrenza del 1° aprile 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
L'intervallo
Numbered
fa sì che l'intervallo di tempo si verifichi per un numero fisso di volte (in base al criterio).Proprietà Pertinenza Descrizione Tipo Obbligatorio Deve essere impostato su Numbered
.NumberOfOccurrences Richiesto Specifica il numero di occorrenze. L'esempio seguente ripeterà l'intervallo di tempo lunedì e martedì fino a quando non saranno presenti tre occorrenze, che si verificano rispettivamente il 1° aprile(lun), il 2 aprile(mar) e l'8 aprile (lun).
"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 } }
Per creare una regola di ricorrenza, è necessario specificare sia Pattern
che Range
. Qualsiasi tipo di criterio può funzionare con qualsiasi tipo di intervallo.
Avanzate: l'offset del fuso orario della proprietà Start
viene applicato alle impostazioni di ricorrenza.
Microsoft.Targeting
Questo filtro offre la possibilità di abilitare una funzionalità per un pubblico di destinazione. Nella sezione di destinazione è illustrata una spiegazione approfondita della destinazione. I parametri di filtro includono un oggetto Audience
che descrive utenti, gruppi, utenti/gruppi esclusi e una percentuale predefinita della base di utenti che deve avere accesso alla funzionalità. Ogni oggetto gruppo elencato nella sezione Groups
deve specificare anche la percentuale di accesso ai membri del gruppo. Se nella sezione Exclusion
viene specificato un utente, sia direttamente che se l'utente si trova in un gruppo escluso, la funzionalità è disabilitata. In caso contrario, se un utente viene specificato direttamente nella sezione Users
, se l'utente si trova nella percentuale di implementazione inclusa di uno dei gruppi o se rientra nella percentuale di implementazione predefinita, tale utente avrà la funzionalità abilitata.
"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"
]
}
}
}
}
]
}
Spazi dei nomi alias del filtro di funzionalità
Tutti gli alias di filtro di funzionalità predefiniti si trovano nello spazio dei nomi del filtro di funzionalità Microsoft
. Questo spazio dei nomi consente di evitare conflitti con altri filtri di funzionalità che possono condividere lo stesso alias. I segmenti di uno spazio dei nomi dei filtri di funzionalità vengono suddivisi in base al carattere '.'. È possibile fare riferimento a un filtro di funzionalità tramite il relativo alias completo, ad esempio Microsoft.Percentage
o dall'ultimo segmento che, nel caso di Microsoft.Percentage
, è Percentage
.
Selezione della destinazione
La destinazione è una strategia di gestione delle funzionalità che consente agli sviluppatori di implementare progressivamente nuove funzionalità alla base degli utenti. La strategia si basa sul concetto di destinazione di un set di utenti noto come gruppo di destinatari. Un gruppo di destinatari è costituito da utenti, gruppi specifici, utenti/gruppi esclusi e una percentuale designata dell'intera base di utenti. I gruppi inclusi nel gruppo di destinatari possono essere suddivisi ulteriormente in percentuali dei membri totali.
I passaggi seguenti illustrano un esempio di implementazione progressiva per una nuova funzionalità "Beta":
- Ai singoli utenti Jeff e Alicia viene concesso l'accesso alla versione Beta
- Un altro utente, Mark, chiede di acconsentire esplicitamente ed è incluso.
- Il venti percento di un gruppo noto come utenti "Ring1" è incluso nella Beta.
- Il numero di utenti "Ring1" inclusi nella Beta è salito fino al 100%.
- Il 5% della base di utenti è incluso nella versione Beta.
- La percentuale di implementazione viene incrementata fino al 100% e la funzionalità viene implementata completamente.
Questa strategia per l'implementazione di una funzionalità è integrata nella libreria tramite il filtro di funzionalità Microsoft.Targeting incluso.
Destinazione in un'applicazione Web
Un'applicazione Web di esempio che usa il filtro di funzionalità di destinazione è disponibile nel progetto di esempio FeatureFlagDemo.
Per iniziare a usare TargetingFilter
in un'applicazione, è necessario aggiungerlo alla raccolta di servizi dell'applicazione esattamente come qualsiasi altro filtro di funzionalità. A differenza di altri filtri predefiniti, TargetingFilter
si basa su un altro servizio da aggiungere alla raccolta di servizi dell'applicazione. Tale servizio è un oggetto ITargetingContextAccessor
.
Microsoft.FeatureManagement.AspNetCore
fornisce un'implementazione predefinita di ITargetingContextAccessor
che estrae le informazioni di destinazione da un HttpContext
di una richiesta. È possibile usare la funzione di accesso del contesto di destinazione predefinita quando si configura la destinazione usando l'overload non generico WithTargeting
in IFeatureManagementBuilder
.
La funzione di accesso del contesto di destinazione predefinita e TargetingFilter
viene registrata chiamando WithTargeting
in IFeatureManagementBuilder
.
services.AddFeatureManagement()
.WithTargeting();
È anche possibile registrare un'implementazione personalizzata per ITargetingContextAccessor
e TargetingFilter
chiamando WithTargeting<T>
. Ecco un esempio di configurazione della gestione delle funzionalità in un'applicazione Web per usare TargetingFilter
con un'implementazione di ITargetingContextAccessor
denominata ExampleTargetingContextAccessor
.
services.AddFeatureManagement()
.WithTargeting<ExampleTargetingContextAccessor>();
ITargetingContextAccessor
Per usare TargetingFilter
in un'applicazione Web, è necessaria un'implementazione di ITargetingContextAccessor
. Questo requisito è dovuto al fatto che, quando viene eseguita una valutazione di destinazione, sono necessarie informazioni contestuali, ad esempio l'utente attualmente in fase di valutazione. Queste informazioni sono note come TargetingContext
. Applicazioni diverse possono estrarre queste informazioni da posizioni diverse. Alcuni esempi comuni di dove un'applicazione può eseguire il pull del contesto di destinazione sono il contesto HTTP della richiesta o un database.
Un esempio che estrae informazioni sul contesto di destinazione dal contesto HTTP dell'applicazione è DefaultHttpTargetingContextAccessor
fornito dal pacchetto Microsoft.FeatureManagement.AspNetCore
. Estrae le informazioni di destinazione da HttpContext.User
. UserId
le informazioni verranno estratte dal Identity.Name
campo e Groups
le informazioni verranno estratte dalle attestazioni di tipo Role
. Questa implementazione si basa sull'uso di IHttpContextAccessor
, illustrato qui.
Destinazione in un'applicazione console
Il filtro di destinazione si basa su un contesto di destinazione per valutare se una funzionalità deve essere attivata. Questo contesto di destinazione contiene informazioni quali l'utente attualmente in fase di valutazione e i gruppi in cui si trova l'utente. Nelle applicazioni console, in genere non è disponibile alcun contesto ambientale per il flusso di queste informazioni nel filtro di destinazione, pertanto deve essere passato direttamente quando viene chiamato FeatureManager.IsEnabledAsync
. Questo tipo di contesto è supportato tramite .ContextualTargetingFilter
Le applicazioni che devono spostare il contesto di destinazione nel gestore delle funzionalità devono usare questa opzione anziché TargetingFilter.
Poiché ContextualTargetingFilter
è IContextualTargetingFilter<ITargetingContext>
, un'implementazione di ITargetingContext
deve essere passata a IVariantFeatureManager.IsEnabledAsync
per poter valutare e attivare una funzionalità.
IVariantFeatureManager fm;
…
// userId and groups defined somewhere earlier in application
TargetingContext targetingContext = new TargetingContext
{
UserId = userId,
Groups = groups
};
await fm.IsEnabledAsync(featureName, targetingContext);
ContextualTargetingFilter
usa ancora l'alias di filtro di funzionalità Microsoft.Targeting, quindi la configurazione per questo filtro è coerente con quanto indicato in tale sezione.
Un esempio che usa ContextualTargetingFilter
in un'applicazione console è disponibile nel progetto di esempio TargetingConsoleApp.
Opzioni di valutazione di destinazione
Le opzioni sono disponibili per personalizzare la modalità di esecuzione della valutazione della destinazione in tutte le funzionalità. Queste opzioni possono essere configurate durante la configurazione della gestione delle funzionalità.
services.Configure<TargetingEvaluationOptions>(options =>
{
options.IgnoreCase = true;
});
Esclusione di destinazione
Quando si definisce un gruppo di destinatari, gli utenti e i gruppi possono essere esclusi dal gruppo di destinatari. L'esclusione è utile quando viene implementata una funzionalità a un gruppo di utenti, ma alcuni utenti o gruppi devono essere esclusi dall'implementazione. L'esclusione viene definita aggiungendo un elenco di utenti e gruppi alla proprietà Exclusion
del gruppo di destinatari.
"Audience": {
"Users": [
"Jeff",
"Alicia"
],
"Groups": [
{
"Name": "Ring0",
"RolloutPercentage": 100
}
],
"DefaultRolloutPercentage": 0
"Exclusion": {
"Users": [
"Mark"
]
}
}
Nell'esempio precedente la funzionalità è abilitata per gli utenti denominati Jeff
e Alicia
. È anche abilitata per gli utenti nel gruppo denominato Ring0
. Tuttavia, se l'utente è denominato Mark
, la funzionalità è disabilitata, indipendentemente dal fatto che si trovino nel gruppo Ring0
o meno. Le esclusioni hanno la priorità rispetto al resto del filtro di destinazione.
Varianti
Quando vengono aggiunte nuove funzionalità a un'applicazione, potrebbe verificarsi un momento in cui una funzionalità include differenti opzioni di progettazione proposte. Una soluzione comune per decidere una progettazione è una forma di test A/B, che implica la fornitura di una versione differente della funzionalità a differenti segmenti della base di utenti e la scelta di una versione in base all'interazione dell'utente. In questa libreria, la funzionalità è abilitata rappresentando differenti configurazioni di una funzionalità con varianti.
Le varianti consentono a un flag di funzionalità di diventare più di un semplice flag on/off. Una variante rappresenta un valore di un flag di funzionalità che può essere una stringa, un numero, un valore booleano o anche un oggetto di configurazione. Un flag di funzionalità che dichiara le varianti deve definire in quali circostanze deve essere usata ogni variante, descritta in modo più dettagliato nella sezione Allocazione varianti.
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; }
}
Recupero di varianti
Per ogni funzionalità, è possibile recuperare una variante usando il metodo IVariantFeatureManager
del 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
Dopo aver recuperato una variante, la configurazione di una variante può essere usata direttamente come oggetto IConfigurationSection
dalla proprietà Configuration
della variante. Un'altra opzione consiste nell'associare la configurazione a un oggetto usando il criterio di associazione di configurazione di .NET.
IConfigurationSection variantConfiguration = variant.Configuration;
MyFeatureSettings settings = new MyFeatureSettings();
variantConfiguration.Bind(settings);
La variante restituita dipende dall'utente attualmente in fase di valutazione e le informazioni vengono ottenute da un'istanza di TargetingContext
. Questo contesto può essere passato durante la chiamata GetVariantAsync
o può essere recuperato automaticamente da un'implementazione di ITargetingContextAccessor
se ne è registrato uno.
Dichiarazione dei flag di funzionalità delle varianti
Rispetto ai normali flag di funzionalità, i flag di funzionalità delle varianti hanno due proprietà aggiuntive: variants
e allocation
. La proprietà variants
è un array che contiene le varianti definite per questa funzionalità. La proprietà allocation
definisce la modalità di allocazione di queste varianti per la funzionalità. Come per dichiarare i normali flag di funzionalità, è possibile configurare flag di funzionalità delle varianti in un file JSON. Di seguito è riportato un esempio di flag di funzionalità delle varianti.
{
"feature_management": {
"feature_flags": [
{
"id": "MyVariantFeatureFlag",
"enabled": true,
"allocation": {
"default_when_enabled": "Small",
"group": [
{
"variant": "Big",
"groups": [
"Ring1"
]
}
]
},
"variants": [
{
"name": "Big"
},
{
"name": "Small"
}
]
}
]
}
}
Definizione di varianti
Ogni variante ha due proprietà: un nome e una configurazione. Il nome viene usato per fare riferimento a una variante specifica e la configurazione è il valore di tale variante. La configurazione può essere impostata usando la proprietà configuration_value
. configuration_value
è una configurazione inline che può essere una stringa, un numero, un valore booleano o un oggetto di configurazione. Se configuration_value
non viene specificato, la proprietà Configuration
della variante restituita sarà Null.
Un elenco di tutte le possibili varianti viene definito per ogni funzionalità nella proprietà variants
.
{
"feature_management": {
"feature_flags": [
{
"id": "MyVariantFeatureFlag",
"variants": [
{
"name": "Big",
"configuration_value": {
"Size": 500
}
},
{
"name": "Small",
"configuration_value": {
"Size": 300
}
}
]
}
]
}
}
Allocazione di varianti
Il processo di allocazione delle varianti di una funzionalità è determinato dalla proprietà allocation
della funzionalità.
"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"
}
]
L'impostazione allocation
di una funzionalità ha le proprietà seguenti:
Proprietà | Descrizione |
---|---|
default_when_disabled |
Specifica quale variante deve essere utilizzata quando viene richiesta una variante mentre la funzionalità viene considerata disabilitata. |
default_when_enabled |
Specifica quale variante deve essere utilizzata quando viene richiesta una variante mentre la funzionalità viene considerata abilitata e nessun'altra variante è stata assegnata all'utente. |
user |
Specifica una variante e un elenco di utenti a cui deve essere assegnata tale variante. |
group |
Specifica una variante e un elenco di gruppi. La variante verrà assegnata se l'utente si trova in almeno uno dei gruppi. |
percentile |
Specifica una variante e un intervallo percentuale in base al quale deve essere assegnata la percentuale calcolata dell'utente. |
seed |
Valore su cui si basano i calcoli percentuali per percentile . Il calcolo percentuale per un utente specifico sarà lo stesso in tutte le funzionalità se viene usato lo stesso valore seed . Se non viene specificato alcun valore seed , viene creato un valore di inizializzazione predefinito in base al nome della funzionalità. |
Nell'esempio precedente, se la funzionalità non è abilitata, il gestore delle funzionalità assegnerà la variante contrassegnata come default_when_disabled
all'utente corrente, in questo caso Small
.
Se la funzionalità è abilitata, il gestore delle funzionalità verificherà le allocazioni user
, group
e percentile
in tale ordine al fine di assegnare una variante. Per questo particolare esempio, se l'utente valutato è denominato Marsha
nel gruppo denominato Ring1
, o se l'utente si trova tra lo 0 e il 10° percentile, la variante specificata viene assegnata all'utente. In questo caso, tutti questi valori restituirebbero la variante Big
. Se nessuna di queste allocazioni corrisponde, all'utente viene assegnata la variante default_when_enabled
, ovvero Small
.
La logica di allocazione è simile al filtro di funzionalità Microsoft.Targeting, ma esistono alcuni parametri presenti nella destinazione che non sono nell'allocazione e viceversa. I risultati della destinazione e dell'allocazione non sono correlati.
Nota
Per consentire l'allocazione delle varianti di funzionalità, è necessario eseguire la registrazione ITargetingContextAccessor
chiamando il WithTargeting<T>
metodo .
Override dello stato abilitato con una variante
È possibile usare varianti per eseguire l'override dello stato abilitato di un flag di funzionalità. In questo modo, le varianti possono estendere la valutazione di un flag di funzionalità. Quando si chiama IsEnabled
su un flag con varianti, il gestore delle funzionalità verificherà se la variante assegnata all'utente corrente è configurata per eseguire l'override del risultato. Questa operazione viene eseguita usando la proprietà variante facoltativa status_override
. Per impostazione predefinita, questa proprietà è impostata su None
, il che significa che la variante non influisce sul fatto che il flag sia considerato abilitato o disabilitato. L'impostazione status_override
su Enabled
consente alla variante, se scelta, di eseguire l'override di un flag da abilitare. L'impostazione status_override
su Disabled
fornisce la funzionalità opposta, disabilitando quindi il flag quando viene scelta la variante. Non è possibile eseguire l'override di una funzionalità con stato enabled
di false
.
Se si usa un flag di funzionalità con varianti binarie, la proprietà status_override
può essere molto utile. Consente di continuare a usare API come IsEnabledAsync
e FeatureGateAttribute
nell'applicazione, sfruttando al tempo stesso le nuove funzionalità fornite con varianti, ad esempio allocazione percentile e seeding.
{
"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"
}
]
}
Nell'esempio precedente la funzionalità è sempre abilitata. Se l'utente corrente si trova nell'intervallo percentile calcolato compreso tra 10 e 20, viene restituita la variante On
. In caso contrario, viene restituita la variante Off
e, poiché status_override
è uguale a Disabled
, la funzionalità verrà ora considerata disabilitata.
Varianti nell'inserimento delle dipendenze
I flag di funzionalità varianti possono essere usati insieme all'inserimento delle dipendenze per visualizzare implementazioni differenti di un servizio per utenti differenti. Questa combinazione viene eseguita usando l'interfaccia IVariantServiceProvider<TService>
.
IVariantServiceProvider<IAlgorithm> algorithmServiceProvider;
...
IAlgorithm forecastAlgorithm = await algorithmServiceProvider.GetServiceAsync(cancellationToken);
Nel frammento di codice precedente, IVariantServiceProvider<IAlgorithm>
recupera un'implementazione di IAlgorithm
dal contenitore di inserimento delle dipendenze. L'implementazione scelta dipende da:
- Flag di funzionalità con cui è stato registrato il servizio
IAlgorithm
. - Variante allocata per tale funzionalità.
L'oggetto IVariantServiceProvider<T>
viene reso disponibile per l'applicazione chiamando IFeatureManagementBuilder.WithVariantService<T>(string featureName)
. Vedi l'esempio seguente.
services.AddFeatureManagement()
.WithVariantService<IAlgorithm>("ForecastAlgorithm");
La chiamata precedente rende IVariantServiceProvider<IAlgorithm>
disponibile nella raccolta di servizi. Le implementazioni di IAlgorithm
devono essere aggiunte separatamente tramite un metodo di aggiunta, ad esempio services.AddSingleton<IAlgorithm, SomeImplementation>()
. L'implementazione di IAlgorithm
, che IVariantServiceProvider
usa, dipende dal flag di funzionalità varianti ForecastAlgorithm
. Se non viene aggiunta alcuna implementazione di IAlgorithm
alla raccolta di servizi, IVariantServiceProvider<IAlgorithm>.GetServiceAsync()
restituisce un'attività con risultato Null.
{
// The example variant feature flag
"id": "ForecastAlgorithm",
"enabled": true,
"variants": [
{
"Name": "AlgorithmBeta"
},
...
]
}
Attributo alias del servizio delle varianti
[VariantServiceAlias("Beta")]
public class AlgorithmBeta : IAlgorithm
{
...
}
Il provider di servizi delle varianti userà i nomi dei tipi di implementazioni per trovare la corrispondenza con la variante allocata. Se un servizio delle varianti è decorato con VariantServiceAliasAttribute
, il nome dichiarato in questo attributo deve essere usato nella configurazione per fare riferimento a questo servizio variante.
Telemetria
Quando viene distribuita una modifica del flag di funzionalità, è spesso importante analizzarne l'effetto su un'applicazione. Ecco alcune domande che possono verificarsi, ad esempio:
- I flag sono abilitati/disabilitati come previsto?
- Gli utenti di destinazione ottengono l'accesso a una determinata funzionalità come previsto?
- Quale variante viene visualizzata da un utente specifico?
Questi tipi di domande possono essere risposte tramite l'emissione e l'analisi degli eventi di valutazione dei flag di funzionalità. Questa libreria usa l'API System.Diagnostics.Activity
per produrre dati di telemetria di traccia durante la valutazione del flag di funzionalità.
Abilitazione della telemetria
Per impostazione predefinita, i flag di funzionalità non hanno dati di telemetria generati. Per pubblicare i dati di telemetria per un determinato flag di funzionalità, il flag MUST dichiara che è abilitato per l'emissione di dati di telemetria.
Per i flag di funzionalità definiti in appsettings.json
, i dati di telemetria possono essere abilitati usando la telemetry
proprietà .
{
"feature_management": {
"feature_flags": [
{
"id": "MyFeatureFlag",
"enabled": true,
"telemetry": {
"enabled": true
}
}
]
}
}
Il frammento di codice appsettings precedente definisce un flag di funzionalità denominato MyFeatureFlag
abilitato per i dati di telemetria. Lo stato di telemetria è indicato dall'oggetto telemetry
che imposta su enabled
true. Il valore della proprietà enabled
deve essere true
per pubblicare i dati di telemetria per il flag.
La sezione telemetry
di un flag di funzionalità ha le proprietà seguenti:
Proprietà | Descrizione |
---|---|
enabled |
Specifica se i dati di telemetria devono essere pubblicati per il flag di funzionalità. |
metadata |
Raccolta di coppie chiave-valore, modellate come dizionario, che possono essere usate per allegare metadati personalizzati relativi al flag di funzionalità agli eventi di valutazione. |
Pubblicazione di telemetria personalizzata
Il gestore delle funzionalità ha il proprio ActivitySource
denominato "Microsoft.FeatureManagement". Se telemetry
è abilitato per un flag di funzionalità, ogni volta che viene avviata la valutazione del flag di funzionalità, il gestore delle funzionalità avvierà Activity
. Al termine della valutazione del flag di funzionalità, il gestore delle funzionalità aggiungerà un ActivityEvent
denominato FeatureFlag
all'attività corrente. L'evento FeatureFlag
includerà tag che includono le informazioni sulla valutazione del flag di funzionalità, seguendo i campi definiti nello schema FeatureEvaluationEvent.
Nota
Tutte le coppie chiave-valore specificate in telemetry.metadata
del flag di funzionalità verranno incluse anche nei tag.
Per abilitare la pubblicazione di dati di telemetria personalizzati, è possibile creare un oggetto ActivityListener
e ascoltare l'origine dell'attività Microsoft.FeatureManagement
. Di seguito è riportato un esempio che mostra come ascoltare l'origine dell'attività di gestione delle funzionalità e aggiungere un callback quando viene valutata una funzionalità.
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.
}
}
});
Per altre informazioni, vedere Raccogliere una traccia distribuita.
Telemetria di Application Insights
Il pacchetto Microsoft.FeatureManagement.Telemetry.ApplicationInsights
fornisce un server di pubblicazione di telemetria predefinito che invia i dati di valutazione dei flag di funzionalità ad Application Insights. Il Microsoft.FeatureManagement.Telemetry.ApplicationInsights
pacchetto fornisce anche un inizializzatore di telemetria che contrassegna automaticamente tutti gli eventi con TargetingId
in modo che gli eventi possano essere collegati alle valutazioni dei flag. Per sfruttare questo vantaggio, aggiungere un riferimento al pacchetto e registrare i dati di telemetria di Application Insights come nell'esempio seguente.
builder.services
.AddFeatureManagement()
.AddApplicationInsightsTelemetry();
Nota
Per assicurarsi che i dati di telemetria di Application Insights funzionino come previsto, è necessario usare .TargetingHttpContextMiddleware
Per abilitare la persistenza del contesto di destinazione nell'attività corrente, è possibile usare .TargetingHttpContextMiddleware
app.UseMiddleware<TargetingHttpContextMiddleware>();
Un esempio di utilizzo è disponibile nell'esempio VariantAndTelemetryDemo .
Prerequisito
Questo server di pubblicazione di telemetria dipende dalla configurazione di Application Insights già configurata come servizio dell'applicazione. Ad esempio, questa operazione viene eseguita qui nell'applicazione di esempio.
Questo server di pubblicazione di telemetria dipende dalla configurazione e dalla registrazione di Application Insights come servizio dell'applicazione.
Memorizzazione nella cache
Lo stato della funzionalità viene fornito dal sistema IConfiguration
. È previsto che qualsiasi memorizzazione nella cache e aggiornamento dinamico vengano gestito dai provider di configurazione. La gestione delle funzionalità richiede a IConfiguration
il valore più recente dello stato di una funzionalità ogni volta che viene verificata l'abilitazione di una funzionalità.
Snapshot
Esistono scenari che richiedono che lo stato di una funzionalità rimanga coerente durante la durata di una richiesta. I valori restituiti dallo standard IVariantFeatureManager
possono cambiare se l'origine IConfiguration
da cui viene eseguito il pull viene aggiornata durante la richiesta. Questa operazione può essere impedita tramite IVariantFeatureManagerSnapshot
. IVariantFeatureManagerSnapshot
può essere recuperato nello stesso modo di IVariantFeatureManager
. IVariantFeatureManagerSnapshot
implementa l'interfaccia di IVariantFeatureManager
, ma memorizza nella cache il primo stato valutato di una funzionalità durante una richiesta e restituisce lo stesso stato di funzionalità per tutta la sua durata.
Provider di funzionalità personalizzati
L'implementazione di un provider di funzionalità personalizzato consente agli sviluppatori di eseguire il pull dei flag di funzionalità dalle origini, ad esempio un database o un servizio di gestione delle funzionalità. Il provider di funzionalità incluso usato per impostazione predefinita esegue il pull dei flag di funzionalità dal sistema di configurazione di .NET Core. Ciò consente di definire le funzionalità in un file appsettings.json o in provider di configurazione come Configurazione app di Azure. Questo comportamento può essere sostituito per fornire un controllo completo della posizione da cui le definizioni delle funzionalità vengono lette.
Per personalizzare il caricamento delle definizioni di funzionalità, è necessario implementare l'interfaccia IFeatureDefinitionProvider
.
public interface IFeatureDefinitionProvider
{
Task<FeatureDefinition> GetFeatureDefinitionAsync(string featureName);
IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync();
}
Per usare un'implementazione di IFeatureDefinitionProvider
, è necessario aggiungerla alla raccolta di servizi prima di aggiungere la gestione delle funzionalità. Nell'esempio di codice seguente viene aggiunta un'implementazione di IFeatureDefinitionProvider
denominata InMemoryFeatureDefinitionProvider
.
services.AddSingleton<IFeatureDefinitionProvider, InMemoryFeatureDefinitionProvider>()
.AddFeatureManagement()
Passaggi successivi
Per informazioni su come usare i flag di funzionalità nelle applicazioni, continuare con gli avvi rapidi.
Per informazioni su come usare i filtri di funzionalità, continuare con le esercitazioni seguenti.