You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+52-19
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,9 @@ Here are some of the benefits of using this library:
10
10
* Supports JSON file feature flag setup
11
11
* Feature Flag lifetime management
12
12
* Configuration values can change in real-time, feature flags can be consistent across the entire request
13
+
* Simple to Complex Scenarios Covered
14
+
* Toggle on/off features through declarative configuration file
15
+
* Dynamically evaluate state of feature based on call to server
13
16
* API extensions for ASP.Net Core and MVC framework
14
17
* Routing
15
18
* Filters
@@ -128,13 +131,13 @@ This tells the feature manager to use the "FeatureManagement" section from the c
128
131
The simplest use case for feature flags is to do a conditional check for whether a feature is enabled to take different paths in code. The uses cases grow from there as the feature flag API begins to offer extensions into ASP.Net Core.
129
132
130
133
### Feature Check
131
-
The basic form of feature management is checking if a feature is enabled and then performing actions based on the result. This is done through the `IFeatureManager`'s `IsEnabled` method.
134
+
The basic form of feature management is checking if a feature is enabled and then performing actions based on the result. This is done through the `IFeatureManager`'s `IsEnabledAsync` method.
132
135
133
136
```
134
137
...
135
138
IFeatureManager featureManager;
136
139
...
137
-
if (featureManager.IsEnabled(nameof(MyFeatureFlags.FeatureU)))
140
+
if (await featureManager.IsEnabledAsync(nameof(MyFeatureFlags.FeatureU)))
138
141
{
139
142
// Do something
140
143
}
@@ -207,7 +210,8 @@ The `<feature>` tag requires a tag helper to work. This can be done by adding th
207
210
208
211
### MVC Filters
209
212
210
-
MVC 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.
213
+
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.
214
+
The feature management pipeline supports async MVC Action filters, which implement `IAsyncActionFilter`.
211
215
212
216
```
213
217
services.AddMvc(o =>
@@ -218,18 +222,6 @@ services.AddMvc(o =>
218
222
219
223
The code above adds an MVC filter named `SomeMvcFilter`. This filter is only triggered within the MVC pipeline if the feature it specifies, "FeatureV", is enabled.
220
224
221
-
### Routing
222
-
Certain routes may expose application capabilites that are gated by features. These routes can be dynamically registered and exposed based on whether a feature is enabled.
223
-
224
-
```
225
-
app.UseMvc(routes =>
226
-
{
227
-
routes.MapRouteForFeature(nameof(MyFeatureFlags.Beta), "betaDefault" /* route name */, "{controller=Beta}/{action=Index}/{id?}"
228
-
});
229
-
```
230
-
231
-
The route above exposes beta functionality of some application that is gated behind the "Beta" feature flag. The state of this feature is evaluated on every request, which means routes can be exposed to a subset of requests and or users. Furthermore, routes can dynamically be added or removed based on the toggling of feature states.
232
-
233
225
### Application building
234
226
235
227
The feature management library can be used to add application branches and middleware that execute conditionally based on feature state.
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 `Evaluate`. When a feature specifies that it can be enabled for a feature filter, the `Evaluate` method is called. If `Evaluate` returns `true` it means the feature should be enabled.
246
+
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.
255
247
256
248
Feature filters are registered by the `IFeatureManagementBuilder` when `AddFeatureManagement` is called. 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.
257
249
258
250
### Parameterized Feature Filters
259
251
260
-
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.Evaluate`.
252
+
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`.
261
253
262
254
```
263
255
public class FeatureFilterEvaluationContext
@@ -282,7 +274,7 @@ Some feature filters require parameters to decide whether a feature should be tu
282
274
{
283
275
... Removed for example
284
276
285
-
public bool Evaluate(FeatureFilterEvaluationContext context)
277
+
public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
286
278
{
287
279
BrowserFilterSettings settings = context.Parameters.Get<BrowserFilterSettings>() ?? new BrowserFilterSettings();
288
280
@@ -333,6 +325,46 @@ public void ConfigureServices(IServiceCollection services)
333
325
}
334
326
```
335
327
328
+
## Providing a Context For Feature Evaluation
329
+
330
+
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<TContext>(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.
331
+
332
+
```
333
+
MyAppContext context = new MyAppContext
334
+
{
335
+
AccountId = current.Id;
336
+
}
337
+
338
+
if (featureManager.IsEnabled(feature, context))
339
+
{
340
+
}
341
+
```
342
+
343
+
### Contextual Feature Filters
344
+
345
+
Contextual feature filters implement the `IContextualFeatureFilter<TContext>` interface. These special feature filters can take advantage of the context that is passed in when `IFeatureManager.IsEnabledAsync<TContext>` is called. The `TContext` type parameter in `IContextualFeatureFilter<TContext>` 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<object>` can be called for any provided context. To illustrate an example of a more specific contextual feature filter, consider a feature that is enabled if an account is in a configured list of enabled accounts.
346
+
347
+
```
348
+
public interface IAccountContext
349
+
{
350
+
string AccountId { get; set; }
351
+
}
352
+
353
+
[FilterAlias("AccountId")]
354
+
class AccountIdFilter : IContextualFeatureFilter<IAccountContext>
355
+
{
356
+
public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext featureEvaluationContext, IAccountContext accountId)
357
+
{
358
+
//
359
+
// Evaluate if the feature should be on with the help of the provided IAccountContext
360
+
}
361
+
}
362
+
```
363
+
364
+
We can see that the `AccountIdFilter` requires an object that implements `IAccountContext` to be provided to be able to evalute the state of a feature. When using this feature filter, the caller needs to make sure that the passed in object implements `IAccountContext`.
365
+
366
+
**Note:** Only a single feature filter interface can be implemented by a single type. Trying to add a feature filter that implements more than a single feature filter interface will result in an `ArgumentException`.
367
+
336
368
### Built-In Feature Filters
337
369
338
370
There a few feature filters that come with the `Microsoft.FeatureManagement` package. These feature filters are not added automatically, but can be referenced and registered as soon as the package is registered.
@@ -360,7 +392,8 @@ This filter provides the capability to enable a feature based on a set percentag
360
392
361
393
This filter provides the capability to enable a feature based on a time window. If only `End` is specified, the feature will be considered on until that time. If only start is specified, the feature will be considered on at all points after that time.
/// A filter that uses the feature management context to ensure that the current task has the notion of an account id, and that the account id is allowed.
15
+
/// This filter will only be executed if an object implementing <see cref="IAccountContext"/> is passed in during feature evaluation.
0 commit comments