diff --git a/src/Microsoft.FeatureManagement/FeatureManagementError.cs b/src/Microsoft.FeatureManagement/FeatureManagementError.cs
index a1e3319f..4631dd09 100644
--- a/src/Microsoft.FeatureManagement/FeatureManagementError.cs
+++ b/src/Microsoft.FeatureManagement/FeatureManagementError.cs
@@ -16,6 +16,11 @@ public enum FeatureManagementError
///
/// A feature filter configured for the feature being evaluated is an ambiguous reference to multiple registered feature filters.
///
- AmbiguousFeatureFilter
+ AmbiguousFeatureFilter,
+
+ ///
+ /// The specified feature does not exist.
+ ///
+ MissingFeature
}
}
diff --git a/src/Microsoft.FeatureManagement/FeatureManagementOptions.cs b/src/Microsoft.FeatureManagement/FeatureManagementOptions.cs
index 9322934e..0c444c1b 100644
--- a/src/Microsoft.FeatureManagement/FeatureManagementOptions.cs
+++ b/src/Microsoft.FeatureManagement/FeatureManagementOptions.cs
@@ -13,5 +13,11 @@ public class FeatureManagementOptions
/// If missing feature filters are not ignored an exception will be thrown when attempting to evaluate a feature that depends on a missing feature filter.
///
public bool IgnoreMissingFeatureFilters { get; set; }
+
+ ///
+ /// Controls the behavior of feature evaluation when the specified feature does not exist.
+ /// If missing features are not ignored, an exception will be thrown when attempting to evaluate them.
+ ///
+ public bool IgnoreMissingFeatures { get; set; }
}
}
diff --git a/src/Microsoft.FeatureManagement/FeatureManager.cs b/src/Microsoft.FeatureManagement/FeatureManager.cs
index 6f0b2a14..2bbe542b 100644
--- a/src/Microsoft.FeatureManagement/FeatureManager.cs
+++ b/src/Microsoft.FeatureManagement/FeatureManager.cs
@@ -141,6 +141,10 @@ private async Task IsEnabledAsync(string feature, TContext appCo
}
}
}
+ else if (!_options.IgnoreMissingFeatures)
+ {
+ throw new FeatureManagementException(FeatureManagementError.MissingFeature, $"The feature declaration for specified feature '{feature}' was not found.");
+ }
foreach (ISessionManager sessionManager in _sessionManagers)
{
diff --git a/tests/Tests.FeatureManagement/FeatureManagement.cs b/tests/Tests.FeatureManagement/FeatureManagement.cs
index 1076d81c..5bf76f70 100644
--- a/tests/Tests.FeatureManagement/FeatureManagement.cs
+++ b/tests/Tests.FeatureManagement/FeatureManagement.cs
@@ -14,6 +14,7 @@
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Reflection;
using System.Threading.Tasks;
using Xunit;
@@ -25,6 +26,7 @@ public class FeatureManagement
private const string OffFeature = "OffFeature";
private const string ConditionalFeature = "ConditionalFeature";
private const string ContextualFeature = "ContextualFeature";
+ private const string MissingFeature = "MissingFeature";
[Fact]
public async Task ReadsConfiguration()
@@ -33,6 +35,12 @@ public async Task ReadsConfiguration()
var services = new ServiceCollection();
+ services
+ .Configure(options =>
+ {
+ options.IgnoreMissingFeatures = true;
+ });
+
services
.AddSingleton(config)
.AddFeatureManagement()
@@ -483,5 +491,59 @@ public async Task SwallowsExceptionForMissingFeatureFilter()
Assert.False(isEnabled);
}
+
+ [Fact]
+ public async Task ThrowsOnMissingFeature()
+ {
+ IConfiguration config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
+
+ var services = new ServiceCollection();
+
+ services
+ .Configure(options =>
+ {
+ options.IgnoreMissingFeatures = false;
+ });
+
+ services
+ .AddSingleton(config)
+ .AddFeatureManagement()
+ .AddFeatureFilter();
+
+ ServiceProvider serviceProvider = services.BuildServiceProvider();
+
+ IFeatureManager featureManager = serviceProvider.GetRequiredService();
+
+ FeatureManagementException e = await Assert.ThrowsAsync(async () => await featureManager.IsEnabledAsync(MissingFeature));
+
+ Assert.Equal(FeatureManagementError.MissingFeature, e.Error);
+ }
+
+ [Fact]
+ public async Task SwallowsOnMissingFeature()
+ {
+ IConfiguration config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
+
+ var services = new ServiceCollection();
+
+ services
+ .Configure(options =>
+ {
+ options.IgnoreMissingFeatures = true;
+ });
+
+ services
+ .AddSingleton(config)
+ .AddFeatureManagement()
+ .AddFeatureFilter();
+
+ ServiceProvider serviceProvider = services.BuildServiceProvider();
+
+ IFeatureManager featureManager = serviceProvider.GetRequiredService();
+
+ var isEnabled = await featureManager.IsEnabledAsync(ConditionalFeature);
+
+ Assert.False(isEnabled);
+ }
}
}