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 1/6] 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 From 990d8fab5b1614a902045ca4ef34ff3afafecf34 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> Date: Tue, 25 Jun 2024 12:53:20 +0800 Subject: [PATCH 2/6] re-add nuget package in readme (#469) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7a6ff819..415773b6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # .NET Feature Management +[![Microsoft.FeatureManagement](https://img.shields.io/nuget/v/Microsoft.FeatureManagement?label=Microsoft.FeatureManagement)](https://www.nuget.org/packages/Microsoft.FeatureManagement) +[![Microsoft.FeatureManagement.AspNetCore](https://img.shields.io/nuget/v/Microsoft.FeatureManagement.AspNetCore?label=Microsoft.FeatureManagement.AspNetCore)](https://www.nuget.org/packages/Microsoft.FeatureManagement.AspNetCore) + 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. ## Get started From 138a4e24936d3e3d4a63ead98eb0ae03db606efc Mon Sep 17 00:00:00 2001 From: Ross Grambo Date: Mon, 15 Jul 2024 11:33:33 -0700 Subject: [PATCH 3/6] Adds Default Targeting Accessor and extension method WithTargeting (#466) * Adds default targeting accessor and extension method WithTargeting variation for ASP.NET * Updates accessor to internal * Forced query evaluation * Updated description of .WithTargeting extension --- .../QueryStringAuthenticationHandler.cs | 2 +- examples/FeatureFlagDemo/ClaimTypes.cs | 10 --- .../HttpContextTargetingContextAccessor.cs | 66 ----------------- examples/FeatureFlagDemo/Startup.cs | 2 +- ...tCoreFeatureManagementBuilderExtensions.cs | 26 +++++++ .../DefaultHttpTargetingContextAccessor.cs | 74 +++++++++++++++++++ 6 files changed, 102 insertions(+), 78 deletions(-) delete mode 100644 examples/FeatureFlagDemo/ClaimTypes.cs delete mode 100644 examples/FeatureFlagDemo/HttpContextTargetingContextAccessor.cs create mode 100644 src/Microsoft.FeatureManagement.AspNetCore/DefaultHttpTargetingContextAccessor.cs diff --git a/examples/FeatureFlagDemo/Authentication/QueryStringAuthenticationHandler.cs b/examples/FeatureFlagDemo/Authentication/QueryStringAuthenticationHandler.cs index 073b7452..0049cca3 100644 --- a/examples/FeatureFlagDemo/Authentication/QueryStringAuthenticationHandler.cs +++ b/examples/FeatureFlagDemo/Authentication/QueryStringAuthenticationHandler.cs @@ -49,7 +49,7 @@ protected override Task HandleAuthenticateAsync() foreach (string group in groups) { - identity.AddClaim(new Claim(ClaimTypes.GroupName, group)); + identity.AddClaim(new Claim(ClaimTypes.Role, group)); } Logger.LogInformation($"Assigning the following groups '{string.Join(", ", groups)}' to the request."); diff --git a/examples/FeatureFlagDemo/ClaimTypes.cs b/examples/FeatureFlagDemo/ClaimTypes.cs deleted file mode 100644 index b24dfd20..00000000 --- a/examples/FeatureFlagDemo/ClaimTypes.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// -namespace FeatureFlagDemo -{ - static class ClaimTypes - { - public static string GroupName = "http://schemas.featureflagdemo.featuremanagement.microsoft.com/claims/groupname"; - } -} diff --git a/examples/FeatureFlagDemo/HttpContextTargetingContextAccessor.cs b/examples/FeatureFlagDemo/HttpContextTargetingContextAccessor.cs deleted file mode 100644 index 9f9c8964..00000000 --- a/examples/FeatureFlagDemo/HttpContextTargetingContextAccessor.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// -using Microsoft.AspNetCore.Http; -using Microsoft.FeatureManagement.FeatureFilters; -using System; -using System.Collections.Generic; -using System.Security.Claims; -using System.Threading.Tasks; - -namespace FeatureFlagDemo -{ - /// - /// Provides an implementation of that creates a targeting context using info from the current HTTP request. - /// - public class HttpContextTargetingContextAccessor : ITargetingContextAccessor - { - private const string TargetingContextLookup = "HttpContextTargetingContextAccessor.TargetingContext"; - private readonly IHttpContextAccessor _httpContextAccessor; - - public HttpContextTargetingContextAccessor(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); - } - - public ValueTask GetContextAsync() - { - HttpContext httpContext = _httpContextAccessor.HttpContext; - - // - // Try cache lookup - if (httpContext.Items.TryGetValue(TargetingContextLookup, out object value)) - { - return new ValueTask((TargetingContext)value); - } - - ClaimsPrincipal user = httpContext.User; - - List groups = new List(); - - // - // This application expects groups to be specified in the user's claims - foreach (Claim claim in user.Claims) - { - if (claim.Type == ClaimTypes.GroupName) - { - groups.Add(claim.Value); - } - } - - // - // Build targeting context based off user info - TargetingContext targetingContext = new TargetingContext - { - UserId = user.Identity.Name, - Groups = groups - }; - - // - // Cache for subsequent lookup - httpContext.Items[TargetingContextLookup] = targetingContext; - - return new ValueTask(targetingContext); - } - } -} diff --git a/examples/FeatureFlagDemo/Startup.cs b/examples/FeatureFlagDemo/Startup.cs index 4c5722bd..f29f4934 100644 --- a/examples/FeatureFlagDemo/Startup.cs +++ b/examples/FeatureFlagDemo/Startup.cs @@ -45,7 +45,7 @@ public void ConfigureServices(IServiceCollection services) services.AddFeatureManagement() .AddFeatureFilter() - .WithTargeting() + .WithTargeting() .UseDisabledFeaturesHandler(new FeatureNotEnabledDisabledHandler()); services.AddMvc(o => diff --git a/src/Microsoft.FeatureManagement.AspNetCore/AspNetCoreFeatureManagementBuilderExtensions.cs b/src/Microsoft.FeatureManagement.AspNetCore/AspNetCoreFeatureManagementBuilderExtensions.cs index 742b942e..9091a4b0 100644 --- a/src/Microsoft.FeatureManagement.AspNetCore/AspNetCoreFeatureManagementBuilderExtensions.cs +++ b/src/Microsoft.FeatureManagement.AspNetCore/AspNetCoreFeatureManagementBuilderExtensions.cs @@ -3,9 +3,12 @@ // using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.FeatureManagement.FeatureFilters; using Microsoft.FeatureManagement.Mvc; using System; using System.Collections.Generic; +using System.Linq; namespace Microsoft.FeatureManagement { @@ -44,5 +47,28 @@ public static IFeatureManagementBuilder UseDisabledFeaturesHandler(this IFeature return builder; } + + /// + /// Enables the use of targeting within the application and adds a targeting context accessor that extracts targeting details from a request's HTTP context. + /// + /// The used to customize feature management functionality. + /// A that can be used to customize feature management functionality. + public static IFeatureManagementBuilder WithTargeting(this IFeatureManagementBuilder builder) + { + // + // Register the targeting context accessor with the same lifetime as the feature manager + if (builder.Services.Any(descriptor => descriptor.ServiceType == typeof(IFeatureManager) && descriptor.Lifetime == ServiceLifetime.Scoped)) + { + builder.Services.TryAddScoped(); + } + else + { + builder.Services.TryAddSingleton(); + } + + builder.AddFeatureFilter(); + + return builder; + } } } diff --git a/src/Microsoft.FeatureManagement.AspNetCore/DefaultHttpTargetingContextAccessor.cs b/src/Microsoft.FeatureManagement.AspNetCore/DefaultHttpTargetingContextAccessor.cs new file mode 100644 index 00000000..8eb99090 --- /dev/null +++ b/src/Microsoft.FeatureManagement.AspNetCore/DefaultHttpTargetingContextAccessor.cs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +using Microsoft.AspNetCore.Http; +using Microsoft.FeatureManagement.FeatureFilters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; + +namespace Microsoft.FeatureManagement +{ + /// + /// Provides a default implementation of that creates using info from the current HTTP request. + /// + internal sealed class DefaultHttpTargetingContextAccessor : ITargetingContextAccessor + { + /// + /// The key used to store and retrieve the from the items. + /// + private static object _cacheKey = new object(); + + private readonly IHttpContextAccessor _httpContextAccessor; + + /// + /// Creates an instance of the DefaultHttpTargetingContextAccessor + /// + public DefaultHttpTargetingContextAccessor(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); + } + + /// + /// Gets from the current HTTP request. + /// + public ValueTask GetContextAsync() + { + HttpContext httpContext = _httpContextAccessor.HttpContext; + + // + // Try cache lookup + if (httpContext.Items.TryGetValue(_cacheKey, out object value)) + { + return new ValueTask((TargetingContext)value); + } + + // + // Treat user identity name as user id + ClaimsPrincipal user = httpContext.User; + + string userId = user?.Identity?.Name; + + // + // Treat claims of type Role as groups + IEnumerable groups = httpContext.User.Claims + .Where(c => c.Type == ClaimTypes.Role) + .Select(c => c.Value) + .ToList(); + + TargetingContext targetingContext = new TargetingContext + { + UserId = userId, + Groups = groups + }; + + // + // Cache for subsequent lookup + httpContext.Items[_cacheKey] = targetingContext; + + return new ValueTask(targetingContext); + } + } +} \ No newline at end of file From 9ae3c19f669b0a12a80286ac5d7070bd3c97ab6e Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> Date: Wed, 17 Jul 2024 13:08:38 +0800 Subject: [PATCH 4/6] Add linting rule (#472) * remove unused package * fix format issue * enforce format check --- .editorconfig | 39 +++++++++++++++++++ .../BlazorServerApp/BlazorServerApp.csproj | 4 ++ examples/BlazorServerApp/BrowserFilter.cs | 2 +- examples/BlazorServerApp/Program.cs | 2 +- examples/ConsoleApp/AccountServiceContext.cs | 2 +- examples/ConsoleApp/ConsoleApp.csproj | 4 ++ examples/ConsoleApp/Program.cs | 7 +++- .../QueryStringAuthenticationHandler.cs | 4 -- examples/FeatureFlagDemo/BrowserFilter.cs | 5 --- .../FeatureFlagDemo/BrowserFilterSettings.cs | 2 - .../Controllers/BetaController.cs | 2 +- .../Controllers/HomeController.cs | 6 +-- .../FeatureFlagDemo/FeatureFlagDemo.csproj | 6 ++- .../FeatureFlagDemo/Models/ErrorViewModel.cs | 4 +- examples/FeatureFlagDemo/SuperUserFilter.cs | 1 - .../FeatureFlagDemo/ThirdPartyActionFilter.cs | 2 - .../FeatureFlagDemo/ThirdPartyMiddleware.cs | 4 -- .../Views/Shared/Error.cshtml.cs | 2 +- examples/RazorPages/Pages/Error.cshtml.cs | 2 +- examples/RazorPages/Pages/Index.cshtml.cs | 2 +- examples/RazorPages/Pages/Privacy.cshtml.cs | 5 +-- examples/RazorPages/RazorPages.csproj | 4 ++ .../Identity/IUserRepository.cs | 2 - .../Identity/InMemoryUserRepository.cs | 4 -- examples/TargetingConsoleApp/Identity/User.cs | 2 - examples/TargetingConsoleApp/Program.cs | 2 +- .../TargetingConsoleApp.csproj | 5 +++ .../FeatureGateAttribute.cs | 12 +++--- ...rosoft.FeatureManagement.AspNetCore.csproj | 6 ++- .../TagHelpers/FeatureTagHelper.cs | 6 +-- .../AssemblyInfo.cs | 4 +- .../ConfigurationFeatureDefinitionProvider.cs | 6 +-- .../ConfigurationFields.cs | 2 +- .../ConfigurationWrapper.cs | 18 ++++----- .../FeatureFilters/ISystemClock.cs | 2 +- .../Recurrence/RecurrenceEvaluator.cs | 1 - .../FeatureManagementBuilder.cs | 6 +-- .../FeatureManager.cs | 12 +++--- .../IFilterParametersBinder.cs | 2 +- .../Microsoft.FeatureManagement.csproj | 6 ++- .../MicrosoftFeatureManagementFields.cs | 2 +- .../ServiceCollectionExtensions.cs | 32 +++++++-------- .../Targeting/ContextualTargetingFilter.cs | 1 - .../FeatureManagementAspNetCore.cs | 1 - .../MvcFilter.cs | 2 +- .../Tests.FeatureManagement.AspNetCore.csproj | 6 ++- .../CustomTargetingFilter.cs | 3 +- .../FeatureManagement.cs | 8 ++-- .../RecurrenceEvaluation.cs | 4 +- .../Tests.FeatureManagement.csproj | 6 ++- 50 files changed, 159 insertions(+), 115 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..233e6128 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,39 @@ +# editorconfig.org + +# top-most EditorConfig file +root = true + +## Default settings ## +[*] +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +## Formatting rule ## +# https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055 +dotnet_diagnostic.IDE0055.severity = error + +# 'Using' directive preferences +dotnet_sort_system_directives_first = false + +# New line preferences +dotnet_diagnostic.IDE2002.severity = error +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false +dotnet_diagnostic.IDE2004.severity = error +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false +dotnet_diagnostic.IDE2005.severity = error +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false +dotnet_diagnostic.IDE2006.severity = error +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false +dotnet_diagnostic.IDE2000.severity = error +dotnet_style_allow_multiple_blank_lines_experimental = false +dotnet_diagnostic.IDE2003.severity = error +dotnet_style_allow_statement_immediately_after_block_experimental = false + +[*.csproj] +indent_size = 2 +charset = utf-8 + +[*.json] +indent_size = 2 \ No newline at end of file diff --git a/examples/BlazorServerApp/BlazorServerApp.csproj b/examples/BlazorServerApp/BlazorServerApp.csproj index eeae537e..115de563 100644 --- a/examples/BlazorServerApp/BlazorServerApp.csproj +++ b/examples/BlazorServerApp/BlazorServerApp.csproj @@ -9,4 +9,8 @@ + + True + + diff --git a/examples/BlazorServerApp/BrowserFilter.cs b/examples/BlazorServerApp/BrowserFilter.cs index 5105b8a8..376f323e 100644 --- a/examples/BlazorServerApp/BrowserFilter.cs +++ b/examples/BlazorServerApp/BrowserFilter.cs @@ -45,7 +45,7 @@ private static bool IsChromeBrowser(string userAgentContext) return false; } - return userAgentContext.Contains("chrome", StringComparison.OrdinalIgnoreCase) && + return userAgentContext.Contains("chrome", StringComparison.OrdinalIgnoreCase) && !userAgentContext.Contains("edg", StringComparison.OrdinalIgnoreCase); } diff --git a/examples/BlazorServerApp/Program.cs b/examples/BlazorServerApp/Program.cs index 4a66f68c..1dfd1c43 100644 --- a/examples/BlazorServerApp/Program.cs +++ b/examples/BlazorServerApp/Program.cs @@ -48,4 +48,4 @@ public static void Main(string[] args) app.Run(); } } -} \ No newline at end of file +} diff --git a/examples/ConsoleApp/AccountServiceContext.cs b/examples/ConsoleApp/AccountServiceContext.cs index 85114371..95f85a33 100644 --- a/examples/ConsoleApp/AccountServiceContext.cs +++ b/examples/ConsoleApp/AccountServiceContext.cs @@ -4,4 +4,4 @@ class AccountServiceContext : IAccountContext { public string AccountId { get; set; } -} \ No newline at end of file +} diff --git a/examples/ConsoleApp/ConsoleApp.csproj b/examples/ConsoleApp/ConsoleApp.csproj index fe29b948..1ef47ac8 100644 --- a/examples/ConsoleApp/ConsoleApp.csproj +++ b/examples/ConsoleApp/ConsoleApp.csproj @@ -21,4 +21,8 @@ + + True + + diff --git a/examples/ConsoleApp/Program.cs b/examples/ConsoleApp/Program.cs index 12028ca2..fb43a50e 100644 --- a/examples/ConsoleApp/Program.cs +++ b/examples/ConsoleApp/Program.cs @@ -1,4 +1,7 @@ -using Microsoft.Extensions.Configuration; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.FeatureManagement; @@ -49,4 +52,4 @@ // Output results Console.WriteLine($"The {FeatureName} feature is {(enabled ? "enabled" : "disabled")} for the '{account}' account."); } -} \ No newline at end of file +} diff --git a/examples/FeatureFlagDemo/Authentication/QueryStringAuthenticationHandler.cs b/examples/FeatureFlagDemo/Authentication/QueryStringAuthenticationHandler.cs index 0049cca3..7770ed3d 100644 --- a/examples/FeatureFlagDemo/Authentication/QueryStringAuthenticationHandler.cs +++ b/examples/FeatureFlagDemo/Authentication/QueryStringAuthenticationHandler.cs @@ -2,14 +2,10 @@ // Licensed under the MIT license. // using Microsoft.AspNetCore.Authentication; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; -using System.Collections.Generic; -using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; -using System.Threading.Tasks; namespace FeatureFlagDemo.Authentication { diff --git a/examples/FeatureFlagDemo/BrowserFilter.cs b/examples/FeatureFlagDemo/BrowserFilter.cs index efeb8e70..335e6d4c 100644 --- a/examples/FeatureFlagDemo/BrowserFilter.cs +++ b/examples/FeatureFlagDemo/BrowserFilter.cs @@ -1,12 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; using Microsoft.FeatureManagement; -using System; -using System.Linq; -using System.Threading.Tasks; namespace FeatureFlagDemo.FeatureManagement.FeatureFilters { diff --git a/examples/FeatureFlagDemo/BrowserFilterSettings.cs b/examples/FeatureFlagDemo/BrowserFilterSettings.cs index 91b8211a..c4cce8a3 100644 --- a/examples/FeatureFlagDemo/BrowserFilterSettings.cs +++ b/examples/FeatureFlagDemo/BrowserFilterSettings.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System.Collections.Generic; - namespace FeatureFlagDemo.FeatureManagement.FeatureFilters { public class BrowserFilterSettings diff --git a/examples/FeatureFlagDemo/Controllers/BetaController.cs b/examples/FeatureFlagDemo/Controllers/BetaController.cs index 9b69d9cf..4fed13f8 100644 --- a/examples/FeatureFlagDemo/Controllers/BetaController.cs +++ b/examples/FeatureFlagDemo/Controllers/BetaController.cs @@ -7,7 +7,7 @@ namespace FeatureFlagDemo.Controllers { - public class BetaController: Controller + public class BetaController : Controller { private readonly IFeatureManager _featureManager; diff --git a/examples/FeatureFlagDemo/Controllers/HomeController.cs b/examples/FeatureFlagDemo/Controllers/HomeController.cs index 6e43fba2..e7bfcd43 100644 --- a/examples/FeatureFlagDemo/Controllers/HomeController.cs +++ b/examples/FeatureFlagDemo/Controllers/HomeController.cs @@ -1,13 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System.Diagnostics; -using Microsoft.AspNetCore.Mvc; using FeatureFlagDemo.Models; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.FeatureManagement; using Microsoft.FeatureManagement.Mvc; -using System.Threading.Tasks; +using System.Diagnostics; namespace FeatureFlagDemo.Controllers { diff --git a/examples/FeatureFlagDemo/FeatureFlagDemo.csproj b/examples/FeatureFlagDemo/FeatureFlagDemo.csproj index fcf18a50..c3955ace 100644 --- a/examples/FeatureFlagDemo/FeatureFlagDemo.csproj +++ b/examples/FeatureFlagDemo/FeatureFlagDemo.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -32,4 +32,8 @@ + + True + + diff --git a/examples/FeatureFlagDemo/Models/ErrorViewModel.cs b/examples/FeatureFlagDemo/Models/ErrorViewModel.cs index 17542f32..bd9dea6c 100644 --- a/examples/FeatureFlagDemo/Models/ErrorViewModel.cs +++ b/examples/FeatureFlagDemo/Models/ErrorViewModel.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System; - namespace FeatureFlagDemo.Models { public class ErrorViewModel @@ -11,4 +9,4 @@ public class ErrorViewModel public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); } -} \ No newline at end of file +} diff --git a/examples/FeatureFlagDemo/SuperUserFilter.cs b/examples/FeatureFlagDemo/SuperUserFilter.cs index 25dc8e5f..4174c3c1 100644 --- a/examples/FeatureFlagDemo/SuperUserFilter.cs +++ b/examples/FeatureFlagDemo/SuperUserFilter.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. // using Microsoft.FeatureManagement; -using System.Threading.Tasks; namespace FeatureFlagDemo.FeatureManagement.FeatureFilters { diff --git a/examples/FeatureFlagDemo/ThirdPartyActionFilter.cs b/examples/FeatureFlagDemo/ThirdPartyActionFilter.cs index a2d3abd1..4fb4c550 100644 --- a/examples/FeatureFlagDemo/ThirdPartyActionFilter.cs +++ b/examples/FeatureFlagDemo/ThirdPartyActionFilter.cs @@ -1,9 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.Logging; namespace FeatureFlagDemo { diff --git a/examples/FeatureFlagDemo/ThirdPartyMiddleware.cs b/examples/FeatureFlagDemo/ThirdPartyMiddleware.cs index 74907908..52bdeddf 100644 --- a/examples/FeatureFlagDemo/ThirdPartyMiddleware.cs +++ b/examples/FeatureFlagDemo/ThirdPartyMiddleware.cs @@ -1,10 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - namespace FeatureFlagDemo { public class ThirdPartyMiddleware diff --git a/examples/FeatureFlagDemo/Views/Shared/Error.cshtml.cs b/examples/FeatureFlagDemo/Views/Shared/Error.cshtml.cs index d832e108..79b17264 100644 --- a/examples/FeatureFlagDemo/Views/Shared/Error.cshtml.cs +++ b/examples/FeatureFlagDemo/Views/Shared/Error.cshtml.cs @@ -24,4 +24,4 @@ public void OnGet() RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; } } -} \ No newline at end of file +} diff --git a/examples/RazorPages/Pages/Error.cshtml.cs b/examples/RazorPages/Pages/Error.cshtml.cs index 74050d52..149f1f23 100644 --- a/examples/RazorPages/Pages/Error.cshtml.cs +++ b/examples/RazorPages/Pages/Error.cshtml.cs @@ -24,4 +24,4 @@ public void OnGet() RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; } } -} \ No newline at end of file +} diff --git a/examples/RazorPages/Pages/Index.cshtml.cs b/examples/RazorPages/Pages/Index.cshtml.cs index 05dd8805..55bed039 100644 --- a/examples/RazorPages/Pages/Index.cshtml.cs +++ b/examples/RazorPages/Pages/Index.cshtml.cs @@ -18,4 +18,4 @@ public void OnGet() } } -} \ No newline at end of file +} diff --git a/examples/RazorPages/Pages/Privacy.cshtml.cs b/examples/RazorPages/Pages/Privacy.cshtml.cs index c1cd207f..cf5897c5 100644 --- a/examples/RazorPages/Pages/Privacy.cshtml.cs +++ b/examples/RazorPages/Pages/Privacy.cshtml.cs @@ -1,5 +1,4 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; namespace RazorPages.Pages { @@ -16,4 +15,4 @@ public void OnGet() { } } -} \ No newline at end of file +} diff --git a/examples/RazorPages/RazorPages.csproj b/examples/RazorPages/RazorPages.csproj index 2a2cbb46..7eab2e16 100644 --- a/examples/RazorPages/RazorPages.csproj +++ b/examples/RazorPages/RazorPages.csproj @@ -10,4 +10,8 @@ + + True + + diff --git a/examples/TargetingConsoleApp/Identity/IUserRepository.cs b/examples/TargetingConsoleApp/Identity/IUserRepository.cs index 15fedc84..ea5a99f4 100644 --- a/examples/TargetingConsoleApp/Identity/IUserRepository.cs +++ b/examples/TargetingConsoleApp/Identity/IUserRepository.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System.Threading.Tasks; - namespace TargetingConsoleApp.Identity { interface IUserRepository diff --git a/examples/TargetingConsoleApp/Identity/InMemoryUserRepository.cs b/examples/TargetingConsoleApp/Identity/InMemoryUserRepository.cs index 450c7044..1159bda0 100644 --- a/examples/TargetingConsoleApp/Identity/InMemoryUserRepository.cs +++ b/examples/TargetingConsoleApp/Identity/InMemoryUserRepository.cs @@ -1,10 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace TargetingConsoleApp.Identity { class InMemoryUserRepository : IUserRepository diff --git a/examples/TargetingConsoleApp/Identity/User.cs b/examples/TargetingConsoleApp/Identity/User.cs index be27cac1..de1f4069 100644 --- a/examples/TargetingConsoleApp/Identity/User.cs +++ b/examples/TargetingConsoleApp/Identity/User.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System.Collections.Generic; - namespace TargetingConsoleApp.Identity { class User diff --git a/examples/TargetingConsoleApp/Program.cs b/examples/TargetingConsoleApp/Program.cs index 5b89807a..d8ee6359 100644 --- a/examples/TargetingConsoleApp/Program.cs +++ b/examples/TargetingConsoleApp/Program.cs @@ -54,4 +54,4 @@ // Output results Console.WriteLine($"The {FeatureName} feature is {(enabled ? "enabled" : "disabled")} for the user '{userId}'."); } -} \ No newline at end of file +} diff --git a/examples/TargetingConsoleApp/TargetingConsoleApp.csproj b/examples/TargetingConsoleApp/TargetingConsoleApp.csproj index e1ffbd53..c699e5ab 100644 --- a/examples/TargetingConsoleApp/TargetingConsoleApp.csproj +++ b/examples/TargetingConsoleApp/TargetingConsoleApp.csproj @@ -20,4 +20,9 @@ Always + + + True + + diff --git a/src/Microsoft.FeatureManagement.AspNetCore/FeatureGateAttribute.cs b/src/Microsoft.FeatureManagement.AspNetCore/FeatureGateAttribute.cs index fb15e5b1..caf30a28 100644 --- a/src/Microsoft.FeatureManagement.AspNetCore/FeatureGateAttribute.cs +++ b/src/Microsoft.FeatureManagement.AspNetCore/FeatureGateAttribute.cs @@ -106,9 +106,9 @@ public override async Task OnActionExecutionAsync(ActionExecutingContext context // // Enabled state is determined by either 'any' or 'all' features being enabled. - bool enabled = RequirementType == RequirementType.All ? - await Features.All(async feature => await fm.IsEnabledAsync(feature).ConfigureAwait(false)) : - await Features.Any(async feature => await fm.IsEnabledAsync(feature).ConfigureAwait(false)); + bool enabled = RequirementType == RequirementType.All + ? await Features.All(async feature => await fm.IsEnabledAsync(feature).ConfigureAwait(false)) + : await Features.Any(async feature => await fm.IsEnabledAsync(feature).ConfigureAwait(false)); if (enabled) { @@ -134,9 +134,9 @@ public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext contex // // Enabled state is determined by either 'any' or 'all' features being enabled. - bool enabled = RequirementType == RequirementType.All ? - await Features.All(async feature => await fm.IsEnabledAsync(feature).ConfigureAwait(false)) : - await Features.Any(async feature => await fm.IsEnabledAsync(feature).ConfigureAwait(false)); + bool enabled = RequirementType == RequirementType.All + ? await Features.All(async feature => await fm.IsEnabledAsync(feature).ConfigureAwait(false)) + : await Features.Any(async feature => await fm.IsEnabledAsync(feature).ConfigureAwait(false)); if (enabled) { diff --git a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj index 73ab8dfa..c35cf77b 100644 --- a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj +++ b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj @@ -1,4 +1,4 @@ - + @@ -44,4 +44,8 @@ + + True + + diff --git a/src/Microsoft.FeatureManagement.AspNetCore/TagHelpers/FeatureTagHelper.cs b/src/Microsoft.FeatureManagement.AspNetCore/TagHelpers/FeatureTagHelper.cs index 4a0da1e0..2fddf486 100644 --- a/src/Microsoft.FeatureManagement.AspNetCore/TagHelpers/FeatureTagHelper.cs +++ b/src/Microsoft.FeatureManagement.AspNetCore/TagHelpers/FeatureTagHelper.cs @@ -54,9 +54,9 @@ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutpu { IEnumerable names = Name.Split(',').Select(n => n.Trim()); - enabled = Requirement == RequirementType.All ? - await names.All(async n => await _featureManager.IsEnabledAsync(n).ConfigureAwait(false)) : - await names.Any(async n => await _featureManager.IsEnabledAsync(n).ConfigureAwait(false)); + enabled = Requirement == RequirementType.All + ? await names.All(async n => await _featureManager.IsEnabledAsync(n).ConfigureAwait(false)) + : await names.Any(async n => await _featureManager.IsEnabledAsync(n).ConfigureAwait(false)); } if (Negate) diff --git a/src/Microsoft.FeatureManagement/AssemblyInfo.cs b/src/Microsoft.FeatureManagement/AssemblyInfo.cs index 955518ef..75bfb2fa 100644 --- a/src/Microsoft.FeatureManagement/AssemblyInfo.cs +++ b/src/Microsoft.FeatureManagement/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // using System.Runtime.CompilerServices; @@ -9,4 +9,4 @@ "3ae70fbea5662f61dd9d640de2205b7bd5359a43dda006e51d83d1f5f7a7d3f849267a0a28676d" + "cf49727a32487d4c75c4aacd5febb0069e1adc66ec63bbd18ec2276091a0e3c1326aa626c9e4db" + "800714a134f2a81e405f35752b55220021923429cb61776cd2fa66d25c335f8dc27bb92292905a" + -"3798d896")] \ No newline at end of file +"3798d896")] diff --git a/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs b/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs index ebd1c621..28af7ce6 100644 --- a/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs +++ b/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs @@ -381,9 +381,9 @@ private IEnumerable GetFeatureDefinitionSections() .FirstOrDefault(section => string.Equals( section.Key, - _microsoftFeatureManagementSchemaEnabled ? - MicrosoftFeatureManagementFields.FeatureManagementSectionName : - ConfigurationFields.FeatureManagementSectionName, + _microsoftFeatureManagementSchemaEnabled + ? MicrosoftFeatureManagementFields.FeatureManagementSectionName + : ConfigurationFields.FeatureManagementSectionName, StringComparison.OrdinalIgnoreCase)); if (featureManagementConfigurationSection == null) diff --git a/src/Microsoft.FeatureManagement/ConfigurationFields.cs b/src/Microsoft.FeatureManagement/ConfigurationFields.cs index a5472cd8..8b6ba82c 100644 --- a/src/Microsoft.FeatureManagement/ConfigurationFields.cs +++ b/src/Microsoft.FeatureManagement/ConfigurationFields.cs @@ -17,4 +17,4 @@ internal static class ConfigurationFields public const string NameKeyword = "Name"; public const string FeatureManagementSectionName = "FeatureManagement"; } -} \ No newline at end of file +} diff --git a/src/Microsoft.FeatureManagement/ConfigurationWrapper.cs b/src/Microsoft.FeatureManagement/ConfigurationWrapper.cs index 99f0b2a6..61d921f5 100644 --- a/src/Microsoft.FeatureManagement/ConfigurationWrapper.cs +++ b/src/Microsoft.FeatureManagement/ConfigurationWrapper.cs @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System; -using System.Collections.Generic; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Primitives; +using System; +using System.Collections.Generic; namespace Microsoft.FeatureManagement { @@ -27,13 +27,13 @@ public string this[string key] set => _configuration[key] = value; } - public IEnumerable GetChildren() => - _configuration.GetChildren(); + public IEnumerable GetChildren() + => _configuration.GetChildren(); - public IChangeToken GetReloadToken() => - _configuration.GetReloadToken(); + public IChangeToken GetReloadToken() + => _configuration.GetReloadToken(); - public IConfigurationSection GetSection(string key) => - _configuration.GetSection(key); + public IConfigurationSection GetSection(string key) + => _configuration.GetSection(key); } -} \ No newline at end of file +} diff --git a/src/Microsoft.FeatureManagement/FeatureFilters/ISystemClock.cs b/src/Microsoft.FeatureManagement/FeatureFilters/ISystemClock.cs index 50c6743d..1fc9b667 100644 --- a/src/Microsoft.FeatureManagement/FeatureFilters/ISystemClock.cs +++ b/src/Microsoft.FeatureManagement/FeatureFilters/ISystemClock.cs @@ -17,4 +17,4 @@ internal interface ISystemClock /// public DateTimeOffset UtcNow { get; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceEvaluator.cs b/src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceEvaluator.cs index 4dba080a..5e8b6872 100644 --- a/src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceEvaluator.cs +++ b/src/Microsoft.FeatureManagement/FeatureFilters/Recurrence/RecurrenceEvaluator.cs @@ -339,7 +339,6 @@ private static int CalculateWeeklyDayOffset(DayOfWeek day1, DayOfWeek day2) return ((int)day1 - (int)day2 + DaysPerWeek) % DaysPerWeek; } - /// /// Sorts a collection of days of week based on their offsets from a specified first day of week. /// A collection of days of week. diff --git a/src/Microsoft.FeatureManagement/FeatureManagementBuilder.cs b/src/Microsoft.FeatureManagement/FeatureManagementBuilder.cs index 2b2af56c..ab07a595 100644 --- a/src/Microsoft.FeatureManagement/FeatureManagementBuilder.cs +++ b/src/Microsoft.FeatureManagement/FeatureManagementBuilder.cs @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // +using Microsoft.Extensions.DependencyInjection; +using Microsoft.FeatureManagement.FeatureFilters; using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.FeatureManagement.FeatureFilters; namespace Microsoft.FeatureManagement { @@ -35,7 +35,7 @@ public IFeatureManagementBuilder AddFeatureFilter() where T : IFeatureFilterM } IEnumerable featureFilterImplementations = implementationType.GetInterfaces() - .Where(i => i == typeof(IFeatureFilter) || + .Where(i => i == typeof(IFeatureFilter) || (i.IsGenericType && i.GetGenericTypeDefinition().IsAssignableFrom(typeof(IContextualFeatureFilter<>)))); if (featureFilterImplementations.Count() > 1) diff --git a/src/Microsoft.FeatureManagement/FeatureManager.cs b/src/Microsoft.FeatureManagement/FeatureManager.cs index 9080929d..ec7ae990 100644 --- a/src/Microsoft.FeatureManagement/FeatureManager.cs +++ b/src/Microsoft.FeatureManagement/FeatureManager.cs @@ -144,7 +144,7 @@ private async Task IsEnabledAsync(string feature, TContext appCo if (featureDefinition.RequirementType == RequirementType.All && _options.IgnoreMissingFeatureFilters) { throw new FeatureManagementException( - FeatureManagementError.Conflict, + FeatureManagementError.Conflict, $"The 'IgnoreMissingFeatureFilters' flag cannot use used in combination with a feature of requirement type 'All'."); } @@ -183,7 +183,7 @@ private async Task IsEnabledAsync(string feature, TContext appCo enabled = true; break; } - + continue; } @@ -268,7 +268,7 @@ await contextualFilter.EvaluateAsync(context, appContext).ConfigureAwait(false) { throw new FeatureManagementException(FeatureManagementError.MissingFeature, errorMessage); } - + Logger?.LogDebug(errorMessage); } @@ -335,7 +335,8 @@ private IFeatureFilterMetadata GetFeatureFilterMetadata(string filterName, Type { IFeatureFilterMetadata filter = _filterMetadataCache.GetOrAdd( $"{filterName}{Environment.NewLine}{appContextType?.FullName}", - (_) => { + (_) => + { IEnumerable matchingFilters = _featureFilters.Where(f => { @@ -413,7 +414,8 @@ private ContextualFeatureFilterEvaluator GetContextualFeatureFilter(string filte ContextualFeatureFilterEvaluator filter = _contextualFeatureFilterCache.GetOrAdd( $"{filterName}{Environment.NewLine}{appContextType.FullName}", - (_) => { + (_) => + { IFeatureFilterMetadata metadata = GetFeatureFilterMetadata(filterName, appContextType); diff --git a/src/Microsoft.FeatureManagement/IFilterParametersBinder.cs b/src/Microsoft.FeatureManagement/IFilterParametersBinder.cs index bd572e71..fe889893 100644 --- a/src/Microsoft.FeatureManagement/IFilterParametersBinder.cs +++ b/src/Microsoft.FeatureManagement/IFilterParametersBinder.cs @@ -18,4 +18,4 @@ public interface IFilterParametersBinder /// A settings object that is understood by the implementer of . object BindParameters(IConfiguration parameters); } -} \ No newline at end of file +} diff --git a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj index 39cdd2e6..954d6361 100644 --- a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj +++ b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj @@ -1,4 +1,4 @@ - + @@ -52,4 +52,8 @@ + + True + + diff --git a/src/Microsoft.FeatureManagement/MicrosoftFeatureManagementFields.cs b/src/Microsoft.FeatureManagement/MicrosoftFeatureManagementFields.cs index 50351526..20b576b3 100644 --- a/src/Microsoft.FeatureManagement/MicrosoftFeatureManagementFields.cs +++ b/src/Microsoft.FeatureManagement/MicrosoftFeatureManagementFields.cs @@ -24,4 +24,4 @@ internal static class MicrosoftFeatureManagementFields public const string Name = "name"; public const string Parameters = "parameters"; } -} \ No newline at end of file +} diff --git a/src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs b/src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs index b0a9bdd6..50a6ba7f 100644 --- a/src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs +++ b/src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs @@ -42,21 +42,21 @@ public static IFeatureManagementBuilder AddFeatureManagement(this IServiceCollec // Add required services services.TryAddSingleton(); - services.AddSingleton(sp => + services.AddSingleton(sp => new FeatureManager( sp.GetRequiredService(), sp.GetRequiredService>().Value) - { - FeatureFilters = sp.GetRequiredService>(), - SessionManagers = sp.GetRequiredService>(), - Cache = sp.GetRequiredService(), - Logger = sp.GetRequiredService().CreateLogger() - }); + { + FeatureFilters = sp.GetRequiredService>(), + SessionManagers = sp.GetRequiredService>(), + Cache = sp.GetRequiredService(), + Logger = sp.GetRequiredService().CreateLogger() + }); services.AddScoped(); var builder = new FeatureManagementBuilder(services); - + // // Add built-in feature filters builder.AddFeatureFilter(); @@ -119,16 +119,16 @@ public static IFeatureManagementBuilder AddScopedFeatureManagement(this IService // Add required services services.TryAddSingleton(); - services.AddScoped(sp => + services.AddScoped(sp => new FeatureManager( sp.GetRequiredService(), sp.GetRequiredService>().Value) - { - FeatureFilters = sp.GetRequiredService>(), - SessionManagers = sp.GetRequiredService>(), - Cache = sp.GetRequiredService(), - Logger = sp.GetRequiredService().CreateLogger() - }); + { + FeatureFilters = sp.GetRequiredService>(), + SessionManagers = sp.GetRequiredService>(), + Cache = sp.GetRequiredService(), + Logger = sp.GetRequiredService().CreateLogger() + }); services.AddScoped(); @@ -138,7 +138,7 @@ public static IFeatureManagementBuilder AddScopedFeatureManagement(this IService // Add built-in feature filters builder.AddFeatureFilter(); - builder.AddFeatureFilter(sp => + builder.AddFeatureFilter(sp => new TimeWindowFilter() { Cache = sp.GetRequiredService() diff --git a/src/Microsoft.FeatureManagement/Targeting/ContextualTargetingFilter.cs b/src/Microsoft.FeatureManagement/Targeting/ContextualTargetingFilter.cs index b4b43bde..e2c3d5e4 100644 --- a/src/Microsoft.FeatureManagement/Targeting/ContextualTargetingFilter.cs +++ b/src/Microsoft.FeatureManagement/Targeting/ContextualTargetingFilter.cs @@ -132,7 +132,6 @@ public Task EvaluateAsync(FeatureFilterEvaluationContext context, ITargeti return Task.FromResult(IsTargeted(defaultContextId, settings.Audience.DefaultRolloutPercentage)); } - /// /// Determines if a given context id should be targeted based off the provided percentage /// diff --git a/tests/Tests.FeatureManagement.AspNetCore/FeatureManagementAspNetCore.cs b/tests/Tests.FeatureManagement.AspNetCore/FeatureManagementAspNetCore.cs index 3e5d6aa0..19e29dab 100644 --- a/tests/Tests.FeatureManagement.AspNetCore/FeatureManagementAspNetCore.cs +++ b/tests/Tests.FeatureManagement.AspNetCore/FeatureManagementAspNetCore.cs @@ -9,7 +9,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.FeatureManagement; -using System; using System.Collections.Generic; using System.Linq; using System.Net; diff --git a/tests/Tests.FeatureManagement.AspNetCore/MvcFilter.cs b/tests/Tests.FeatureManagement.AspNetCore/MvcFilter.cs index 0635a289..cbf617d5 100644 --- a/tests/Tests.FeatureManagement.AspNetCore/MvcFilter.cs +++ b/tests/Tests.FeatureManagement.AspNetCore/MvcFilter.cs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Filters; +using System.Threading.Tasks; namespace Tests.FeatureManagement.AspNetCore { diff --git a/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj b/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj index b14bbfdb..33f4704a 100644 --- a/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj +++ b/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj @@ -1,4 +1,4 @@ - + net6.0;net7.0;net8.0 @@ -47,4 +47,8 @@ + + True + + diff --git a/tests/Tests.FeatureManagement/CustomTargetingFilter.cs b/tests/Tests.FeatureManagement/CustomTargetingFilter.cs index cc89482f..a0bdbace 100644 --- a/tests/Tests.FeatureManagement/CustomTargetingFilter.cs +++ b/tests/Tests.FeatureManagement/CustomTargetingFilter.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.FeatureManagement; @@ -26,7 +25,7 @@ public CustomTargetingFilter(IOptions options, ILogg public Task EvaluateAsync(FeatureFilterEvaluationContext context) { - return _contextualFilter.EvaluateAsync(context, new TargetingContext(){ UserId = "Jeff" }); + return _contextualFilter.EvaluateAsync(context, new TargetingContext() { UserId = "Jeff" }); } } } diff --git a/tests/Tests.FeatureManagement/FeatureManagement.cs b/tests/Tests.FeatureManagement/FeatureManagement.cs index 964f8dd4..ce337200 100644 --- a/tests/Tests.FeatureManagement/FeatureManagement.cs +++ b/tests/Tests.FeatureManagement/FeatureManagement.cs @@ -106,7 +106,6 @@ public async Task ReadsTopLevelConfiguration() Assert.True(await featureManager.IsEnabledAsync(feature)); } - [Fact] public void AddsScopedFeatureManagement() { @@ -175,7 +174,7 @@ public async Task AllowsDuplicatedFilterAlias() var appContext = new AppContext(); var dummyContext = new DummyContext(); - + var targetingContext = new TargetingContext(); Assert.True(await featureManager.IsEnabledAsync(featureName)); @@ -271,7 +270,7 @@ public async Task CustomFilterContextualTargetingWithNullSetting() IConfiguration config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); ServiceCollection services = new ServiceCollection(); - + var targetingContextAccessor = new OnDemandTargetingContextAccessor(); services.AddSingleton(targetingContextAccessor); @@ -343,7 +342,7 @@ public async Task TimeWindow() Assert.False(await featureManager.IsEnabledAsync(feature4)); Assert.True(await featureManager.IsEnabledAsync(feature5)); Assert.False(await featureManager.IsEnabledAsync(feature6)); - + for (int i = 0; i < 10; i++) { Assert.True(await featureManager.IsEnabledAsync(Features.RecurringTimeWindowTestFeature)); @@ -882,7 +881,6 @@ public async Task UsesRequirementType() // Set filters to all return true testFeatureFilter.Callback = _ => Task.FromResult(true); - Assert.True(await featureManager.IsEnabledAsync(anyFilterFeature)); Assert.True(await featureManager.IsEnabledAsync(allFilterFeature)); diff --git a/tests/Tests.FeatureManagement/RecurrenceEvaluation.cs b/tests/Tests.FeatureManagement/RecurrenceEvaluation.cs index 50c6e449..184f3612 100644 --- a/tests/Tests.FeatureManagement/RecurrenceEvaluation.cs +++ b/tests/Tests.FeatureManagement/RecurrenceEvaluation.cs @@ -594,7 +594,7 @@ public void MatchDailyRecurrenceTest() Range = new RecurrenceRange() } }, - false ), + false ) }; ConsumeEvaluationTestData(testData); @@ -1671,7 +1671,7 @@ public async void RecurrenceEvaluationThroughCacheTest() mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-7T00:00:00+08:00"); Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context)); - for (int i = 0; i < 10; i++ ) + for (int i = 0; i < 10; i++) { mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddDays(1); Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context)); diff --git a/tests/Tests.FeatureManagement/Tests.FeatureManagement.csproj b/tests/Tests.FeatureManagement/Tests.FeatureManagement.csproj index ebf99ad6..fbde38d2 100644 --- a/tests/Tests.FeatureManagement/Tests.FeatureManagement.csproj +++ b/tests/Tests.FeatureManagement/Tests.FeatureManagement.csproj @@ -1,4 +1,4 @@ - + net48;net6.0;net7.0;net8.0 @@ -51,4 +51,8 @@ + + True + + From 106ccc431ab963260b3d6a5af88cc2f2ffa9bcb7 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> Date: Thu, 18 Jul 2024 00:08:45 +0800 Subject: [PATCH 5/6] Add directory props (#474) * add directory props * update --- Directory.Build.props | 7 +++++++ examples/BlazorServerApp/BlazorServerApp.csproj | 4 ---- examples/ConsoleApp/ConsoleApp.csproj | 6 +----- examples/FeatureFlagDemo/FeatureFlagDemo.csproj | 4 ---- examples/RazorPages/RazorPages.csproj | 4 ---- examples/TargetingConsoleApp/TargetingConsoleApp.csproj | 4 ---- .../Microsoft.FeatureManagement.AspNetCore.csproj | 4 ---- .../Microsoft.FeatureManagement.csproj | 4 ---- .../Tests.FeatureManagement.AspNetCore.csproj | 6 +----- .../Tests.FeatureManagement/Tests.FeatureManagement.csproj | 4 ---- 10 files changed, 9 insertions(+), 38 deletions(-) create mode 100644 Directory.Build.props diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..e1220a8d --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,7 @@ + + + + True + + + \ No newline at end of file diff --git a/examples/BlazorServerApp/BlazorServerApp.csproj b/examples/BlazorServerApp/BlazorServerApp.csproj index 115de563..eeae537e 100644 --- a/examples/BlazorServerApp/BlazorServerApp.csproj +++ b/examples/BlazorServerApp/BlazorServerApp.csproj @@ -9,8 +9,4 @@ - - True - - diff --git a/examples/ConsoleApp/ConsoleApp.csproj b/examples/ConsoleApp/ConsoleApp.csproj index 1ef47ac8..8a40ebaf 100644 --- a/examples/ConsoleApp/ConsoleApp.csproj +++ b/examples/ConsoleApp/ConsoleApp.csproj @@ -20,9 +20,5 @@ Always - - - True - - + diff --git a/examples/FeatureFlagDemo/FeatureFlagDemo.csproj b/examples/FeatureFlagDemo/FeatureFlagDemo.csproj index c3955ace..94a10cc8 100644 --- a/examples/FeatureFlagDemo/FeatureFlagDemo.csproj +++ b/examples/FeatureFlagDemo/FeatureFlagDemo.csproj @@ -32,8 +32,4 @@ - - True - - diff --git a/examples/RazorPages/RazorPages.csproj b/examples/RazorPages/RazorPages.csproj index 7eab2e16..2a2cbb46 100644 --- a/examples/RazorPages/RazorPages.csproj +++ b/examples/RazorPages/RazorPages.csproj @@ -10,8 +10,4 @@ - - True - - diff --git a/examples/TargetingConsoleApp/TargetingConsoleApp.csproj b/examples/TargetingConsoleApp/TargetingConsoleApp.csproj index c699e5ab..2d3d3985 100644 --- a/examples/TargetingConsoleApp/TargetingConsoleApp.csproj +++ b/examples/TargetingConsoleApp/TargetingConsoleApp.csproj @@ -20,9 +20,5 @@ Always - - - True - diff --git a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj index c35cf77b..7e6b3226 100644 --- a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj +++ b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj @@ -44,8 +44,4 @@ - - True - - diff --git a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj index 954d6361..95e64f26 100644 --- a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj +++ b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj @@ -52,8 +52,4 @@ - - True - - diff --git a/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj b/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj index 33f4704a..4f9cbc6b 100644 --- a/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj +++ b/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj @@ -46,9 +46,5 @@ Always - - - True - - + diff --git a/tests/Tests.FeatureManagement/Tests.FeatureManagement.csproj b/tests/Tests.FeatureManagement/Tests.FeatureManagement.csproj index fbde38d2..c75fb404 100644 --- a/tests/Tests.FeatureManagement/Tests.FeatureManagement.csproj +++ b/tests/Tests.FeatureManagement/Tests.FeatureManagement.csproj @@ -51,8 +51,4 @@ - - True - - From 7557b1db7d68c2e1080fb69a03f780ee5794b1cc Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Thu, 18 Jul 2024 14:13:33 +0800 Subject: [PATCH 6/6] adjust spacing --- examples/BlazorServerApp/BlazorServerApp.csproj | 2 +- examples/ConsoleApp/ConsoleApp.csproj | 2 +- examples/TargetingConsoleApp/TargetingConsoleApp.csproj | 4 ++-- .../Microsoft.FeatureManagement.AspNetCore.csproj | 3 ++- .../Microsoft.FeatureManagement.csproj | 1 + .../Tests.FeatureManagement.AspNetCore.csproj | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/BlazorServerApp/BlazorServerApp.csproj b/examples/BlazorServerApp/BlazorServerApp.csproj index eeae537e..e1ab1c73 100644 --- a/examples/BlazorServerApp/BlazorServerApp.csproj +++ b/examples/BlazorServerApp/BlazorServerApp.csproj @@ -4,7 +4,7 @@ net6.0 enable - + diff --git a/examples/ConsoleApp/ConsoleApp.csproj b/examples/ConsoleApp/ConsoleApp.csproj index 8a40ebaf..fe29b948 100644 --- a/examples/ConsoleApp/ConsoleApp.csproj +++ b/examples/ConsoleApp/ConsoleApp.csproj @@ -20,5 +20,5 @@ Always - + diff --git a/examples/TargetingConsoleApp/TargetingConsoleApp.csproj b/examples/TargetingConsoleApp/TargetingConsoleApp.csproj index 2d3d3985..fe29b948 100644 --- a/examples/TargetingConsoleApp/TargetingConsoleApp.csproj +++ b/examples/TargetingConsoleApp/TargetingConsoleApp.csproj @@ -5,7 +5,7 @@ net6.0 enable - + @@ -20,5 +20,5 @@ Always - + diff --git a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj index 5610dc3a..bdafc42d 100644 --- a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj +++ b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj @@ -1,4 +1,5 @@ + @@ -31,7 +32,7 @@ https://aka.ms/AzureAppConfigurationPackageIcon © Microsoft Corporation. All rights reserved. - + diff --git a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj index be817edb..5ffcb495 100644 --- a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj +++ b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj @@ -1,4 +1,5 @@ + diff --git a/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj b/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj index 4f9cbc6b..47592cc5 100644 --- a/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj +++ b/tests/Tests.FeatureManagement.AspNetCore/Tests.FeatureManagement.AspNetCore.csproj @@ -46,5 +46,5 @@ Always - +