Administración de características de .NET

Microsoft.FeatureManagement
Microsoft.FeatureManagement.AspNetCore

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

La biblioteca de administración de características de .NET proporciona una manera de desarrollar y exponer la funcionalidad de la aplicación en función de las marcas de características. Una vez desarrollada una nueva característica, muchas aplicaciones tienen requisitos especiales, como cuándo se debe habilitar la característica y en qué condiciones. Esta biblioteca proporciona una manera de definir estas relaciones y también se integra en patrones de código de .NET comunes para hacer posible la exposición de estas características.

Las marcas de características proporcionan una manera de que las aplicaciones de .NET y ASP.NET Core activen o desactiven dinámicamente las características. Los desarrolladores pueden usar marcas de características en casos de uso simples, como instrucciones condicionales, para escenarios más avanzados, como agregar rutas condicionalmente o filtros MVC. Las marcas de características se basan en el sistema de configuración de .NET Core. Cualquier proveedor de configuración de .NET Core es capaz de actuar como la red troncal de las marcas de características.

Estas son algunas de las ventajas de usar la biblioteca de administración de características de .NET:

  • Una convención común para la administración de características

  • Baja barrera a entrada

    • Basado en IConfiguration
    • Admite la configuración de la marca de características de archivo JSON
  • Administración de la duración de la marca de características

    • Los valores de configuración pueden cambiar en tiempo real; las marcas de características pueden ser coherentes en toda la solicitud
  • Escenarios sencillos a complejos cubiertos

    • Activar o desactivar características mediante el archivo de configuración declarativo
    • Evaluar dinámicamente el estado de la característica en función de la llamada al servidor
  • Extensiones de API para ASP.NET Core y MVC Framework

    • Enrutamiento
    • Filters
    • Atributos de acción

    La biblioteca de administración de características de .NET es de código abierto. Para obtener más información, visite el repositorio de GitHub.

Marcas de características

Las marcas de características se componen de dos partes, un nombre y una lista de filtros de características que se usan para activar la característica.

Filtros de características

Los filtros de características definen un escenario para cuando se debe habilitar una característica. Cuando se evalúa si una característica está activada o desactivada, se recorre su lista de filtros de características hasta que uno de los filtros decide que la característica debe estar habilitada. En este momento, la característica se considera habilitada y se recorre a través de los filtros de características se detiene. Si no hay ningún filtro de características que indique que la característica debe estar habilitada, se considera deshabilitada.

Por ejemplo, se podría diseñar un filtro de características del explorador Microsoft Edge. Este filtro de características activaría las características a las que está asociada siempre que una solicitud HTTP provendría de Microsoft Edge.

Configuración de marcas de características

El sistema de configuración de .NET Core se usa para determinar el estado de las marcas de características. La base de este sistema es IConfiguration. Cualquier proveedor de IConfiguration se puede usar como proveedor de estado de características para la biblioteca de marcas de características. Este sistema permite escenarios que van desde appsettings.json a Azure App Configuration y mucho más.

Declaración de marca de características

La biblioteca de administración de características admite appsettings.json como origen de marca de características, ya que es un proveedor para el sistema IConfiguration de .NET Core. A continuación se muestra un ejemplo del formato usado para configurar marcas de características en un archivo 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 sección FeatureManagement del documento json se usa por convención para cargar la configuración de la marca de características. En la sección anterior, vemos tres características diferentes. Las características definen sus filtros de características mediante la propiedad EnabledFor. En los filtros de características de FeatureT, vemos AlwaysOn. Este filtro de características está integrado y, si se especifica, siempre habilitará la característica. El filtro de características AlwaysOn no requiere ninguna configuración, por lo que solo tiene la propiedad Name. FeatureU no tiene ningún filtro en su propiedad EnabledFor y, por tanto, nunca se habilitará. Las funcionalidades que se basan en esta característica que se habilitan no serán accesibles siempre que los filtros de características permanezcan vacíos. Sin embargo, en cuanto se agrega un filtro de características que habilita la característica que puede empezar a funcionar. FeatureV especifica un filtro de características denominado TimeWindow. Este es un ejemplo de un filtro de características configurable. Podemos ver en el ejemplo que el filtro tiene una propiedad Parameters. Se usa para configurar el filtro. En este caso, se configuran las horas de inicio y finalización de la característica que se va a activar.

Puede encontrar el esquemaFeatureManagement detallado de la sección aquí.

Avanzadas: El uso de dos puntos ":" está prohibido en los nombres de marcas de características.

Declaración activado/desactivado

En el fragmento de código siguiente se muestra una manera alternativa de definir una característica que se puede usar para las características activadas y desactivadas.

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

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

RequirementType

La propiedad RequirementType de una marca de característica se usa para determinar si los filtros deben usar Any o All lógica al evaluar el estado de una característica. Si no se especifica RequirementType, el valor predeterminado es Any.

  • Any significa que solo un filtro debe evaluarse como true para que se habilite la característica.
  • All significa que cada filtro debe evaluarse como true para que se habilite la característica.

Un RequirementType de All cambia el recorrido. En primer lugar, si no hay ningún filtro, la característica está deshabilitada. A continuación, los filtros de características se recorren hasta que uno de los filtros decide que la característica debe deshabilitarse. Si no hay ningún filtro que indique que la característica debe deshabilitarse, se considera habilitada.

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

En el ejemplo anterior, FeatureW especifica un RequirementType de All, lo que significa que todos sus filtros deben evaluarse como true para que se habilite la característica. En este caso, la característica está habilitada para el 50 % de los usuarios durante el período de tiempo especificado.

Esquema de administración de características de Microsoft

La biblioteca de administración de características también admite el uso del Microsoft Feature Management schema para declarar marcas de características. Este esquema es independiente del lenguaje en el origen y es compatible con todas las bibliotecas de administración de características de 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"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

Nota:

Si la sección feature_management se puede encontrar en la configuración, se omite la sección FeatureManagement.

La biblioteca de administración de características admite appsettings.json como origen de marca de características, ya que es un proveedor para el sistema IConfiguration de .NET Core. Las marcas de características se declaran mediante el Microsoft Feature Management schema. Este esquema es independiente del lenguaje en el origen y es compatible con todas las bibliotecas de administración de características de Microsoft.

A continuación se muestra un ejemplo de declaración de marcas de características en un archivo 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 sección feature_management del documento json se usa por convención para cargar la configuración de la marca de características. Los objetos de marca de características deben aparecer en la matriz feature_flags en la sección feature_management. En la sección anterior, vemos que hemos proporcionado tres características diferentes. Una marca de característica tiene propiedades id y enabled. El id es el nombre que se usa para identificar y hacer referencia a la marca de característica. La propiedad enabled especifica el estado habilitado de la marca de característica. Una característica se Desactiva si enabled es false. Si enabled es true, el estado de la característica depende del conditions. Si no hay ningún conditions, la característica se Activa. Si hay conditions y se cumplen, la característica se Activa. Si hay conditions y se cumplen, la característica se Desactiva. La propiedad conditions declara las condiciones usadas para habilitar dinámicamente la característica. Las características definen sus filtros de características en la matriz client_filters. FeatureV especifica un filtro de características denominado Microsoft.TimeWindow. Este es un ejemplo de un filtro de características configurable. Podemos ver en el ejemplo que el filtro tiene una propiedad Parameters. Se usa para configurar el filtro. En este caso, se configuran las horas de inicio y finalización de la característica que se va a activar.

Avanzadas: El uso de dos puntos ":" está prohibido en los nombres de marcas de características.

RequirementType

La propiedad requirement_type de conditions se usa para determinar si los filtros deben usar Any o All lógica al evaluar el estado de una característica. Si no se especifica requirement_type, el valor predeterminado es Any.

  • Any significa que solo un filtro debe evaluarse como true para que se habilite la característica.
  • All significa que cada filtro debe evaluarse como true para que se habilite la característica.

Un requirement_type de All cambia el recorrido. En primer lugar, si no hay ningún filtro, la característica se deshabilitará. Si hay filtros, los filtros de características se recorren hasta que uno de los filtros decide que la característica debe deshabilitarse. Si no hay ningún filtro que indique que la característica debe deshabilitarse, se considerará habilitada.

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

En el ejemplo anterior, FeatureW especifica un requirement_type de All, lo que significa que todos sus filtros deben evaluarse como true para que se habilite la característica. En este caso, la característica se habilitará para el 50 % de los usuarios durante el período de tiempo especificado.

Esquema de administración de características de .NET

En versiones anteriores, el esquema principal de la biblioteca de administración de características era el .NET feature management schema. A partir de la versión 4.0.0, las nuevas características, incluidas las variantes y la telemetría, no se admitirán para el esquema de administración de características de .NET.

Nota:

Si hay una declaración de marca de característica que se pueda encontrar en las secciones feature_management y FeatureManagement, se adoptará la de la sección feature_management.

Consumo

La forma básica de administración de características es comprobar si está habilitada una marca de característica y, a continuación, realizar acciones en función del resultado. Esto se hace a través del método IFeatureManager del IsEnabledAsync.

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

Registro de servicios

La administración de características se basa en la inserción de dependencias de .NET Core. Podemos registrar los servicios de administración de características mediante convenciones estándar.

using Microsoft.FeatureManagement;

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

De forma predeterminada, el administrador de características recupera la configuración de la marca de características de la sección "FeatureManagement" de los datos de configuración de .NET Core. Si la sección "FeatureManagement" no existe, la configuración se considera vacía.

Nota:

También puede especificar que la configuración de la marca de características se debe recuperar de una sección de configuración diferente pasando la sección a AddFeatureManagement. En el ejemplo siguiente se indica al administrador de características que lea de otra sección denominada "MyFeatureFlags" en su lugar:

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

Inserción de dependencias

Al usar la biblioteca de administración de características con MVC, el IFeatureManager se puede obtener mediante la inserción de dependencias.

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

Servicios de administración de características con ámbito

El método AddFeatureManagement agrega servicios de administración de características como singletons dentro de la aplicación, pero hay escenarios en los que puede ser necesario que los servicios de administración de características se agreguen como servicios con ámbito en su lugar. Por ejemplo, es posible que los usuarios quieran usar filtros de características que consumen servicios con ámbito para obtener información de contexto. En este caso, el método AddScopedFeatureManagement debe usarse en su lugar. Esto garantiza que los servicios de administración de características, incluidos los filtros de características, se agreguen como servicios con ámbito.

services.AddScopedFeatureManagement();

Integración de ASP.NET Core

La biblioteca de administración de características proporciona funcionalidad en ASP.NET Core y MVC para habilitar escenarios comunes de marcas de características en aplicaciones web. Estas funcionalidades están disponibles haciendo referencia al paquete NuGet de Microsoft.FeatureManagement.AspNetCore.

Controladores y acciones

El controlador y las acciones de MVC pueden requerir que una característica determinada o una de las listas de características estén habilitadas para ejecutarse. Esto se puede hacer mediante un FeatureGateAttribute, que se puede encontrar en el espacio de nombres Microsoft.FeatureManagement.Mvc.

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

La HomeController anterior está controlada por "FeatureX". "FeatureX" debe estar habilitado antes de que se pueda ejecutar cualquier acción que contenga el HomeController.

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

La acción Index MVC anterior requiere que se habilite "FeatureX" antes de poder ejecutarse.

Control de acciones deshabilitado

Cuando se bloquea un controlador o una acción de MVC porque ninguna de las características que especifica está habilitada, se invocará un IDisabledFeaturesHandler registrado. De forma predeterminada, se registra un controlador minimalista que devuelve HTTP 404. Esto se puede invalidar mediante el IFeatureManagementBuilder al registrar marcas de características.

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

Ver

En las vistas de MVC <feature> las etiquetas se pueden usar para representar de forma condicional el contenido en función de si una característica está habilitada o no.

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

También puede negar la evaluación del asistente de etiquetas para mostrar contenido cuando se deshabilita una característica o un conjunto de características. Al establecer negate="true" en el ejemplo siguiente, el contenido solo se representa si FeatureX está deshabilitado.

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

La etiqueta <feature> puede hacer referencia a varias características especificando una lista separada por comas de características en el atributo name.

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

De forma predeterminada, todas las características enumeradas deben estar habilitadas para que se represente la etiqueta de característica. Este comportamiento se puede invalidar agregando el atributo requirement como se muestra en el ejemplo siguiente.

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

En las vistas de MVC <feature> las etiquetas se pueden usar para representar de forma condicional el contenido en función de si una característica está habilitada o si se asigna una variante específica de una característica. Para obtener más información, vea la sección 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>

También puede negar la evaluación del asistente de etiquetas para mostrar contenido cuando se deshabilita una característica o un conjunto de características. Al establecer negate="true" en el ejemplo siguiente, el contenido solo se representa si FeatureX está deshabilitado.

<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 etiqueta <feature> puede hacer referencia a varias características o variantes especificando una lista separada por comas de características o variantes en el atributo 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:

Si se especifica variant, solo se debe especificar una característica.

De forma predeterminada, todas las características enumeradas deben estar habilitadas para que se represente la etiqueta de característica. Este comportamiento se puede invalidar agregando el atributo requirement como se muestra en el ejemplo siguiente.

Nota:

Si se usa un requirement de And junto con variant se producirá un error, ya que nunca se pueden asignar varias variantes.

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

La etiqueta <feature> requiere que un asistente de etiquetas funcione. Para ello, agregue el asistente de etiquetas de administración de características al archivo ViewImports.cshtml.

@addTagHelper *, Microsoft.FeatureManagement.AspNetCore

Filtros MVC

Los filtros de acción de MVC se pueden configurar para ejecutarse condicionalmente en función del estado de una característica. Para ello, se registran filtros de MVC de forma compatible con características. La canalización de administración de características admite filtros de acción asincrónicos de MVC, que implementan IAsyncActionFilter.

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

El código anterior agrega un filtro MVC denominado SomeMvcFilter. Este filtro solo se desencadena dentro de la canalización de MVC si está habilitado "FeatureX".

Páginas de Razor

Las páginas de Razor de MVC pueden requerir que una característica determinada o una de las listas de características estén habilitadas para ejecutarse. Esto se puede hacer mediante un FeatureGateAttribute, que se puede encontrar en el espacio de nombres Microsoft.FeatureManagement.Mvc.

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

El código anterior configura una página de Razor para requerir que se habilite "FeatureX". Si la característica no está habilitada, la página genera un resultado HTTP 404 (NotFound).

Cuando se usa en páginas de Razor, el FeatureGateAttribute debe colocarse en el tipo de controlador de página. No se puede colocar en métodos de controlador individuales.

Compilación de aplicaciones

La biblioteca de administración de características se puede usar para agregar ramas de aplicación y middleware que se ejecutan condicionalmente en función del estado de la característica.

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

Con la llamada anterior, la aplicación agrega un componente de middleware que solo aparece en la canalización de solicitudes si la característica "FeatureX" está habilitada. Si la característica está habilitada o deshabilitada durante el tiempo de ejecución, la canalización de middleware se puede cambiar dinámicamente.

Esto se basa en la funcionalidad más genérica para bifurcar toda la aplicación en función de una característica.

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

Implementación de un filtro de características

La creación de un filtro de características proporciona una manera de habilitar las características en función de los criterios que defina. Para implementar un filtro de características, se debe implementar la interfaz IFeatureFilter. IFeatureFilter tiene un único método denominado EvaluateAsync. Cuando una característica especifica que se puede habilitar para un filtro de características, se llama al método EvaluateAsync. Si EvaluateAsync devuelve true, significa que la característica debe estar habilitada.

En el fragmento de código siguiente se muestra cómo agregar un filtro de características personalizado MyCriteriaFilter.

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

Los filtros de características se registran llamando a AddFeatureFilter<T> en el IFeatureManagementBuilder devuelto desde AddFeatureManagement. Estos filtros de características tienen acceso a los servicios que existen dentro de la colección de servicios que se usó para agregar marcas de características. La inserción de dependencias se puede usar para recuperar estos servicios.

Nota:

Cuando se hace referencia a los filtros en la configuración de la marca de características (por ejemplo, appsettings.json), se debe omitir el Filtro parte del nombre de tipo. Para obtener más información, vea la sección Filter Alias Attribute.

Filtros de características con parámetros

Algunos filtros de características requieren parámetros para decidir si se debe activar o no una característica. Por ejemplo, un filtro de características del explorador puede activar una característica para un determinado conjunto de exploradores. Es posible que desee que los exploradores Edge y Chrome habiliten una característica, mientras que Firefox no lo hace. Para ello, se puede diseñar un filtro de características para esperar parámetros. Estos parámetros se especificarían en la configuración de características y, en el código, sería accesible a través del parámetro 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 tiene una propiedad denominada Parameters. Estos parámetros representan una configuración sin procesar que el filtro de características puede usar para decidir cómo evaluar si la característica debe estar habilitada o no. Para usar el filtro de características del explorador como ejemplo de nuevo, el filtro podría usar Parameters para extraer un conjunto de exploradores permitidos que se especificarían para la característica y, a continuación, comprobar si la solicitud se envía desde uno de esos exploradores.

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

Atributo de alias de filtro

Cuando se registra un filtro de características para una marca de característica, el alias usado en la configuración es el nombre del tipo de filtro de características con el Filtro sufijo, si existe, quitado. Por ejemplo, MyCriteriaFilter se denominaría MyCriteria en la configuración.

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

Esto se puede invalidar mediante el FilterAliasAttribute. Un filtro de características se puede decorar con este atributo para declarar el nombre que se debe usar en la configuración para hacer referencia a este filtro de características dentro de una marca de característica.

Faltan filtros de características

Si una característica está configurada para habilitarse para un filtro de características específico y ese filtro de características no está registrado, se produce una excepción cuando se evalúa la característica. La excepción se puede deshabilitar mediante las opciones de administración de características.

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

Uso de HttpContext

Los filtros de características pueden evaluar si una característica debe habilitarse en función de las propiedades de una solicitud HTTP. Esto se realiza inspeccionando el contexto HTTP. Un filtro de características puede obtener una referencia al contexto HTTP obteniendo un IHttpContextAccessor a través de la inserción de dependencias.

public class BrowserFilter : IFeatureFilter
{
    private readonly IHttpContextAccessor _httpContextAccessor;

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

El IHttpContextAccessor debe agregarse al contenedor de inserción de dependencias al iniciarlo para que esté disponible. Se puede registrar en el IServiceCollection mediante el método siguiente.

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

Avanzadas: IHttpContextAccessor/HttpContext no se debe usar en los componentes de Razor de las aplicaciones Blazor del lado servidor. El enfoque recomendado para pasar contexto http en aplicaciones Blazor es copiar los datos en un servicio con ámbito. En el caso de las aplicaciones Blazor, se debe usar AddScopedFeatureManagement para registrar los servicios de administración de características. Para obtener más información, vea la sección Scoped Feature Management Services.

Proporcionar un contexto para la evaluación de características

En las aplicaciones de consola, no hay ningún contexto ambiental, como HttpContext que los filtros de características pueden adquirir y usar para comprobar si una característica debe estar activada o desactivada. En este caso, las aplicaciones deben proporcionar un objeto que represente un contexto en el sistema de administración de características para que lo usen los filtros de características. Esto se hace mediante IFeatureManager.IsEnabledAsync<TContext>(string featureName, TContext appContext). Los filtros de características pueden usar el objeto appContext que se proporciona al administrador de características para evaluar el estado de una característica.

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

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

Filtros de características contextuales

Los filtros de características contextuales implementan la interfaz IContextualFeatureFilter<TContext>. Estos filtros de características especiales pueden aprovechar el contexto que se pasa cuando se llama a IFeatureManager.IsEnabledAsync<TContext>. El parámetro de tipo TContext en IContextualFeatureFilter<TContext> describe qué tipo de contexto es capaz de controlar el filtro. Esto permite al desarrollador de un filtro de características contextuales describir lo que es necesario para aquellos que desean usarlo. Dado que cada tipo es un descendiente de objeto, se puede llamar a un filtro que implementa IContextualFeatureFilter<object> para cualquier contexto proporcionado. Para ilustrar un ejemplo de un filtro de características contextuales más específico, considere una característica habilitada si una cuenta está en una lista configurada de cuentas habilitadas.

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

Podemos ver que el AccountIdFilter requiere que se proporcione un objeto que implementa IAccountContext para poder evaluar el estado de una característica. Al usar este filtro de características, el autor de la llamada debe asegurarse de que el objeto pasado implementa IAccountContext.

Nota:

Solo un solo tipo puede implementar una interfaz de filtro de características. Al intentar agregar un filtro de características que implementa más de una única interfaz de filtro de características, se produce un ArgumentException.

Uso de filtros contextuales y no contextuales con el mismo alias

Los filtros de IFeatureFilter y IContextualFeatureFilter pueden compartir el mismo alias. En concreto, puede tener un alias de filtro compartido por 0 o 1 IFeatureFilter y 0 o N IContextualFeatureFilter<ContextType>, siempre y cuando haya como máximo un filtro aplicable para ContextType.

En el paso siguiente se describe el proceso de selección de un filtro cuando se registran filtros contextuales y no contextuales del mismo nombre en una aplicación.

Supongamos que tiene un filtro no contextual denominado FilterA y dos filtros contextuales FilterB y FilterC que aceptan TypeB y TypeC contextos respectivamente. Los tres filtros comparten el mismo alias SharedFilterName.

También tiene una marca de característica MyFeature que usa el filtro de características SharedFilterName en su configuración.

Si se registran los tres filtros:

  • Cuando se llama a IsEnabledAsync("MyFeature"), se usa el FilterA para evaluar la marca de característica.
  • Cuando se llama a IsEnabledAsync("MyFeature", context), si el tipo del contexto es TypeB, se usa FilterB. Si el tipo del contexto es TypeC, se usa FilterC.
  • Cuando se llama a IsEnabledAsync("MyFeature", context), si el tipo del contexto es TypeF, se usa FilterA.

Filtros de características integrados

Hay algunos filtros de características que vienen con el paquete de Microsoft.FeatureManagement: PercentageFilter, TimeWindowFilter, ContextualTargetingFilter y TargetingFilter. Todos los filtros, excepto el TargetingFilter, se agregan automáticamente cuando el método AddFeatureManagement registra la administración de características. El TargetingFilter se agrega con el método WithTargeting que se detalla en la sección Targeting siguiente.

Cada uno de los filtros de características integrados tiene sus propios parámetros. Esta es la lista de filtros de características junto con ejemplos.

Microsoft.Percentage

Este filtro proporciona la capacidad de habilitar una característica basada en un porcentaje establecido.

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

Microsoft.TimeWindow

Este filtro proporciona la capacidad de habilitar una característica basada en un período de tiempo. Si solo se especifica End, la característica se tiene en cuenta hasta ese momento. Si solo se especifica Start, la característica se considera en todos los puntos después de ese tiempo.

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

El período de tiempo se puede configurar para que se repita periódicamente. Esto puede ser útil para los escenarios en los que es posible que tenga que activar una característica durante un período de tráfico bajo o alto de un día o determinados días de una semana. Para expandir el período de tiempo individual a ventanas de tiempo periódicas, la regla de periodicidad debe especificarse en el parámetro Recurrence.

Nota:

Start y End deben especificarse para habilitar 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"
                    }
                }
            }
        }
    ]
}

La configuración de Recurrence se compone de dos partes: Pattern (con qué frecuencia se repite la ventana de tiempo) y Range (durante cuánto tiempo se repite el patrón de periodicidad).

Patrón de periodicidad

Hay dos posibles tipos de patrón de periodicidad: Daily y Weekly. Por ejemplo, un período de tiempo podría repetirse "todos los días", "cada tres días", "todos los lunes" o "todos los demás viernes".

Según el tipo, se requieren determinados campos de la Pattern, opcionales o se omiten.

  • Daily

    El patrón de periodicidad diaria hace que la ventana de tiempo se repita en función de un número de días entre cada repetición.

    Propiedad Relevancia Descripción
    Tipo Obligatorio Se debe establecer en Daily.
    Intervalo Opcionales Especifica el número de días entre cada repetición. El valor predeterminado es 1.
  • Weekly

    El patrón de periodicidad semanal hace que el período de tiempo se repita en el mismo día o días de la semana, en función del número de semanas entre cada conjunto de repeticiones.

    Propiedad Relevancia Descripción
    Tipo Obligatorio Se debe establecer en Weekly.
    DaysOfWeek Obligatorio Especifica en qué días de la semana se produce el evento.
    Intervalo Opcionales Especifica el número de semanas entre cada conjunto de repeticiones. El valor predeterminado es 1.
    FirstDayOfWeek Opcionales Especifica qué día se considera el primer día de la semana. El valor predeterminado es Sunday.

    En el ejemplo siguiente se repite la ventana de tiempo todos los demás lunes y martes

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

Nota:

Start debe ser una primera aparición válida que se ajuste al patrón de periodicidad. Además, la duración del período de tiempo no puede ser mayor que la frecuencia con la que se produce. Por ejemplo, no es válido que se repita un período de tiempo de 25 horas cada día.

Intervalo de periodicidad

Hay tres tipos de intervalos de periodicidad posibles: NoEnd, EndDate y Numbered.

  • NoEnd

    El intervalo de NoEnd hace que la periodicidad se produzca indefinidamente.

    Propiedad Relevancia Descripción
    Tipo Obligatorio Se debe establecer en NoEnd.
  • EndDate

    El intervalo de EndDate hace que el período de tiempo se produzca en todos los días que se ajusten al patrón aplicable hasta la fecha de finalización.

    Propiedad Relevancia Descripción
    Tipo Obligatorio Se debe establecer en EndDate.
    EndDate Obligatorio Especifica la fecha y hora para dejar de aplicar el patrón. Siempre que la hora de inicio de la última aparición caiga antes de la fecha de finalización, se permite que la hora de finalización de esa repetición se extienda más allá de ella.

    En el ejemplo siguiente se repetirá el período de tiempo todos los días hasta que se produzca la última aparición el 1 de abril de 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

    El intervalo de Numbered hace que el período de tiempo se produzca un número fijo de veces (en función del patrón).

    Propiedad Relevancia Descripción
    Tipo Obligatorio Se debe establecer en Numbered.
    NumberOfOccurrences Obligatorio Especifica el número de repeticiones.

    En el ejemplo siguiente se repetirá el período de tiempo del lunes y el martes hasta que haya tres repeticiones, que respectivamente se producen el 1 de abril (Mon), el 2 de abril (Tue) y el 8 de abril (Mon).

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

Para crear una regla de periodicidad, debe especificar tanto Pattern y Range. Cualquier tipo de patrón puede funcionar con cualquier tipo de intervalo.

Avanzadas: El desplazamiento de zona horaria de la propiedad Start se aplica a la configuración de periodicidad.

Microsoft.Targeting

Este filtro proporciona la capacidad de habilitar una característica para una audiencia de destino. Una explicación detallada de la segmentación se explica en la sección destino siguiente. Los parámetros de filtro incluyen un objeto Audience que describe usuarios, grupos, usuarios o grupos excluidos y un porcentaje predeterminado de la base de usuarios que debe tener acceso a la característica. Cada objeto de grupo que aparece en la sección Groups también debe especificar el porcentaje de los miembros del grupo que deben tener acceso. Si se especifica un usuario en la sección Exclusion, ya sea directamente o si el usuario está en un grupo excluido, la característica está deshabilitada. De lo contrario, si un usuario se especifica directamente en la sección de Users, o si el usuario está en el porcentaje incluido de cualquiera de los lanzamientos de grupo, o si el usuario entra en el porcentaje de lanzamiento predeterminado, ese usuario tendrá habilitada la característica.

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

Espacios de nombres de alias de filtro de características

Todos los alias de filtro de características integrados están en el espacio de nombres de filtro de características Microsoft. Esto es para evitar conflictos con otros filtros de características que pueden compartir el mismo alias. Los segmentos de un espacio de nombres de filtro de características se dividen por el carácter ".". Se puede hacer referencia a un filtro de características por su alias completo, como Microsoft.Percentage o por el último segmento que, en el caso de Microsoft.Percentage, es Percentage.

Selección de destino

El destino es una estrategia de administración de características que habilita a los desarrolladores implementar progresivamente nuevas características en su base de usuarios. La estrategia se basa en el concepto de dirigirse a un conjunto de usuarios conocidos como destino audiencia. Un público se compone de usuarios específicos, grupos, usuarios o grupos excluidos y un porcentaje designado de toda la base de usuarios. Los grupos que se incluyen en la audiencia se pueden dividir más en porcentajes de sus miembros totales.

En los pasos siguientes se muestra un ejemplo de una implementación progresiva para una nueva característica "Beta":

  1. A los usuarios individuales, Jeff y Alicia se les concede acceso a la versión beta
  2. Otro usuario, Mark, pide que opte por participar y se incluya.
  3. El veinte por ciento de un grupo conocido como "Ring1" se incluye en la versión Beta.
  4. El número de usuarios "Ring1" incluidos en la versión beta aumenta hasta el 100 %.
  5. El cinco por ciento de la base de usuarios se incluye en la versión beta.
  6. El porcentaje de lanzamiento se aumenta hasta el 100 % y la característica se implementa por completo.

Esta estrategia para implementar una característica está integrada en la biblioteca a través del filtro de característicasMicrosoft.Targeting incluido.

Selección de destino en una aplicación web

Una aplicación web de ejemplo que usa el filtro de características de destino está disponible en el proyecto de ejemplo FeatureFlagDemo.

Para empezar a usar el TargetingFilter en una aplicación, debe agregarse a la colección de servicios de la aplicación como cualquier otro filtro de características. A diferencia de otros filtros integrados, el TargetingFilter se basa en otro servicio que se va a agregar a la colección de servicios de la aplicación. Ese servicio es un ITargetingContextAccessor.

Microsoft.FeatureManagement.AspNetCore proporciona una implementación predeterminada de ITargetingContextAccessor que extraerá la información de destino del HttpContext de una solicitud. Puede usar el descriptor de acceso de contexto de destino predeterminado al configurar el destino mediante la sobrecarga no genérica de WithTargeting en IFeatureManagementBuilder.

El descriptor de acceso de contexto de destino y TargetingFilter se registran llamando a WithTargeting en IFeatureManagementBuilder.

services.AddFeatureManagement()
        .WithTargeting();

También puede registrar una implementación personalizada para ITargetingContextAccessor y TargetingFilter llamando a WithTargeting<T>. Este es un ejemplo de configuración de la administración de características en una aplicación web para usar el TargetingFilter con una implementación de ITargetingContextAccessor denominada ExampleTargetingContextAccessor.

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

ITargetingContextAccessor

Para usar el TargetingFilter en una aplicación web, se requiere una implementación de ITargetingContextAccessor. Esto se debe a que cuando se realiza una evaluación de destino, se necesita información contextual como lo que el usuario está evaluando actualmente. Esta información se conoce como TargetingContext. Diferentes aplicaciones web pueden extraer esta información de diferentes lugares. Algunos ejemplos comunes de dónde una aplicación puede extraer el contexto de destino son el contexto HTTP de la solicitud o una base de datos.

Un ejemplo que extrae la información del contexto de destino del contexto HTTP de la aplicación es DefaultHttpTargetingContextAccessor proporcionado por el paquete Microsoft.FeatureManagement.AspNetCore. Extraerá la información de destino de HttpContext.User. La información de UserId se extraerá del campo Identity.Name y la información de Groups se extraerá de las notificaciones de tipo Role. Esta implementación se basa en el uso de IHttpContextAccessor, que se describe aquí.

Selección de destino en una aplicación de consola

El filtro de destino se basa en un contexto de destino para evaluar si se debe activar una característica. Este contexto de destino contiene información como qué usuario se está evaluando actualmente y en qué grupos el usuario. En las aplicaciones de consola, normalmente no hay ningún contexto ambiente disponible para transmitir esta información al filtro de destino, por lo que debe pasarse directamente cuando se llama a FeatureManager.IsEnabledAsync. Esto se admite mediante el ContextualTargetingFilter. Las aplicaciones que necesitan flotar el contexto de destino en el administrador de características deben usar esto en lugar de la TargetingFilter.

Dado que ContextualTargetingFilter es un IContextualTargetingFilter<ITargetingContext>, se debe pasar una implementación de ITargetingContext a IFeatureManager.IsEnabledAsync para poder evaluar y activar una característica.

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

await fm.IsEnabledAsync(featureName, targetingContext);

El ContextualTargetingFilter sigue usando el alias de filtro de características Microsoft.Targeting, por lo que la configuración de este filtro es coherente con lo que se menciona en esa sección.

Un ejemplo que usa el ContextualTargetingFilter en una aplicación de consola está disponible en el proyecto de ejemplo TargetingConsoleApp.

Opciones de evaluación de destino

Las opciones están disponibles para personalizar cómo se realiza la evaluación de destino en todas las características. Estas opciones se pueden configurar al configurar la administración de características.

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

Exclusión de destino

Al definir una audiencia, los usuarios y grupos se pueden excluir de la audiencia. Esto resulta útil cuando se implementa una característica en un grupo de usuarios, pero algunos usuarios o grupos deben excluirse del lanzamiento. La exclusión se define agregando una lista de usuarios y grupos a la propiedad Exclusion del público.

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

En el ejemplo anterior, la característica está habilitada para los usuarios denominados Jeff y Alicia. También está habilitado para los usuarios del grupo denominado Ring0. Sin embargo, si el usuario se denomina Mark, la característica está deshabilitada, independientemente de si están en el grupo Ring0 o no. Las exclusiones tienen prioridad sobre el resto del filtro de destino.

Variantes

Cuando se agregan nuevas características a una aplicación, puede haber un momento en el que una característica tenga varias opciones de diseño propuestas diferentes. Una solución común para decidir sobre un diseño es alguna forma de pruebas A/B, lo que implica proporcionar una versión diferente de la característica a diferentes segmentos de la base de usuarios y elegir una versión basada en la interacción del usuario. En esta biblioteca, esta funcionalidad se habilita mediante la representación de diferentes configuraciones de una característica con variantes.

Las variantes permiten que una marca de característica sea más que una marca de activación o desactivación simple. Una variante representa un valor de una marca de característica que puede ser una cadena, un número, un valor booleano o incluso un objeto de configuración. Una marca de característica que declara variantes debe definir en qué circunstancias se debe usar cada variante, que se trata con mayor detalle en la sección Asignación 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; }
}

Obtención de variantes

Para cada característica, se puede recuperar una variante mediante el método IVariantFeatureManager 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

Una vez recuperada una variante, la configuración de una variante se puede usar directamente como IConfigurationSection de la propiedad Configuration de la variante. Otra opción es enlazar la configuración a un objeto mediante el patrón de enlace de configuración de NET.

IConfigurationSection variantConfiguration = variant.Configuration;

MyFeatureSettings settings = new MyFeatureSettings();

variantConfiguration.Bind(settings);

La variante devuelta depende del usuario que se está evaluando actualmente y esa información se obtiene de una instancia de TargetingContext. Este contexto se puede pasar al llamar a GetVariantAsync o se puede recuperar automáticamente de una implementación de ITargetingContextAccessor si se registra uno.

Declaración de marca de característica Variante

En comparación con las marcas de características normales, las marcas de características variantes tienen dos propiedades adicionales: variants y allocation. La propiedad variants es una matriz que contiene las variantes definidas para esta característica. La propiedad allocation define cómo se deben asignar estas variantes para la característica. Al igual que declarar marcas de características normales, puede configurar marcas de características variantes en un archivo JSON. Este es un ejemplo de una marca de característica variante.

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

Definición de variantes

Cada variante tiene dos propiedades: un nombre y una configuración. El nombre se usa para hacer referencia a una variante específica y la configuración es el valor de esa variante. La configuración se puede establecer mediante la propiedad configuration_value. configuration_value es una configuración insertada que puede ser una cadena, un número, un valor booleano o un objeto de configuración. Si no se especifica configuration_value, la propiedad Configuration de la variante devuelta será null.

Se define una lista de todas las variantes posibles para cada característica en la propiedad variants.

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

Asignación de variantes

El proceso de asignación de variantes de una característica viene determinado por la propiedad allocation de la característica.

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

La configuración allocation de una característica tiene las siguientes propiedades:

Propiedad Descripción
default_when_disabled Especifica qué variante se debe usar cuando se solicita una variante mientras la característica se considera deshabilitada.
default_when_enabled Especifica qué variante se debe usar cuando se solicita una variante mientras la característica se considera habilitada y no se asignó ninguna otra variante al usuario.
user Especifica una variante y una lista de usuarios a los que se debe asignar esa variante.
group Especifica una variante y una lista de grupos. La variante se asignará si el usuario está en al menos uno de los grupos.
percentile Especifica una variante y un intervalo de porcentajes en el que debe caber el porcentaje calculado del usuario para que se asigne esa variante.
seed Valor en el que se basan los cálculos porcentuales de percentile. El cálculo porcentual de un usuario específico será el mismo en todas las características si se usa el mismo valor seed. Si no se especifica ningún seed, se crea una inicialización predeterminada en función del nombre de la característica.

En el ejemplo anterior, si la característica no está habilitada, el administrador de características asignará la variante marcada como default_when_disabled al usuario actual, que es Small en este caso.

Si la característica está habilitada, el administrador de características comprobará el user, group, y percentile asignaciones en ese orden para asignar una variante. En este ejemplo concreto, si el usuario que se evalúa se denomina Marsha, en el grupo denominado Ring1, o el usuario tiene lugar entre el percentil 0 y el 10, la variante especificada se asigna al usuario. En este caso, todos estos devolverían la variante Big. Si ninguna de estas asignaciones coincide, al usuario se le asigna la variante default_when_enabled, que es Small.

La lógica de asignación es similar a el filtro de características de Microsoft.Targeting, pero hay algunos parámetros presentes en el destino que no están en la asignación y viceversa. Los resultados de la selección de destino y la asignación no están relacionados.

Nota:

Para permitir la asignación de variantes de características, debe registrar ITargetingContextAccessor. Esto se puede hacer llamando al método WithTargeting<T>.

Invalidar el estado habilitado con una variante

Puede usar variantes para invalidar el estado habilitado de una marca de característica. Esto ofrece a las variantes una oportunidad para ampliar la evaluación de una marca de característica. Al llamar a IsEnabled en una marca con variantes, el administrador de características comprobará si la variante asignada al usuario actual está configurada para invalidar el resultado. Esto se hace mediante la propiedad variante opcional status_override. De forma predeterminada, esta propiedad se establece en None, lo que significa que la variante no afecta a si la marca se considera habilitada o deshabilitada. Establecer status_override en Enabled permite que la variante, cuando se elija, invalide una marca que se va a habilitar. Establecer status_override en Disabled proporciona la funcionalidad opuesta, por lo que deshabilitar la marca cuando se elige la variante. No se puede invalidar una característica con un estado enabled false.

Si usa una marca de característica con variantes binarias, la propiedad status_override puede ser muy útil. Permite seguir usando API como IsEnabledAsync y FeatureGateAttribute en la aplicación, al tiempo que se beneficia de las nuevas características que incluyen variantes, como la asignación de percentil y la inicialización.

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

En el ejemplo anterior, la característica siempre está habilitada. Si el usuario actual está en el intervalo de percentil calculado de 10 a 20, se devuelve la variante On. De lo contrario, se devuelve la variante Off y, dado que status_override es igual a Disabled, la característica ahora se considerará deshabilitada.

Variantes en la inserción de dependencias

Las marcas de características variante se pueden usar junto con la inserción de dependencias para exponer diferentes implementaciones de un servicio para distintos usuarios. Esto se logra mediante la interfaz IVariantServiceProvider<TService>.

IVariantServiceProvider<IAlgorithm> algorithmServiceProvider;
...

IAlgorithm forecastAlgorithm = await algorithmServiceProvider.GetServiceAsync(cancellationToken); 

En el fragmento de código anterior, el IVariantServiceProvider<IAlgorithm> recupera una implementación de IAlgorithm del contenedor de inserción de dependencias. La implementación elegida depende de:

  • Marca de característica con la que se registró el servicio IAlgorithm.
  • Variante asignada para esa característica.

El IVariantServiceProvider<T> está disponible para la aplicación llamando a IFeatureManagementBuilder.WithVariantService<T>(string featureName). Encontrará un ejemplo a continuación.

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

La llamada anterior hace que IVariantServiceProvider<IAlgorithm> esté disponible en la colección de servicios. Las implementaciones de IAlgorithm se deben agregar por separado a través de un método add, como services.AddSingleton<IAlgorithm, SomeImplementation>(). La implementación de IAlgorithm que usa el IVariantServiceProvider depende de la marca de característica ForecastAlgorithm variante. Si no se agrega ninguna implementación de IAlgorithm a la colección de servicios, el IVariantServiceProvider<IAlgorithm>.GetServiceAsync() devuelve una tarea con un resultado null.

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

Atributo de alias de servicio variante

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

El proveedor de servicios variante usará los nombres de tipo de implementaciones para que coincidan con la variante asignada. Si un servicio variante está decorado con el VariantServiceAliasAttribute, el nombre declarado en este atributo debe usarse en la configuración para hacer referencia a este servicio variante.

Telemetría

Cuando se implementa un cambio de marca de característica, a menudo es importante analizar su efecto en una aplicación. Por ejemplo, estas son algunas preguntas que pueden surgir:

  • ¿Mis marcas están habilitadas o deshabilitadas según lo previsto?
  • ¿Los usuarios de destino obtienen acceso a una determinada característica según lo previsto?
  • ¿Qué variante ve un usuario determinado?

Estos tipos de preguntas se pueden responder a través de la emisión y el análisis de eventos de evaluación de marcas de características. Esta biblioteca usa la API System.Diagnostics.Activity para generar telemetría de seguimiento durante la evaluación de marcas de características.

Habilitación de telemetría

De forma predeterminada, las marcas de características no tienen telemetría emitida. Para publicar telemetría para una marca de característica determinada, la marca DEBE declarar que está habilitada para la emisión de telemetría.

Para las marcas de características definidas en appsettings.json, esto se realiza mediante la propiedad telemetry.

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

El fragmento de código appsettings anterior define una marca de característica denominada MyFeatureFlag que está habilitada para la telemetría. Esto se indica mediante el objeto telemetry que establece enabled en true. El valor de la propiedad enabled debe ser true para publicar datos de telemetría para la marca.

La sección telemetry de una marca de característica tiene las siguientes propiedades:

Propiedad Descripción
enabled Especifica si se debe publicar la telemetría para la marca de característica.
metadata Colección de pares clave-valor, modelado como diccionario, que se pueden usar para adjuntar metadatos personalizados sobre la marca de característica a eventos de evaluación.

Publicadores de telemetría personalizados

El administrador de características tiene su propio ActivitySource llamado "Microsoft.FeatureManagement". Si telemetry está habilitado para una marca de característica, siempre que se inicie la evaluación de la marca de característica, el administrador de características iniciará un Activity. Cuando finalice la evaluación de la marca de características, el administrador de características agregará un ActivityEvent llamado FeatureFlag a la actividad actual. El evento FeatureFlag tendrá etiquetas que incluirán la información sobre la evaluación de marcas de características, siguiendo los campos definidos en el esquema FeatureEvaluationEvent.

Nota:

Todos los pares clave-valor especificados en la marca de característica telemetry.metadata también se incluirán en las etiquetas.

Para habilitar la publicación de telemetría personalizada, puede crear ActivityListener y escuchar el origen de la actividad Microsoft.FeatureManagement. Este es un ejemplo que muestra cómo escuchar el origen de la actividad de administración de características y agregar una devolución de llamada cuando se evalúa una característica.

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

Para obtener más información, vaya a Recopilar un seguimiento distribuido.

Publicador de telemetría de Application Insights

El paquete de Microsoft.FeatureManagement.Telemetry.ApplicationInsights proporciona un publicador de telemetría integrado que envía los datos de la evaluación de marcas de características a Application Insights. Para aprovechar esto, agregue una referencia al paquete y registre el publicador de telemetría de Application Insights, como se muestra a continuación.

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

El paquete Microsoft.FeatureManagement.Telemetry.ApplicationInsights proporciona un inicializador de telemetría que etiqueta automáticamente todos los eventos con TargetingId para que los eventos se puedan vincular a evaluaciones de marcas. Para usar el inicializador de telemetría TargetingTelemetryInitializer, agréguelo a la colección de servicios de la aplicación.

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

Nota:

Para asegurarse de que TargetingTelemetryInitializer funciona según lo previsto, se debe usar el TargetingHttpContextMiddleware que se describe a continuación.

Para habilitar la conservación del contexto de destino en la actividad actual, puede usar TargetingHttpContextMiddleware.

app.UseMiddleware<TargetingHttpContextMiddleware>();

Puede encontrar un ejemplo de su uso en el elemento VariantAndTelemetryDemo.

Requisito previo

Este publicador de telemetría depende de que Application Insights que ya esté configurado y registrado como servicio de aplicación. Por ejemplo, esto se hace aquí en la aplicación de ejemplo.

Este publicador de telemetría depende de Application Insights que ya esté configurado y registrado como servicio de aplicación.

Almacenamiento en memoria caché

El sistema IConfiguration proporciona el estado de la característica. Se espera que los proveedores de configuración controle cualquier almacenamiento en caché y actualización dinámica. El administrador de características solicita IConfiguration el valor más reciente del estado de una característica cada vez que se activa una característica para habilitarse.

Depurador de

Hay escenarios que requieren que el estado de una característica permanezca coherente durante la vigencia de una solicitud. Los valores devueltos desde el IFeatureManager estándar pueden cambiar si el origen del IConfiguration que se extrae se actualiza durante la solicitud. Esto se puede evitar mediante IFeatureManagerSnapshot. IFeatureManagerSnapshot se puede recuperar de la misma manera que IFeatureManager. IFeatureManagerSnapshot implementa la interfaz de IFeatureManager, pero almacena en caché el primer estado evaluado de una característica durante una solicitud y devuelve el mismo estado de una característica durante su vigencia.

Proveedores de características personalizados

La implementación de un proveedor de características personalizado permite a los desarrolladores extraer marcas de características de orígenes como una base de datos o un servicio de administración de características. El proveedor de características incluido que se usa de forma predeterminada extrae las marcas de características del sistema de configuración de .NET Core. Esto permite definir características en un archivo appsettings.json o en proveedores de configuración como Azure App Configuration. Este comportamiento se puede sustituir para proporcionar un control completo de dónde se leen las definiciones de características.

Para personalizar la carga de definiciones de características, debe implementar la interfaz IFeatureDefinitionProvider.

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

    IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync();
}

Para usar una implementación de IFeatureDefinitionProvider, debe agregarse a la colección de servicios antes de agregar la administración de características. En el ejemplo siguiente se agrega una implementación de IFeatureDefinitionProvider denominada InMemoryFeatureDefinitionProvider.

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

Pasos siguientes

Para obtener información sobre cómo usar marcas de características en las aplicaciones, continúe con los siguientes inicios rápidos.

Para obtener más información sobre cómo usar los filtros de características, continúe con los siguientes tutoriales.

Para obtener información sobre cómo ejecutar experimentos con marcas de características variantes, continúe con el siguiente tutorial.