From 5c26df69b6f318cbf68d7c1050cb3e9f705c0ec8 Mon Sep 17 00:00:00 2001
From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com>
Date: Sat, 1 Jun 2024 13:39:37 +0800
Subject: [PATCH 1/5] simplify IsDurationCompliantWithDaysOfWeek (#458)
---
.../Recurrence/RecurrenceValidator.cs | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceValidator.cs b/src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceValidator.cs
index 992bea72..230ae674 100644
--- a/src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceValidator.cs
+++ b/src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceValidator.cs
@@ -358,25 +358,20 @@ private static bool IsDurationCompliantWithDaysOfWeek(TimeSpan duration, int int
foreach (DayOfWeek dayOfWeek in sortedDaysOfWeek)
{
- if (prev == DateTime.MinValue)
- {
- prev = firstDayOfThisWeek.AddDays(
- CalculateWeeklyDayOffset(dayOfWeek, firstDayOfWeek));
- }
- else
- {
- DateTime date = firstDayOfThisWeek.AddDays(
+ DateTime date = firstDayOfThisWeek.AddDays(
CalculateWeeklyDayOffset(dayOfWeek, firstDayOfWeek));
+ if (prev != DateTime.MinValue)
+ {
TimeSpan gap = date - prev;
if (gap < minGap)
{
minGap = gap;
}
-
- prev = date;
}
+
+ prev = date;
}
//
From 31f4a20bc0386451bf49a441f6829249adef0867 Mon Sep 17 00:00:00 2001
From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com>
Date: Sat, 15 Jun 2024 01:03:10 +0800
Subject: [PATCH 2/5] Stop using init-only setter for netstandard (#450)
* replace init with set
* revert to csharp 8.0
* add comment for LangVersion
* update comment
---
.../ConfigurationFeatureDefinitionProvider.cs | 4 ++--
.../FeatureFilters/TimeWindowFilter.cs | 4 ++--
.../FeatureManager.cs | 12 +++++------
.../IsExternalInit.cs | 21 -------------------
.../Microsoft.FeatureManagement.csproj | 4 +++-
5 files changed, 13 insertions(+), 32 deletions(-)
delete mode 100644 src/Microsoft.FeatureManagement/IsExternalInit.cs
diff --git a/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs b/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs
index 3ae10329..ebd1c621 100644
--- a/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs
+++ b/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs
@@ -58,12 +58,12 @@ public ConfigurationFeatureDefinitionProvider(IConfiguration configuration)
///
/// The option that controls the behavior when "FeatureManagement" section in the configuration is missing.
///
- public bool RootConfigurationFallbackEnabled { get; init; }
+ public bool RootConfigurationFallbackEnabled { get; set; }
///
/// The logger for the configuration feature definition provider.
///
- public ILogger Logger { get; init; }
+ public ILogger Logger { get; set; }
///
/// Disposes the change subscription of the configuration.
diff --git a/src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs b/src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs
index 121bb4cf..fb1f6f01 100644
--- a/src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs
+++ b/src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs
@@ -34,12 +34,12 @@ public TimeWindowFilter(ILoggerFactory loggerFactory = null)
///
/// The application memory cache to store the start time of the closest active time window. By caching this time, the time window can minimize redundant computations when evaluating recurrence.
///
- public IMemoryCache Cache { get; init; }
+ public IMemoryCache Cache { get; set; }
///
/// This property allows the time window filter in our test suite to use simulated time.
///
- internal ISystemClock SystemClock { get; init; }
+ internal ISystemClock SystemClock { get; set; }
///
/// Binds configuration representing filter parameters to .
diff --git a/src/Microsoft.FeatureManagement/FeatureManager.cs b/src/Microsoft.FeatureManagement/FeatureManager.cs
index ef850a03..9080929d 100644
--- a/src/Microsoft.FeatureManagement/FeatureManager.cs
+++ b/src/Microsoft.FeatureManagement/FeatureManager.cs
@@ -21,11 +21,11 @@ public sealed class FeatureManager : IFeatureManager
private readonly TimeSpan ParametersCacheAbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1);
private readonly IFeatureDefinitionProvider _featureDefinitionProvider;
- private readonly IEnumerable _featureFilters;
- private readonly IEnumerable _sessionManagers;
private readonly ConcurrentDictionary _filterMetadataCache;
private readonly ConcurrentDictionary _contextualFeatureFilterCache;
private readonly FeatureManagementOptions _options;
+ private IEnumerable _featureFilters;
+ private IEnumerable _sessionManagers;
private class ConfigurationCacheItem
{
@@ -60,7 +60,7 @@ public IEnumerable FeatureFilters
{
get => _featureFilters;
- init
+ set
{
_featureFilters = value ?? throw new ArgumentNullException(nameof(value));
}
@@ -74,7 +74,7 @@ public IEnumerable SessionManagers
{
get => _sessionManagers;
- init
+ set
{
_sessionManagers = value ?? throw new ArgumentNullException(nameof(value));
}
@@ -83,12 +83,12 @@ public IEnumerable SessionManagers
///
/// The application memory cache to store feature filter settings.
///
- public IMemoryCache Cache { get; init; }
+ public IMemoryCache Cache { get; set; }
///
/// The logger for the feature manager.
///
- public ILogger Logger { get; init; }
+ public ILogger Logger { get; set; }
///
/// Checks whether a given feature is enabled.
diff --git a/src/Microsoft.FeatureManagement/IsExternalInit.cs b/src/Microsoft.FeatureManagement/IsExternalInit.cs
deleted file mode 100644
index 2798741c..00000000
--- a/src/Microsoft.FeatureManagement/IsExternalInit.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-//
-
-// The init accessor for properties is supported in C# 9.0 and later.
-// This class is used to compile .NET frameworks that don't support C# 9.0 or later while still using the init accessor for a property.
-// The code referenced for this file can be found here: https://github.com/dotnet/roslyn/issues/45510#issuecomment-725091019
-
-#if NETSTANDARD2_0 || NETSTANDARD2_1
-
-using System.ComponentModel;
-
-namespace System.Runtime.CompilerServices
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal static class IsExternalInit
- {
- }
-}
-
-#endif
diff --git a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj
index 528a3448..ea79919a 100644
--- a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj
+++ b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj
@@ -15,7 +15,9 @@
truefalse..\..\build\Microsoft.FeatureManagement.snk
- 9.0
+
+ 8.0
From f88aec9b445e723934baa0c33ba63be39d84d20b Mon Sep 17 00:00:00 2001
From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com>
Date: Sat, 15 Jun 2024 20:30:44 +0800
Subject: [PATCH 3/5] Update REAMDE to reference Microsoft Learn (#459)
* update readme
* update
* update
* update title
* emphasize the link
* enumerate links
* update
---
README.md | 885 +-----------------------------------------------------
1 file changed, 12 insertions(+), 873 deletions(-)
diff --git a/README.md b/README.md
index a2b2c511..7a6ff819 100644
--- a/README.md
+++ b/README.md
@@ -1,885 +1,24 @@
# .NET Feature Management
+Feature management provides a way to develop and expose application functionality based on features. Many applications have special requirements when a new feature is developed such as when the feature should be enabled and under what conditions. This library provides a way to define these relationships, and also integrates into common .NET code patterns to make exposing these features possible.
-[](https://www.nuget.org/packages/Microsoft.FeatureManagement)
-[](https://www.nuget.org/packages/Microsoft.FeatureManagement.AspNetCore)
+## Get started
-Feature flags provide a way for .NET and ASP.NET Core applications to turn features on or off dynamically. Developers can use feature flags in simple use cases like conditional statements to more advanced scenarios like conditionally adding routes or MVC filters. Feature flags are built on top of the .NET Core configuration system. Any .NET Core configuration provider is capable of acting as the backbone for feature flags.
+[**Quickstart**](https://learn.microsoft.com/azure/azure-app-configuration/quickstart-feature-flag-dotnet): A quickstart guide is available to learn how to integrate feature flags from *Azure App Configuration* into your .NET applications.
-Here are some of the benefits of using this library:
+[**Feature Reference**](https://learn.microsoft.com/azure/azure-app-configuration/feature-management-dotnet-reference): This document provides a full feature rundown.
-* A common convention for feature management
-* Low barrier-to-entry
- * Built on `IConfiguration`
- * Supports JSON file feature flag setup
-* Feature Flag lifetime management
- * Configuration values can change in real-time, feature flags can be consistent across the entire request
-* Simple to Complex Scenarios Covered
- * Toggle on/off features through declarative configuration file
- * Dynamically evaluate state of feature based on call to server
-* API extensions for ASP.NET Core and MVC framework
- * Routing
- * Filters
- * Action Attributes
+[**API reference**](https://go.microsoft.com/fwlink/?linkid=2091700): This API reference details the API surface of the libraries contained within this repository.
-**API Reference**: https://go.microsoft.com/fwlink/?linkid=2091700
+## Examples
-## Index
-* [Feature Flags](#feature-flags)
- * [Feature Filters](#feature-filters)
- * [Feature Flag Declaration](#feature-flag-declaration)
-* [Consumption](#consumption)
-* [ASP.NET Core Integration](#ASPNET-core-integration)
-* [Implement a Feature Filter](#implementing-a-feature-filter)
-* [Providing a Context For Feature Evaluation](#providing-a-context-for-feature-evaluation)
-* [Built-in Feature Filters](#built-in-feature-filters)
-* [Targeting](#targeting)
- * [Targeting Exclusion](#targeting-exclusion)
-* [Caching](#caching)
-* [Custom Feature Providers](#custom-feature-providers)
+* [.NET Console App](./examples/ConsoleApp)
+* [.NET Console App with Targeting](./examples/TargetingConsoleApp)
+* [ASP.NET Core Web App (Razor Page)](./examples/RazorPages)
+* [ASP.NET Core Web App (MVC)](./examples/FeatureFlagDemo)
+* [Blazor Server App](./examples/BlazorServerApp)
-## Feature Flags
-Feature flags are composed of two parts, a name and a list of feature-filters that are used to turn the feature on.
-
-### Feature Filters
-Feature filters define a scenario for when a feature should be enabled. When a feature is evaluated for whether it is on or off, its list of feature filters is traversed until one of the filters decides the feature should be enabled. At this point the feature is considered enabled and traversal through the feature filters stops. If no feature filter indicates that the feature should be enabled, then it will be considered disabled.
-
-As an example, a Microsoft Edge browser feature filter could be designed. This feature filter would activate any features it is attached to as long as an HTTP request is coming from Microsoft Edge.
-
-### Feature Flag Configuration
-
-The .NET Core configuration system is used to determine the state of feature flags. The foundation of this system is `IConfiguration`. Any provider for IConfiguration can be used as the feature state provider for the feature flag library. This enables scenarios ranging from appsettings.json to Azure App Configuration and more.
-
-### Feature Flag Declaration
-
-The feature management library supports appsettings.json as a feature flag source since it is a provider for .NET Core's IConfiguration system. Below we have an example of the format used to set up feature flags in a json file.
-
-``` JavaScript
-{
- "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"
- }
- }
- ]
- }
- }
-}
-```
-
-The `FeatureManagement` section of the json document is used by convention to load feature flag settings. In the section above, we see that we have provided three different features. Features define their feature filters using the `EnabledFor` property. In the feature filters for `FeatureT` we see `AlwaysOn`. This feature filter is built-in and if specified will always enable the feature. The `AlwaysOn` feature filter does not require any configuration, so it only has the `Name` property. `FeatureU` has no filters in its `EnabledFor` property and thus will never be enabled. Any functionality that relies on this feature being enabled will not be accessible as long as the feature filters remain empty. However, as soon as a feature filter is added that enables the feature it can begin working. `FeatureV` specifies a feature filter named `TimeWindow`. This is an example of a configurable feature filter. We can see in the example that the filter has a `Parameters` property. This is used to configure the filter. In this case, the start and end times for the feature to be active are configured.
-
-The detailed schema of the `FeatureManagement` section can be found [here](./schemas/FeatureManagement.Dotnet.v1.0.0.schema.json).
-
-**Advanced:** The usage of colon ':' in feature flag names is forbidden.
-
-#### On/Off Declaration
-
-The following snippet demonstrates an alternative way to define a feature that can be used for on/off features.
-``` JavaScript
-{
- "Logging": {
- "LogLevel": {
- "Default": "Warning"
- }
- },
-
- // Define feature flags in config file
- "FeatureManagement": {
- "FeatureT": true, // On feature
- "FeatureX": false // Off feature
- }
-}
-```
-
-#### RequirementType
-
-The `RequirementType` property of a feature flag is used to determine if the filters should use `Any` or `All` logic when evaluating the state of a feature. If `RequirementType` is not specified, the default value is `Any`.
-
-* `Any` means only one filter needs to evaluate to true for the feature to be enabled.
-* `All` means every filter needs to evaluate to true for the feature to be enabled.
-
-A `RequirementType` of `All` changes the traversal. First, if there are no filters, the feature will be disabled. Then, the feature-filters are traversed until one of the filters decides that the feature should be disabled. If no filter indicates that the feature should be disabled, then it will be considered enabled.
-
-``` JavaScript
-"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"
- }
- }
- ]
-}
-```
-
-In the above example, `FeatureW` specifies a `RequirementType` of `All`, meaning all of its filters must evaluate to true for the feature to be enabled. In this case, the feature will be enabled for 50% of users during the specified time window.
-
-#### Microsoft Feature Management Schema
-
-The feature management library also supports the usage of the [`Microsoft Feature Management schema`](https://github.com/Azure/AppConfiguration/blob/main/docs/FeatureManagement/FeatureManagement.v1.0.0.schema.json) to declare feature flags. This schema is language agnostic in origin and is supported by all Microsoft feature management libraries.
-
-``` JavaScript
-{
- "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"
- }
- }
- ]
- }
- }
- ]
- }
-}
-```
-
-**Note:** If the `feature_management` section can be found in the configuration, the `FeatureManagement` section will be ignored.
-
-## Consumption
-
-The basic form of feature management is checking if a feature flag is enabled and then performing actions based on the result. This is done through the `IFeatureManager`'s `IsEnabledAsync` method.
-
-``` C#
-…
-IFeatureManager featureManager;
-…
-if (await featureManager.IsEnabledAsync("FeatureX"))
-{
- // Do something
-}
-```
-
-### Service Registration
-
-Feature management relies on .NET Core dependency injection. We can register the feature management services using standard conventions.
-
-``` C#
-using Microsoft.FeatureManagement;
-
-public class Startup
-{
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddFeatureManagement();
- }
-}
-```
-
-By default, the feature manager retrieves feature flag configuration from the "FeatureManagement" section of the .NET Core configuration data. If the "FeatureManagement" section does not exist, the configuration will be considered empty.
-
-You can also specify that feature flag configuration should be retrieved from a different configuration section by passing the section to `AddFeatureManagement`. The following example tells the feature manager to read from a different section called "MyFeatureFlags" instead:
-
-``` C#
-services.AddFeatureManagement(configuration.GetSection("MyFeatureFlags"));
-```
-
-### Dependency Injection
-
-When using the feature management library with MVC, the `IFeatureManager` can be obtained through dependency injection.
-
-``` C#
-public class HomeController : Controller
-{
- private readonly IFeatureManager _featureManager;
-
- public HomeController(IFeatureManager featureManager)
- {
- _featureManager = featureManager;
- }
-}
-```
-
-### Scoped Feature Management Services
-
-The `AddFeatureManagement` method adds feature management services as singletons within the application, but there are scenarios where it may be necessary for feature management services to be added as scoped services instead. For example, users may want to use feature filters which consume scoped services for context information. In this case, the `AddScopedFeatureManagement` method should be used instead. This will ensure that feature management services, including feature filters, are added as scoped services.
-
-``` C#
-services.AddScopedFeatureManagement();
-```
-
-## ASP.NET Core Integration
-
-The feature management library provides functionality in ASP.NET Core and MVC to enable common feature flag scenarios in web applications. These capabilities are available by referencing the [Microsoft.FeatureManagement.AspNetCore](https://www.nuget.org/packages/Microsoft.FeatureManagement.AspNetCore/) NuGet package.
-
-### Controllers and Actions
-
-MVC controller and actions can require that a given feature, or one of any list of features, be enabled in order to execute. This can be done by using a `FeatureGateAttribute`, which can be found in the `Microsoft.FeatureManagement.Mvc` namespace.
-
-``` C#
-[FeatureGate("FeatureX")]
-public class HomeController : Controller
-{
- …
-}
-```
-
-The `HomeController` above is gated by "FeatureX". "FeatureX" must be enabled before any action the `HomeController` contains can be executed.
-
-``` C#
-[FeatureGate("FeatureX")]
-public IActionResult Index()
-{
- return View();
-}
-```
-
-The `Index` MVC action above requires "FeatureX" to be enabled before it can be executed.
-
-### Disabled Action Handling
-
-When an MVC controller or action is blocked because none of the features it specifies are enabled, a registered `IDisabledFeaturesHandler` will be invoked. By default, a minimalistic handler is registered which returns HTTP 404. This can be overridden using the `IFeatureManagementBuilder` when registering feature flags.
-
-``` C#
-public interface IDisabledFeaturesHandler
-{
- Task HandleDisabledFeature(IEnumerable features, ActionExecutingContext context);
-}
-```
-
-### View
-
-In MVC views `` tags can be used to conditionally render content based on whether a feature is enabled or not.
-
-``` HTML+Razor
-
-
This can only be seen if 'FeatureX' is enabled.
-
-```
-
-You can also negate the tag helper evaluation to display content when a feature or set of features are disabled. By setting `negate="true"` in the example below, the content is only rendered if `FeatureX` is disabled.
-
-``` HTML+Razor
-
-
This can only be seen if 'FeatureX' is disabled.
-
-```
-
-The `` tag can reference multiple features by specifying a comma separated list of features in the `name` attribute.
-
-``` HTML+Razor
-
-
This can only be seen if 'FeatureX' and 'FeatureY' are enabled.
-
-```
-
-By default, all listed features must be enabled for the feature tag to be rendered. This behavior can be overidden by adding the `requirement` attribute as seen in the example below.
-
-``` HTML+Razor
-
-
This can only be seen if either 'FeatureX' or 'FeatureY' or both are enabled.
-
-```
-
-The `` tag requires a tag helper to work. This can be done by adding the feature management tag helper to the _ViewImports.cshtml_ file.
-``` HTML+Razor
-@addTagHelper *, Microsoft.FeatureManagement.AspNetCore
-```
-
-### MVC Filters
-
-MVC action filters can be set up to conditionally execute based on the state of a feature. This is done by registering MVC filters in a feature aware manner.
-The feature management pipeline supports async MVC Action filters, which implement `IAsyncActionFilter`.
-
-``` C#
-services.AddMvc(o =>
-{
- o.Filters.AddForFeature("FeatureX");
-});
-```
-
-The code above adds an MVC filter named `SomeMvcFilter`. This filter is only triggered within the MVC pipeline if the feature it specifies, "FeatureX", is enabled.
-
-### Razor Pages
-
-MVC Razor pages can require that a given feature, or one of any list of features, be enabled in order to execute. This can be done by using a `FeatureGateAttribute`, which can be found in the `Microsoft.FeatureManagement.Mvc` namespace.
-
-``` C#
-[FeatureGate("FeatureX")]
-public class IndexModel : PageModel
-{
- public void OnGet()
- {
- }
-}
-```
-
-The code above sets up a Razor page to require the "FeatureX" to be enabled. If the feature is not enabled, the page will generate an HTTP 404 (NotFound) result.
-
-When used on Razor pages, the `FeatureGateAttribute` must be placed on the page handler type. It cannot be placed on individual handler methods.
-
-### Application building
-
-The feature management library can be used to add application branches and middleware that execute conditionally based on feature state.
-
-``` C#
-app.UseMiddlewareForFeature("FeatureX");
-```
-
-With the above call, the application adds a middleware component that only appears in the request pipeline if the feature "FeatureX" is enabled. If the feature is enabled/disabled during runtime, the middleware pipeline can be changed dynamically.
-
-This builds off the more generic capability to branch the entire application based on a feature.
-
-``` C#
-app.UseForFeature(featureName, appBuilder =>
-{
- appBuilder.UseMiddleware();
-});
-```
-
-## Implementing a Feature Filter
-
-Creating a feature filter provides a way to enable features based on criteria that you define. To implement a feature filter, the `IFeatureFilter` interface must be implemented. `IFeatureFilter` has a single method named `EvaluateAsync`. When a feature specifies that it can be enabled for a feature filter, the `EvaluateAsync` method is called. If `EvaluateAsync` returns `true` it means the feature should be enabled.
-
-The following snippet demonstrates how to add a customized feature filter `MyCriteriaFilter`.
-
-``` C#
-services.AddFeatureManagement()
- .AddFeatureFilter();
-```
-
-Feature filters are registered by calling `AddFeatureFilter` on the `IFeatureManagementBuilder` returned from `AddFeatureManagement`. These feature filters have access to the services that exist within the service collection that was used to add feature flags. Dependency injection can be used to retrieve these services.
-
-**Note:** When filters are referenced in feature flag settings (e.g. appsettings.json), the _Filter_ part of the type name should be omitted. Please refer to the `Filter Alias Attribute` section below for more details.
-
-### Parameterized Feature Filters
-
-Some feature filters require parameters to decide whether a feature should be turned on or not. For example, a browser feature filter may turn on a feature for a certain set of browsers. It may be desired that Edge and Chrome browsers enable a feature, while Firefox does not. To do this a feature filter can be designed to expect parameters. These parameters would be specified in the feature configuration, and in code would be accessible via the `FeatureFilterEvaluationContext` parameter of `IFeatureFilter.EvaluateAsync`.
-
-``` C#
-public class FeatureFilterEvaluationContext
-{
- ///
- /// The name of the feature being evaluated.
- ///
- public string FeatureName { get; set; }
-
- ///
- /// The settings provided for the feature filter to use when evaluating whether the feature should be enabled.
- ///
- public IConfiguration Parameters { get; set; }
-}
-```
-
-`FeatureFilterEvaluationContext` has a property named `Parameters`. These parameters represent a raw configuration that the feature filter can use to decide how to evaluate whether the feature should be enabled or not. To use the browser feature filter as an example once again, the filter could use `Parameters` to extract a set of allowed browsers that would have been specified for the feature and then check if the request is being sent from one of those browsers.
-
-``` C#
-[FilterAlias("Browser")]
-public class BrowserFilter : IFeatureFilter
-{
- …
-
- public Task EvaluateAsync(FeatureFilterEvaluationContext context)
- {
- BrowserFilterSettings settings = context.Parameters.Get() ?? new BrowserFilterSettings();
-
- //
- // Here we would use the settings and see if the request was sent from any of BrowserFilterSettings.AllowedBrowsers
- }
-}
-```
-
-### Filter Alias Attribute
-
-When a feature filter is registered to be used for a feature flag, the alias used in configuration is the name of the feature filter type with the _Filter_ suffix, if any, removed. For example, `MyCriteriaFilter` would be referred to as _MyCriteria_ in configuration.
-
-``` JavaScript
-"MyFeature": {
- "EnabledFor": [
- {
- "Name": "MyCriteria"
- }
- ]
-}
-```
-This can be overridden through the use of the `FilterAliasAttribute`. A feature filter can be decorated with this attribute to declare the name that should be used in configuration to reference this feature filter within a feature flag.
-
-### Missing Feature Filters
-
-If a feature is configured to be enabled for a specific feature filter and that feature filter hasn't been registered, then an exception will be thrown when the feature is evaluated. The exception can be disabled by using the feature management options.
-
-``` C#
-services.Configure(options =>
-{
- options.IgnoreMissingFeatureFilters = true;
-});
-```
-
-### Using HttpContext
-
-Feature filters can evaluate whether a feature should be enabled based on the properties of an HTTP Request. This is performed by inspecting the HTTP Context. A feature filter can get a reference to the HTTP Context by obtaining an `IHttpContextAccessor` through dependency injection.
-
-``` C#
-public class BrowserFilter : IFeatureFilter
-{
- private readonly IHttpContextAccessor _httpContextAccessor;
-
- public BrowserFilter(IHttpContextAccessor httpContextAccessor)
- {
- _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
- }
-}
-```
-
-The `IHttpContextAccessor` must be added to the dependency injection container on startup for it to be available. It can be registered in the `IServiceCollection` using the following method.
-
-``` C#
-public void ConfigureServices(IServiceCollection services)
-{
- …
- services.TryAddSingleton();
- …
-}
-```
-
-**Advanced:** `IHttpContextAccessor`/`HttpContext` should not be used in the Razor components of server-side Blazor apps. [The recommended approach](https://learn.microsoft.com/en-us/aspnet/core/blazor/security/server/interactive-server-side-rendering?view=aspnetcore-7.0#ihttpcontextaccessorhttpcontext-in-razor-components) for passing http context in Blazor apps is to copy the data into a scoped service. For Blazor apps, `AddScopedFeatureManagement` should be used to register the feature management services.
-Please refer to the `Scoped Feature Management Services` section for more details.
-
-## Providing a Context For Feature Evaluation
-
-In console applications there is no ambient context such as `HttpContext` that feature filters can acquire and utilize to check if a feature should be on or off. In this case, applications need to provide an object representing a context into the feature management system for use by feature filters. This is done by using `IFeatureManager.IsEnabledAsync(string featureName, TContext appContext)`. The appContext object that is provided to the feature manager can be used by feature filters to evaluate the state of a feature.
-
-``` C#
-MyAppContext context = new MyAppContext
-{
- AccountId = current.Id;
-}
-
-if (await featureManager.IsEnabledAsync(feature, context))
-{
-…
-}
-```
-
-### Contextual Feature Filters
-
-Contextual feature filters implement the `IContextualFeatureFilter` interface. These special feature filters can take advantage of the context that is passed in when `IFeatureManager.IsEnabledAsync` is called. The `TContext` type parameter in `IContextualFeatureFilter` describes what context type the filter is capable of handling. This allows the developer of a contextual feature filter to describe what is required of those who wish to utilize it. Since every type is a descendant of object, a filter that implements `IContextualFeatureFilter
diff --git a/examples/FeatureFlagDemo/FeatureFlagDemo.csproj b/examples/FeatureFlagDemo/FeatureFlagDemo.csproj
index 724d6920..fcf18a50 100644
--- a/examples/FeatureFlagDemo/FeatureFlagDemo.csproj
+++ b/examples/FeatureFlagDemo/FeatureFlagDemo.csproj
@@ -2,7 +2,6 @@
net6.0
- enableenable
diff --git a/examples/FeatureFlagDemo/Views/Shared/Error.cshtml.cs b/examples/FeatureFlagDemo/Views/Shared/Error.cshtml.cs
index ae038094..d832e108 100644
--- a/examples/FeatureFlagDemo/Views/Shared/Error.cshtml.cs
+++ b/examples/FeatureFlagDemo/Views/Shared/Error.cshtml.cs
@@ -8,7 +8,7 @@ namespace FeatureFlagDemo.Pages.Shared
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
- public string? RequestId { get; set; }
+ public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
diff --git a/examples/TargetingConsoleApp/TargetingConsoleApp.csproj b/examples/TargetingConsoleApp/TargetingConsoleApp.csproj
index 91831acc..e1ffbd53 100644
--- a/examples/TargetingConsoleApp/TargetingConsoleApp.csproj
+++ b/examples/TargetingConsoleApp/TargetingConsoleApp.csproj
@@ -4,7 +4,6 @@
Exenet6.0enable
- enable
diff --git a/tests/Tests.FeatureManagement/FeatureManagement.cs b/tests/Tests.FeatureManagement/FeatureManagement.cs
index e5c0ba06..964f8dd4 100644
--- a/tests/Tests.FeatureManagement/FeatureManagement.cs
+++ b/tests/Tests.FeatureManagement/FeatureManagement.cs
@@ -752,11 +752,11 @@ public async Task ThreadsafeSnapshot()
await Task.WhenAll(tasks);
- bool result = tasks.First().Result;
+ bool result = await tasks.First();
foreach (Task t in tasks)
{
- Assert.Equal(result, t.Result);
+ Assert.Equal(result, await t);
}
}
From 319fc2b4dad4fab079348577ea0eaf898aea3745 Mon Sep 17 00:00:00 2001
From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com>
Date: Fri, 21 Jun 2024 07:08:09 +0800
Subject: [PATCH 5/5] version bump 3.4.0 (#465)
---
.../Microsoft.FeatureManagement.AspNetCore.csproj | 4 ++--
.../Microsoft.FeatureManagement.csproj | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj
index 94d93f15..73ab8dfa 100644
--- a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj
+++ b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj
@@ -4,8 +4,8 @@
3
- 3
- 1
+ 4
+ 0
diff --git a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj
index ea79919a..39cdd2e6 100644
--- a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj
+++ b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj
@@ -4,8 +4,8 @@
3
- 3
- 1
+ 4
+ 0