Skip to content

Commit 206a208

Browse files
Revert "Merge main to release/v4 (#570)" (#572)
This reverts commit a74d56b.
1 parent a74d56b commit 206a208

11 files changed

Lines changed: 19 additions & 239 deletions

File tree

src/Microsoft.FeatureManagement.AspNetCore/FeatureGatedAsyncActionFilter.cs

Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,73 +4,33 @@
44
using Microsoft.AspNetCore.Mvc.Filters;
55
using Microsoft.Extensions.DependencyInjection;
66
using System;
7-
using System.Collections.Generic;
8-
using System.Linq;
97
using System.Threading.Tasks;
108

119
namespace Microsoft.FeatureManagement
1210
{
1311
/// <summary>
14-
/// A place holder MVC filter that is used to dynamically activate a filter based on whether a feature (or set of features) is enabled.
12+
/// A place holder MVC filter that is used to dynamically activate a filter based on whether a feature is enabled.
1513
/// </summary>
1614
/// <typeparam name="T">The filter that will be used instead of this placeholder.</typeparam>
1715
class FeatureGatedAsyncActionFilter<T> : IAsyncActionFilter where T : IAsyncActionFilter
1816
{
19-
/// <summary>
20-
/// Creates a feature gated filter for multiple features with a specified requirement type and ability to negate the evaluation.
21-
/// </summary>
22-
/// <param name="requirementType">Specifies whether all or any of the provided features should be enabled.</param>
23-
/// <param name="negate">Whether to negate the evaluation result.</param>
24-
/// <param name="features">The features that control whether the wrapped filter executes.</param>
25-
public FeatureGatedAsyncActionFilter(RequirementType requirementType, bool negate, params string[] features)
17+
public FeatureGatedAsyncActionFilter(string featureName)
2618
{
27-
if (features == null || features.Length == 0)
19+
if (string.IsNullOrEmpty(featureName))
2820
{
29-
throw new ArgumentNullException(nameof(features));
21+
throw new ArgumentNullException(nameof(featureName));
3022
}
3123

32-
Features = features;
33-
RequirementType = requirementType;
34-
Negate = negate;
24+
FeatureName = featureName;
3525
}
3626

37-
/// <summary>
38-
/// The set of features that gate the wrapped filter.
39-
/// </summary>
40-
public IEnumerable<string> Features { get; }
41-
42-
/// <summary>
43-
/// Controls whether any or all features in <see cref="Features"/> should be enabled to allow the wrapped filter to execute.
44-
/// </summary>
45-
public RequirementType RequirementType { get; }
46-
47-
/// <summary>
48-
/// Negates the evaluation for whether or not the wrapped filter should execute.
49-
/// </summary>
50-
public bool Negate { get; }
27+
public string FeatureName { get; }
5128

5229
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
5330
{
54-
IFeatureManagerSnapshot featureManager = context.HttpContext.RequestServices.GetRequiredService<IFeatureManagerSnapshot>();
55-
56-
bool enabled;
57-
58-
// Enabled state is determined by either 'any' or 'all' features being enabled.
59-
if (RequirementType == RequirementType.All)
60-
{
61-
enabled = await Features.All(async f => await featureManager.IsEnabledAsync(f).ConfigureAwait(false));
62-
}
63-
else
64-
{
65-
enabled = await Features.Any(async f => await featureManager.IsEnabledAsync(f).ConfigureAwait(false));
66-
}
67-
68-
if (Negate)
69-
{
70-
enabled = !enabled;
71-
}
31+
IFeatureManager featureManager = context.HttpContext.RequestServices.GetRequiredService<IFeatureManagerSnapshot>();
7232

73-
if (enabled)
33+
if (await featureManager.IsEnabledAsync(FeatureName).ConfigureAwait(false))
7434
{
7535
IAsyncActionFilter filter = ActivatorUtilities.CreateInstance<T>(context.HttpContext.RequestServices);
7636

src/Microsoft.FeatureManagement.AspNetCore/FilterCollectionExtensions.cs

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,63 +16,12 @@ public static class FilterCollectionExtensions
1616
/// <typeparam name="TFilterType">The MVC filter to add and use if the feature is enabled.</typeparam>
1717
/// <param name="filters">The filter collection to add to.</param>
1818
/// <param name="feature">The feature that will need to enabled to trigger the execution of the MVC filter.</param>
19-
/// <returns>The reference to the added filter metadata.</returns>
19+
/// <returns></returns>
2020
public static IFilterMetadata AddForFeature<TFilterType>(this FilterCollection filters, string feature) where TFilterType : IAsyncActionFilter
2121
{
22-
IFilterMetadata filterMetadata = new FeatureGatedAsyncActionFilter<TFilterType>(RequirementType.Any, false, feature);
22+
IFilterMetadata filterMetadata = null;
2323

24-
filters.Add(filterMetadata);
25-
26-
return filterMetadata;
27-
}
28-
29-
/// <summary>
30-
/// Adds an MVC filter that will only activate during a request if the specified feature is enabled.
31-
/// </summary>
32-
/// <typeparam name="TFilterType">The MVC filter to add and use if the feature is enabled.</typeparam>
33-
/// <param name="filters">The filter collection to add to.</param>
34-
/// <param name="features">The features that control whether the MVC filter executes.</param>
35-
/// <returns>The reference to the added filter metadata.</returns>
36-
public static IFilterMetadata AddForFeature<TFilterType>(this FilterCollection filters, params string[] features) where TFilterType : IAsyncActionFilter
37-
{
38-
IFilterMetadata filterMetadata = new FeatureGatedAsyncActionFilter<TFilterType>(RequirementType.Any, false, features);
39-
40-
filters.Add(filterMetadata);
41-
42-
return filterMetadata;
43-
}
44-
45-
/// <summary>
46-
/// Adds an MVC filter that will only activate during a request if the specified features are enabled based on the provided requirement type.
47-
/// </summary>
48-
/// <typeparam name="TFilterType">The MVC filter to add and use if the features condition is satisfied.</typeparam>
49-
/// <param name="filters">The filter collection to add to.</param>
50-
/// <param name="requirementType">Specifies whether all or any of the provided features should be enabled.</param>
51-
/// <param name="features">The features that control whether the MVC filter executes.</param>
52-
/// <returns>The reference to the added filter metadata.</returns>
53-
public static IFilterMetadata AddForFeature<TFilterType>(this FilterCollection filters, RequirementType requirementType, params string[] features) where TFilterType : IAsyncActionFilter
54-
{
55-
IFilterMetadata filterMetadata = new FeatureGatedAsyncActionFilter<TFilterType>(requirementType, false, features);
56-
57-
filters.Add(filterMetadata);
58-
59-
return filterMetadata;
60-
}
61-
62-
/// <summary>
63-
/// Adds an MVC filter that will only activate during a request if the specified features are enabled based on the provided requirement type and negation flag.
64-
/// </summary>
65-
/// <typeparam name="TFilterType">The MVC filter to add and use if the features condition is satisfied.</typeparam>
66-
/// <param name="filters">The filter collection to add to.</param>
67-
/// <param name="requirementType">Specifies whether all or any of the provided features should be enabled.</param>
68-
/// <param name="negate">Whether to negate the evaluation result for the provided features set.</param>
69-
/// <param name="features">The features that control whether the MVC filter executes.</param>
70-
/// <returns>The reference to the added filter metadata.</returns>
71-
public static IFilterMetadata AddForFeature<TFilterType>(this FilterCollection filters, RequirementType requirementType, bool negate, params string[] features) where TFilterType : IAsyncActionFilter
72-
{
73-
IFilterMetadata filterMetadata = new FeatureGatedAsyncActionFilter<TFilterType>(requirementType, negate, features);
74-
75-
filters.Add(filterMetadata);
24+
filters.Add(new FeatureGatedAsyncActionFilter<TFilterType>(feature));
7625

7726
return filterMetadata;
7827
}

src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<!-- Official Version -->
66
<PropertyGroup>
77
<MajorVersion>4</MajorVersion>
8-
<MinorVersion>4</MinorVersion>
8+
<MinorVersion>3</MinorVersion>
99
<PatchVersion>0</PatchVersion>
1010
</PropertyGroup>
1111

src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<!-- Official Version -->
55
<PropertyGroup>
66
<MajorVersion>4</MajorVersion>
7-
<MinorVersion>4</MinorVersion>
7+
<MinorVersion>3</MinorVersion>
88
<PatchVersion>0</PatchVersion>
99
</PropertyGroup>
1010

src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ public TimeWindowFilter(ILoggerFactory loggerFactory = null)
3737
public IMemoryCache Cache { get; set; }
3838

3939
/// <summary>
40-
/// This property allows the time window filter to use custom <see cref="TimeProvider"/>.
40+
/// This property allows the time window filter in our test suite to use simulated time.
4141
/// </summary>
42-
public TimeProvider SystemClock { get; set; }
42+
internal TimeProvider SystemClock { get; set; }
4343

4444
/// <summary>
4545
/// Binds configuration representing filter parameters to <see cref="TimeWindowFilterSettings"/>.

src/Microsoft.FeatureManagement/FeatureManagerSnapshot.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public async ValueTask<Variant> GetVariantAsync(string feature, CancellationToke
103103

104104
//
105105
// First, check local cache
106-
if (_variantCache.ContainsKey(cacheKey))
106+
if (_variantCache.ContainsKey(feature))
107107
{
108108
return _variantCache[cacheKey];
109109
}
@@ -121,7 +121,7 @@ public async ValueTask<Variant> GetVariantAsync(string feature, ITargetingContex
121121

122122
//
123123
// First, check local cache
124-
if (_variantCache.ContainsKey(cacheKey))
124+
if (_variantCache.ContainsKey(feature))
125125
{
126126
return _variantCache[cacheKey];
127127
}

src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<!-- Official Version -->
66
<PropertyGroup>
77
<MajorVersion>4</MajorVersion>
8-
<MinorVersion>4</MinorVersion>
8+
<MinorVersion>3</MinorVersion>
99
<PatchVersion>0</PatchVersion>
1010
</PropertyGroup>
1111

src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,7 @@ private static IFeatureManagementBuilder GetFeatureManagementBuilder(IServiceCol
175175
builder.AddFeatureFilter<TimeWindowFilter>(sp =>
176176
new TimeWindowFilter()
177177
{
178-
Cache = sp.GetRequiredService<IMemoryCache>(),
179-
SystemClock = sp.GetService<TimeProvider>() ?? TimeProvider.System,
178+
Cache = sp.GetRequiredService<IMemoryCache>()
180179
});
181180

182181
builder.AddFeatureFilter<ContextualTargetingFilter>();

tests/Tests.FeatureManagement.AspNetCore/FeatureManagementAspNetCore.cs

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -202,47 +202,6 @@ public async Task GatesRazorPageFeatures()
202202
Assert.Equal(HttpStatusCode.OK, gateAnyNegateResponse.StatusCode);
203203
}
204204

205-
[Fact]
206-
public async Task GatesActionFilterFeatures()
207-
{
208-
IConfiguration config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
209-
210-
TestServer server = new TestServer(WebHost.CreateDefaultBuilder().ConfigureServices(services =>
211-
{
212-
services
213-
.AddSingleton(config)
214-
.AddFeatureManagement()
215-
.AddFeatureFilter<TestFilter>();
216-
217-
services.AddMvcCore(o =>
218-
{
219-
DisableEndpointRouting(o);
220-
o.Filters.AddForFeature<MvcFilter>(RequirementType.All, Features.ConditionalFeature, Features.ConditionalFeature2);
221-
});
222-
}).Configure(app => app.UseMvc()));
223-
224-
TestFilter filter = (TestFilter)server.Host.Services.GetRequiredService<IEnumerable<IFeatureFilterMetadata>>().First(f => f is TestFilter);
225-
HttpClient client = server.CreateClient();
226-
227-
//
228-
// Enable all features
229-
filter.Callback = _ => Task.FromResult(true);
230-
HttpResponseMessage res = await client.GetAsync("");
231-
Assert.True(res.Headers.Contains(nameof(MvcFilter)));
232-
233-
//
234-
// Enable 1/2 features
235-
filter.Callback = ctx => Task.FromResult(ctx.FeatureName == Features.ConditionalFeature);
236-
res = await client.GetAsync("");
237-
Assert.False(res.Headers.Contains(nameof(MvcFilter)));
238-
239-
//
240-
// Enable no
241-
filter.Callback = _ => Task.FromResult(false);
242-
res = await client.GetAsync("");
243-
Assert.False(res.Headers.Contains(nameof(MvcFilter)));
244-
}
245-
246205
private static void DisableEndpointRouting(MvcOptions options)
247206
{
248207
options.EnableEndpointRouting = false;

tests/Tests.FeatureManagement/FeatureManagementTest.cs

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -332,67 +332,6 @@ public async Task ThreadSafeSnapshot()
332332
}
333333
}
334334

335-
[Fact]
336-
public async Task ReturnsCachedResultFromSnapshot()
337-
{
338-
IConfiguration config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
339-
340-
var services = new ServiceCollection();
341-
342-
services
343-
.AddSingleton(config)
344-
.AddFeatureManagement()
345-
.AddFeatureFilter<TestFilter>();
346-
347-
ServiceProvider serviceProvider = services.BuildServiceProvider();
348-
349-
IVariantFeatureManager featureManager = serviceProvider.GetRequiredService<IVariantFeatureManager>();
350-
351-
IVariantFeatureManager featureManagerSnapshot = serviceProvider.GetRequiredService<IVariantFeatureManagerSnapshot>();
352-
353-
IEnumerable<IFeatureFilterMetadata> featureFilters = serviceProvider.GetRequiredService<IEnumerable<IFeatureFilterMetadata>>();
354-
355-
TestFilter testFeatureFilter = (TestFilter)featureFilters.First(f => f is TestFilter);
356-
357-
int callCount = 0;
358-
bool filterEnabled = true;
359-
360-
testFeatureFilter.Callback = (evaluationContext) =>
361-
{
362-
callCount++;
363-
return Task.FromResult(filterEnabled);
364-
};
365-
366-
// First evaluation - filter is enabled and should return true
367-
bool result1 = await featureManagerSnapshot.IsEnabledAsync(Features.ConditionalFeature);
368-
Assert.Equal(1, callCount);
369-
Assert.True(result1);
370-
371-
Variant variant1 = await featureManagerSnapshot.GetVariantAsync(Features.ConditionalFeature);
372-
Assert.Equal(2, callCount);
373-
Assert.Equal("DefaultWhenEnabled", variant1.Name);
374-
375-
// "Shut down" the feature filter
376-
filterEnabled = false;
377-
378-
// Second evaluation - should use cached value despite filter being shut down
379-
bool result2 = await featureManagerSnapshot.IsEnabledAsync(Features.ConditionalFeature);
380-
Assert.Equal(2, callCount);
381-
Assert.True(result2);
382-
383-
Variant variant2 = await featureManagerSnapshot.GetVariantAsync(Features.ConditionalFeature);
384-
Assert.Equal(2, callCount);
385-
Assert.Equal("DefaultWhenEnabled", variant2.Name);
386-
387-
bool result3 = await featureManager.IsEnabledAsync(Features.ConditionalFeature);
388-
Assert.Equal(3, callCount);
389-
Assert.False(result3);
390-
391-
Variant variant3 = await featureManager.GetVariantAsync(Features.ConditionalFeature);
392-
Assert.Equal(4, callCount);
393-
Assert.Equal("DefaultWhenDisabled", variant3.Name);
394-
}
395-
396335
[Fact]
397336
public void AddsScopedFeatureManagement()
398337
{
@@ -584,20 +523,6 @@ public async Task MergesFeatureFlagsFromDifferentConfigurationSources()
584523
Assert.True(await featureManager8.IsEnabledAsync("FeatureC"));
585524
Assert.False(await featureManager8.IsEnabledAsync("Feature1"));
586525
Assert.False(await featureManager8.IsEnabledAsync("Feature2"));
587-
588-
var configurationManager = new ConfigurationManager();
589-
configurationManager
590-
.AddJsonFile("appsettings1.json")
591-
.AddJsonFile("appsettings2.json");
592-
593-
var services = new ServiceCollection();
594-
services.AddFeatureManagement();
595-
596-
var featureManager9 = new FeatureManager(new ConfigurationFeatureDefinitionProvider(configurationManager, mergeOptions));
597-
Assert.True(await featureManager9.IsEnabledAsync("FeatureA"));
598-
Assert.True(await featureManager9.IsEnabledAsync("FeatureB"));
599-
Assert.True(await featureManager9.IsEnabledAsync("Feature1"));
600-
Assert.False(await featureManager9.IsEnabledAsync("Feature2")); // appsettings2 should override appsettings1
601526
}
602527
}
603528

0 commit comments

Comments
 (0)