From 9f03a2f563ebf854ac4f71a4ec03f2afc85c8a0f Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 12:54:33 +0530 Subject: [PATCH 01/13] Migrate solution to .NET 10 - Retarget all projects to net10.0 (was netstandard2.1 / net6.0 / netcoreapp3.1) - Replace legacy ASP.NET Core 2.2 package refs with FrameworkReference Microsoft.AspNetCore.App - Bump JwtBearer and System.Drawing.Common to satisfy MISE 1.35.0 transitive requirements - Remove dead 'using static HostingApplication' imports removed after ASP.NET Core 2.2 - Update CI and Azure DevOps pipelines to install .NET 10 SDK Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- .github/workflows/ci.yml | 13 ++++--------- assets/pipeline/cd-feature-flights-management.yml | 4 ++-- assets/pipeline/templates/app-service-deploy.yml | 4 ++-- .../API/Microsoft.FeatureFlighting.API.csproj | 6 +++--- .../Cache/Microsoft.FeatureFlighting.Cache.csproj | 2 +- .../Common/Microsoft.FeatureFlighting.Common.csproj | 2 +- src/service/Domain/FeatureFilters/BaseFilter.cs | 1 - .../Domain/Microsoft.FeatureFlighting.Core.csproj | 4 ++-- .../AppConfig/AzureConfigurationClientProvider.cs | 1 - ...Microsoft.FeatureFlighting.Infrastructure.csproj | 2 +- .../Microsoft.FeatureFlighting.Services.csproj | 4 ++-- .../Microsoft.FeatureFlighting.API.Tests.csproj | 2 +- .../Microsoft.FeatureFlighting.Common.Tests.csproj | 2 +- .../Domain.Tests/FilterTests/CountryFilterTests.cs | 1 - .../Microsoft.PS.FlightingService.Core.Tests.csproj | 4 ++-- ...oft.FeatureFlighting.Infrastructure.Tests.csproj | 5 ++--- ...crosoft.FeatureFlighting.Tests.Functional.csproj | 2 +- 17 files changed, 25 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf159d2..5ecda69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,17 +12,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - name: Setup .NET 3.1.x - uses: actions/setup-dotnet@v1 + - name: Setup .NET 10.x + uses: actions/setup-dotnet@v4 with: - dotnet-version: 3.1.x - - - name: Setup .NET 6.x - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 6.x.x + dotnet-version: 10.0.x - name: Restore dependencies run: dotnet restore src/service/Microsoft.FeatureFlighting.sln diff --git a/assets/pipeline/cd-feature-flights-management.yml b/assets/pipeline/cd-feature-flights-management.yml index 3572567..48a863e 100644 --- a/assets/pipeline/cd-feature-flights-management.yml +++ b/assets/pipeline/cd-feature-flights-management.yml @@ -26,9 +26,9 @@ stages: versionSpec: 4.3.0 checkLatest: true - task: UseDotNet@2 - displayName: Use .Net Core sdk 3.1.x + displayName: Use .NET sdk 10.0.x inputs: - version: 3.1.x + version: 10.0.x includePreviewVersions: true - task: DotNetCoreCLI@2 displayName: Restore API (Microsoft.FeatureFlighting.sln) diff --git a/assets/pipeline/templates/app-service-deploy.yml b/assets/pipeline/templates/app-service-deploy.yml index 4ad7dde..63a6442 100644 --- a/assets/pipeline/templates/app-service-deploy.yml +++ b/assets/pipeline/templates/app-service-deploy.yml @@ -28,9 +28,9 @@ steps: Folder: '$(System.ArtifactsDirectory)/drop/FunctionalTests' - task: UseDotNet@2 - displayName: 'Use .Net Core sdk 3.1.x' + displayName: 'Use .NET sdk 10.0.x' inputs: - version: 3.1.x + version: 10.0.x - task: AzureKeyVault@1 displayName: 'Azure Key Vault: Download Secrets' diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index f342293..8f4e2d0 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -1,7 +1,7 @@  - net6.0 + net10.0 InProcess True @@ -22,7 +22,7 @@ - + @@ -41,7 +41,7 @@ - + diff --git a/src/service/Cache/Microsoft.FeatureFlighting.Cache.csproj b/src/service/Cache/Microsoft.FeatureFlighting.Cache.csproj index 00b2e64..f82a0bd 100644 --- a/src/service/Cache/Microsoft.FeatureFlighting.Cache.csproj +++ b/src/service/Cache/Microsoft.FeatureFlighting.Cache.csproj @@ -1,7 +1,7 @@ - netstandard2.1 + net10.0 diff --git a/src/service/Common/Microsoft.FeatureFlighting.Common.csproj b/src/service/Common/Microsoft.FeatureFlighting.Common.csproj index a9be514..a8d3a91 100644 --- a/src/service/Common/Microsoft.FeatureFlighting.Common.csproj +++ b/src/service/Common/Microsoft.FeatureFlighting.Common.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net10.0 Preview diff --git a/src/service/Domain/FeatureFilters/BaseFilter.cs b/src/service/Domain/FeatureFilters/BaseFilter.cs index ffd4715..2356aec 100644 --- a/src/service/Domain/FeatureFilters/BaseFilter.cs +++ b/src/service/Domain/FeatureFilters/BaseFilter.cs @@ -15,7 +15,6 @@ using Microsoft.FeatureFlighting.Core.Operators; using Microsoft.FeatureFlighting.Common.AppExceptions; using static Microsoft.FeatureFlighting.Common.Constants; -using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication; namespace Microsoft.FeatureFlighting.Core.FeatureFilters { diff --git a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj index b68389c..d747b53 100644 --- a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj +++ b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net10.0 Preview @@ -14,7 +14,7 @@ - + diff --git a/src/service/Infrastructure/AppConfig/AzureConfigurationClientProvider.cs b/src/service/Infrastructure/AppConfig/AzureConfigurationClientProvider.cs index 36678cb..45780fa 100644 --- a/src/service/Infrastructure/AppConfig/AzureConfigurationClientProvider.cs +++ b/src/service/Infrastructure/AppConfig/AzureConfigurationClientProvider.cs @@ -4,7 +4,6 @@ using Azure.Identity; using Microsoft.Extensions.Configuration; using Microsoft.FeatureFlighting.Common; -using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication; namespace Microsoft.FeatureFlighting.Infrastructure.AppConfig { diff --git a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj index 2e49800..7656ca5 100644 --- a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj +++ b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net10.0 enable Preview diff --git a/src/service/Services/Microsoft.FeatureFlighting.Services.csproj b/src/service/Services/Microsoft.FeatureFlighting.Services.csproj index 7c66b46..b9f8ae6 100644 --- a/src/service/Services/Microsoft.FeatureFlighting.Services.csproj +++ b/src/service/Services/Microsoft.FeatureFlighting.Services.csproj @@ -1,12 +1,12 @@  - netstandard2.1 + net10.0 - + diff --git a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj index 591d90f..0aef47d 100644 --- a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj +++ b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 false diff --git a/src/service/Tests/Common.Tests/Microsoft.FeatureFlighting.Common.Tests.csproj b/src/service/Tests/Common.Tests/Microsoft.FeatureFlighting.Common.Tests.csproj index 39c9352..0864c20 100644 --- a/src/service/Tests/Common.Tests/Microsoft.FeatureFlighting.Common.Tests.csproj +++ b/src/service/Tests/Common.Tests/Microsoft.FeatureFlighting.Common.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net10.0 false diff --git a/src/service/Tests/Domain.Tests/FilterTests/CountryFilterTests.cs b/src/service/Tests/Domain.Tests/FilterTests/CountryFilterTests.cs index edd5c2e..7d60574 100644 --- a/src/service/Tests/Domain.Tests/FilterTests/CountryFilterTests.cs +++ b/src/service/Tests/Domain.Tests/FilterTests/CountryFilterTests.cs @@ -11,7 +11,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.FeatureFlighting.Common.AppExceptions; using Microsoft.FeatureFlighting.Core.FeatureFilters; -using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication; namespace Microsoft.FeatureFlighting.Core.Tests.FilterTests { diff --git a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj index 9afd482..923c277 100644 --- a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj +++ b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj @@ -1,7 +1,7 @@  - net6.0 + net10.0 false Preview @@ -12,7 +12,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj index 86edc68..0995527 100644 --- a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj +++ b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 false Preview @@ -20,8 +20,7 @@ - - + diff --git a/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj b/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj index d48f059..123eee6 100644 --- a/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj +++ b/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net10.0 Preview false From 19d675fa0e678be28d17d20c93b237aef48b95fc Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 15:07:30 +0530 Subject: [PATCH 02/13] Remove redundant package references provided by .NET 10 shared framework Removes NU1510-flagged PackageReferences now supplied by the runtime/ASP.NET Core shared framework: Microsoft.AspNetCore.Hosting.Abstractions, Microsoft.AspNetCore.Http.Abstractions, Microsoft.Extensions.Logging.Debug, Microsoft.Extensions.Configuration.Binder, System.Text.Encodings.Web. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- src/service/API/Microsoft.FeatureFlighting.API.csproj | 3 --- .../Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj | 1 - .../Microsoft.PS.FlightingService.Core.Tests.csproj | 2 -- .../Microsoft.FeatureFlighting.Infrastructure.Tests.csproj | 1 - 4 files changed, 7 deletions(-) diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index 8f4e2d0..68657d1 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -23,11 +23,8 @@ - - - diff --git a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj index 0aef47d..f43b0a2 100644 --- a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj +++ b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj @@ -21,7 +21,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj index 923c277..afed106 100644 --- a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj +++ b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj @@ -13,14 +13,12 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - diff --git a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj index 0995527..1cff4d7 100644 --- a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj +++ b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj @@ -31,7 +31,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - From 532e769389aff3a5aff6dfc1f85412eba67d9174 Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 16:41:16 +0530 Subject: [PATCH 03/13] Upgrade NuGet packages to latest compatible versions (Wave 1: safe bumps) Bump non-breaking package versions across all projects and align transitive floors surfaced by NU1605: - Azure SDKs: Identity 1.21.0, AppConfiguration 1.10.0, Storage.Blobs 12.29.1, Cosmos 3.62.0, KeyVault.Secrets 4.11.0, Security config secrets 1.5.1 - Newtonsoft.Json 13.0.4, System.Linq.Dynamic.Core 1.7.3, UnifiedRedisPlatform 1.0.4 - Microsoft.Extensions.* + JwtBearer + System.Drawing.Common -> 10.0.10 - IdentityModel.Validators 8.21.0, Identity.Client 4.84.2 (Azure.Core 1.59 floor) - NuGet.Packaging/Protocol 6.12.1 (CodeGeneration.Design 10.0.2 floor) - Test stack: Microsoft.NET.Test.Sdk 18.8.1, Moq 4.20.72, coverlet 10.0.1, MSTest.TestAdapter/Framework 4.3.2 Migrate 3 [ExpectedException] usages to Assert.ThrowsExactly/ThrowsExactlyAsync (removed in MSTest 4). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- .../API/Microsoft.FeatureFlighting.API.csproj | 22 +++++++++---------- .../Microsoft.FeatureFlighting.Cache.csproj | 2 +- .../Microsoft.FeatureFlighting.Common.csproj | 4 ++-- .../Microsoft.FeatureFlighting.Core.csproj | 10 ++++----- ...oft.FeatureFlighting.Infrastructure.csproj | 16 +++++++------- ...Microsoft.FeatureFlighting.Services.csproj | 8 +++---- ...icrosoft.FeatureFlighting.API.Tests.csproj | 16 +++++++------- ...osoft.FeatureFlighting.Common.Tests.csproj | 14 ++++++------ .../FilterTests/CountryFilterTests.cs | 4 +--- ...soft.PS.FlightingService.Core.Tests.csproj | 16 +++++++------- .../MemberOfSecurityGroupEvaluatorTests.cs | 4 +--- .../AuthorizationServiceTests.cs | 3 +-- ...atureFlighting.Infrastructure.Tests.csproj | 16 +++++++------- ...t.FeatureFlighting.Tests.Functional.csproj | 14 ++++++------ 14 files changed, 72 insertions(+), 77 deletions(-) diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index 68657d1..85d5f69 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -20,25 +20,25 @@ - - - + + + - + - - - - - - + + + + + + - + diff --git a/src/service/Cache/Microsoft.FeatureFlighting.Cache.csproj b/src/service/Cache/Microsoft.FeatureFlighting.Cache.csproj index f82a0bd..612fb4d 100644 --- a/src/service/Cache/Microsoft.FeatureFlighting.Cache.csproj +++ b/src/service/Cache/Microsoft.FeatureFlighting.Cache.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/service/Common/Microsoft.FeatureFlighting.Common.csproj b/src/service/Common/Microsoft.FeatureFlighting.Common.csproj index a8d3a91..208fc46 100644 --- a/src/service/Common/Microsoft.FeatureFlighting.Common.csproj +++ b/src/service/Common/Microsoft.FeatureFlighting.Common.csproj @@ -8,9 +8,9 @@ - + - + diff --git a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj index d747b53..dd1a76d 100644 --- a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj +++ b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj @@ -12,14 +12,14 @@ - - + + - - + + - + diff --git a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj index 7656ca5..78cc371 100644 --- a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj +++ b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj @@ -7,15 +7,15 @@ - - - - - + + + + + - - - + + + diff --git a/src/service/Services/Microsoft.FeatureFlighting.Services.csproj b/src/service/Services/Microsoft.FeatureFlighting.Services.csproj index b9f8ae6..094ab77 100644 --- a/src/service/Services/Microsoft.FeatureFlighting.Services.csproj +++ b/src/service/Services/Microsoft.FeatureFlighting.Services.csproj @@ -5,12 +5,12 @@ - + - - + + - + diff --git a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj index f43b0a2..a05ef21 100644 --- a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj +++ b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj @@ -7,17 +7,17 @@ - - + + - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/service/Tests/Common.Tests/Microsoft.FeatureFlighting.Common.Tests.csproj b/src/service/Tests/Common.Tests/Microsoft.FeatureFlighting.Common.Tests.csproj index 0864c20..7fac0fa 100644 --- a/src/service/Tests/Common.Tests/Microsoft.FeatureFlighting.Common.Tests.csproj +++ b/src/service/Tests/Common.Tests/Microsoft.FeatureFlighting.Common.Tests.csproj @@ -6,16 +6,16 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/service/Tests/Domain.Tests/FilterTests/CountryFilterTests.cs b/src/service/Tests/Domain.Tests/FilterTests/CountryFilterTests.cs index 7d60574..3b08d4d 100644 --- a/src/service/Tests/Domain.Tests/FilterTests/CountryFilterTests.cs +++ b/src/service/Tests/Domain.Tests/FilterTests/CountryFilterTests.cs @@ -251,12 +251,10 @@ public async Task Feature_Filter_Must_Evaluate_To_False_For_StageId_Being_Begati } [TestMethod] - [ExpectedException(typeof(EvaluationException))] public async Task Feature_Filter_GetFilterSettings_Must_Evaluate_To_False() { CountryFilter countryFilter = new CountryFilter(configMock.Object, httpContextAccessorMockInDefinedInt.Object, loggerMock.Object, failureMockEvaluatorStrategy.Object); - var featureFlagStatus = await countryFilter.EvaluateAsync(null); - Assert.IsFalse(featureFlagStatus); + await Assert.ThrowsExactlyAsync(async () => await countryFilter.EvaluateAsync(null)); } [TestMethod] diff --git a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj index afed106..2e1cc30 100644 --- a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj +++ b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj @@ -7,18 +7,18 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - + + + + + + diff --git a/src/service/Tests/Domain.Tests/OperatorTests/MemberOfSecurityGroupEvaluatorTests.cs b/src/service/Tests/Domain.Tests/OperatorTests/MemberOfSecurityGroupEvaluatorTests.cs index 51371cf..ddbfea8 100644 --- a/src/service/Tests/Domain.Tests/OperatorTests/MemberOfSecurityGroupEvaluatorTests.cs +++ b/src/service/Tests/Domain.Tests/OperatorTests/MemberOfSecurityGroupEvaluatorTests.cs @@ -170,7 +170,6 @@ public async Task evaluate_sg_operator_returns_false_for_value_not_inSG_for_alai Assert.AreEqual(evaluationResult.Result, false); } [TestMethod] - [ExpectedException(typeof(GraphException))] public async Task evaluate_sg_operator_throws_exception_whenfor_value_not_inSG_for_alais() { //Arrange @@ -184,8 +183,7 @@ public async Task evaluate_sg_operator_throws_exception_whenfor_value_not_inSG_f }; evaluator = new MemberOfSecurityGroupOperator(mockGraphApiProviderWithUpnAliasInSGException.Object, mockConfig.Object); //Act - var evaluationResult = await evaluator.Evaluate(configuredValue, contextValue, filterType, trackingIds); - + await Assert.ThrowsExactlyAsync(async () => await evaluator.Evaluate(configuredValue, contextValue, filterType, trackingIds)); } } } diff --git a/src/service/Tests/Services.Tests/AuthorizationServiceTests.cs b/src/service/Tests/Services.Tests/AuthorizationServiceTests.cs index 9d5173e..8efe4b1 100644 --- a/src/service/Tests/Services.Tests/AuthorizationServiceTests.cs +++ b/src/service/Tests/Services.Tests/AuthorizationServiceTests.cs @@ -45,12 +45,11 @@ public void Must_Authorize_When_Admin_Claims_Are_Present() authService.EnsureAuthorized("TestApp", "TestOp", "CorrId"); } - [ExpectedException(typeof(AccessForbiddenException))] [TestMethod] public void Must_Authorize_When_Claims_Are_Not_Present() { IAuthorizationService authService = new AuthorizationService(httpAccessorMockWithoutPermissions.Object, _tenantConfigurationProvider, _mockConfiguration); - authService.EnsureAuthorized("TestApp", "TestOp", "CorrId"); + Assert.ThrowsExactly(() => authService.EnsureAuthorized("TestApp", "TestOp", "CorrId")); } [TestMethod] diff --git a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj index 1cff4d7..a715404 100644 --- a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj +++ b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj @@ -19,18 +19,18 @@ - + - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj b/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj index 123eee6..501fb7c 100644 --- a/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj +++ b/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj @@ -7,16 +7,16 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 65a504008ce5d179efc995540e179cf951242ccf Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 17:02:56 +0530 Subject: [PATCH 04/13] Upgrade MISE (Identity.ServiceEssentials) 1.35.0 -> 2.5.3 MISE 2.x is a breaking redesign. Changes: - Bump Microsoft.Identity.ServiceEssentials.AspNetCore + .Caching to 2.5.3 - Drop Microsoft.Identity.ServiceEssentials.Extensions.AspNetCoreMiddleware (no 2.x; middleware folded into the AspNetCore metapackage) - ServicesExtensions.AddAuthentication: AddMiseWithDefaultAuthentication -> AddMiseWithDefaultModules; options now set via MiseOptions.AzureAd (Authority/Audiences/ClientId/Instance/TenantId) - Auth scheme constant S2SAuthenticationDefaults.AuthenticationScheme -> MiseAuthenticationDefaults.AuthenticationScheme (same value 'S2SAuthentication'; MISE 2.x no longer pulls the S2S package transitively) - UseMise namespace: ...Extensions.AspNetCoreMiddleware -> Microsoft.Identity.ServiceEssentials Builds clean; all 219 unit tests pass. NOTE: token validation/auth wiring is not exercised by unit tests - integration/auth testing recommended before merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- .../API/Extensions/ServicesExtensions.cs | 25 +++++++++---------- .../API/Microsoft.FeatureFlighting.API.csproj | 5 ++-- src/service/API/Middlewares/MSALMiddleware.cs | 4 +-- src/service/API/Startup.cs | 2 +- ...icrosoft.FeatureFlighting.API.Tests.csproj | 5 ++-- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/service/API/Extensions/ServicesExtensions.cs b/src/service/API/Extensions/ServicesExtensions.cs index a3a7360..f2e6e34 100644 --- a/src/service/API/Extensions/ServicesExtensions.cs +++ b/src/service/API/Extensions/ServicesExtensions.cs @@ -15,8 +15,8 @@ using Microsoft.FeatureFlighting.Api.ExceptionHandler; using AppInsights.EnterpriseTelemetry.Web.Extension.Middlewares; using Microsoft.IdentityModel.Validators; -using Microsoft.Identity.ServiceEssentials.Extensions.AspNetCoreMiddleware; -using Microsoft.IdentityModel.S2S.Extensions.AspNetCore; +using Microsoft.Identity.ServiceEssentials; +using Microsoft.Identity.ServiceEssentials.Configuration; using System.Configuration; @@ -29,23 +29,22 @@ internal static class ServicesExtensions /// public static void AddAuthentication(this IServiceCollection services, IConfiguration configuration) { - services.AddAuthentication(S2SAuthenticationDefaults.AuthenticationScheme) - .AddMiseWithDefaultAuthentication(configuration, options => + services.AddAuthentication(MiseAuthenticationDefaults.AuthenticationScheme) + .AddMiseWithDefaultModules(configuration, miseOptions => { var primaryAudience = configuration["Authentication:Audience"]; IList validAudiences = !string.IsNullOrWhiteSpace(configuration["Authentication:AdditionalAudiences"]) ? configuration["Authentication:AdditionalAudiences"].Split(',').ToList() : new List(); validAudiences.Add(primaryAudience); - options.Authority= configuration["Authentication:Authority"]; - foreach (var audience in validAudiences) - { - options.Audiences.Add(audience); - } - options.ClientId = configuration["ClientInfo:ClientId"]; - options.Instance = configuration["InstanceInfo:Instance"]; - options.TenantId = configuration["TenantInfo:Tenant"]; - }); + + miseOptions.AzureAd ??= new MiseAuthenticationOptions(); + miseOptions.AzureAd.Authority = configuration["Authentication:Authority"]; + miseOptions.AzureAd.Audiences = validAudiences; + miseOptions.AzureAd.ClientId = configuration["ClientInfo:ClientId"]; + miseOptions.AzureAd.Instance = configuration["InstanceInfo:Instance"]; + miseOptions.AzureAd.TenantId = configuration["TenantInfo:Tenant"]; + }, MiseAuthenticationDefaults.AuthenticationScheme); } diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index 85d5f69..1bb459e 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -28,9 +28,8 @@ - - - + + diff --git a/src/service/API/Middlewares/MSALMiddleware.cs b/src/service/API/Middlewares/MSALMiddleware.cs index 11a8d96..fd234ef 100644 --- a/src/service/API/Middlewares/MSALMiddleware.cs +++ b/src/service/API/Middlewares/MSALMiddleware.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using System.Threading.Tasks; -using Microsoft.IdentityModel.S2S.Extensions.AspNetCore; +using Microsoft.Identity.ServiceEssentials; namespace Microsoft.FeatureFlighting.Api.Middlewares { @@ -17,7 +17,7 @@ public MSALMiddleware(RequestDelegate next) public async Task Invoke(HttpContext httpContext) { - var result = await httpContext.AuthenticateAsync(S2SAuthenticationDefaults.AuthenticationScheme); + var result = await httpContext.AuthenticateAsync(MiseAuthenticationDefaults.AuthenticationScheme); if (result.Succeeded || httpContext.Request.Path.Value == "/api/probe/ping") { httpContext.User = result.Principal; diff --git a/src/service/API/Startup.cs b/src/service/API/Startup.cs index 63737b2..1256445 100644 --- a/src/service/API/Startup.cs +++ b/src/service/API/Startup.cs @@ -16,7 +16,7 @@ using Microsoft.FeatureFlighting.API.Controllers; using AppInsights.EnterpriseTelemetry.Web.Extension; using AppInsights.EnterpriseTelemetry.Web.Extension.Filters; -using Microsoft.Identity.ServiceEssentials.Extensions.AspNetCoreMiddleware; +using Microsoft.Identity.ServiceEssentials; namespace Microsoft.PS.Services.FlightingService.Api { diff --git a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj index a05ef21..a20823b 100644 --- a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj +++ b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj @@ -9,9 +9,8 @@ - - - + + From ae0c3d5e07d383ab96a206cf6d367c0617506ce7 Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 17:35:20 +0530 Subject: [PATCH 05/13] MISE 2.x: add explicit inbound policy to match compliant reference (PR 2003349) Aligns the MISE 2.x auth setup with the reviewed CE-FS-FExP-PageTour MISE 2.X compliance implementation: - Configure MiseInboundPolicyOptions with a Bearer protocol accepting both app and user tokens (AppToken/UserToken/AllowMissingIdTypeClaim). MISE 2.x needs an explicit inbound policy - AzureAd audiences alone do not validate inbound tokens. - Set AzureAd.Audience (single) and expand Audiences to include api:// URI forms and the client id (v1.0/v2.0 token audience formats), plus AdditionalAudiences in both raw and api:// forms. - Drop explicit Authority; rely on Instance + TenantId (MISE-derived authority), matching the reference. - Remove redundant app.UseMise(); the AddMiseWithDefaultModules handler validates inbound tokens via UseAuthentication + AuthenticateAsync (reference does the same). OpenTelemetry.Exporter.Geneva 1.11.2 (the transitive dep the reference pinned) is already resolved automatically here (no central package pinning in this repo). Builds clean; all 219 unit tests pass. Auth behavior still needs integration validation before merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- .../cd-feature-flights-management-build.yml | 188 ++++++++++++++++++ assets/pipeline/ci-feature-flighting.yml | 61 ++++++ .../API/Extensions/ServicesExtensions.cs | 56 +++++- src/service/API/Startup.cs | 4 +- 4 files changed, 295 insertions(+), 14 deletions(-) create mode 100644 assets/pipeline/cd-feature-flights-management-build.yml create mode 100644 assets/pipeline/ci-feature-flighting.yml diff --git a/assets/pipeline/cd-feature-flights-management-build.yml b/assets/pipeline/cd-feature-flights-management-build.yml new file mode 100644 index 0000000..8e9830f --- /dev/null +++ b/assets/pipeline/cd-feature-flights-management-build.yml @@ -0,0 +1,188 @@ +resources: + repositories: + - repository: FeatureFlightingGithub + type: github + endpoint: github.com + name: microsoft/FeatureFlightingManagement + trigger: + - none + - repository: FxpTools + type: git + name: CE-FS-FExP-FxpTools + +variables: + BuildPlatform: 'any cpu' + BuildConfiguration: 'release' +stages: +- stage: Build + jobs: + - job: Build + displayName: "Build & Publish Artifact" + pool: + vmImage: windows-2019 + steps: + - checkout: FeatureFlightingGithub + - checkout: self + - task: NuGetToolInstaller@1 + displayName: Use NuGet 4.3.0 + inputs: + versionSpec: 4.3.0 + checkLatest: true + - task: UseDotNet@2 + displayName: Use .Net Core sdk 3.1.x + inputs: + version: 3.1.x + includePreviewVersions: true + - task: UseDotNet@2 + displayName: Use .Net Core sdk 6.0.x + inputs: + version: 6.0.x + includePreviewVersions: true + - task: DotNetCoreCLI@2 + displayName: Restore API (Microsoft.FeatureFlighting.sln) + inputs: + command: restore + projects: '**/Microsoft.FeatureFlighting.sln' + selectOrConfig: config + feedRestore: c94f6383-c859-4345-ad90-73d2e3bcb70f + nugetConfigPath: NuGet.Config + - task: DotNetCoreCLI@2 + displayName: Build API (Microsoft.FeatureFlighting.sln) + inputs: + projects: '**/Microsoft.FeatureFlighting.sln' + - task: DotNetCoreCLI@2 + displayName: Test API (*.Tests.csproj) + continueOnError: false + inputs: + command: test + projects: '**/*Tests.csproj' + - task: DotNetCoreCLI@2 + displayName: Publish API (Microsoft.FeatureFlighting.sln) + inputs: + command: publish + publishWebProjects: false + projects: '**/Microsoft.FeatureFlighting.API.csproj' + arguments: --output $(Build.artifactstagingdirectory) + - task: DotNetCoreCLI@2 + displayName: Restore Functional Tests (Microsoft.FeatureFlighting.Tests.Functional.sln) + inputs: + command: restore + projects: '**/Microsoft.FeatureFlighting.Tests.Functional.sln' + selectOrConfig: config + feedRestore: c94f6383-c859-4345-ad90-73d2e3bcb70f + nugetConfigPath: NuGet.Config + - task: DotNetCoreCLI@2 + displayName: Build Functional Tests (Microsoft.FeatureFlighting.Tests.Functional.sln) + inputs: + projects: '**/Microsoft.FeatureFlighting.Tests.Functional.sln' + - task: DotNetCoreCLI@2 + displayName: Publish Functional Tests (Microsoft.FeatureFlighting.Tests.Functional.sln) + inputs: + command: publish + publishWebProjects: false + projects: FeatureFlightingManagement/tests/functional/Tests/Microsoft.FeatureFlighting.Tests.Functional.csproj + arguments: --output $(Build.artifactstagingdirectory) + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: drop' + +- stage: Pre_Prod_Perf_Deploy + dependsOn: + - Build + condition: succeeded('Build') + jobs: + - deployment: Pre_Prod_Perf_Deploy_EUS + displayName: Performance Environment Deployment EUS + pool: + name: Azure Pipelines + vmImage: windows-2019 + demands: vstest + variables: + KeyVault-EUS: 'kv-exp-ppe-eus' + AppService-EUS: 'feature-flights-management-api-perf-eus' + AppService-EUS-Staging: 'feature-flights-management-api-perf-eus-staging' + ResourceGroup: 'RG-FieldExperiencePlatform-Uat-01' + Subscription: '05a315f7-744f-4692-b9dd-1aed7c6cee64' + environment: 'PS-GCM-FeXP-Services-Pre-Prod' + strategy: + runOnce: + deploy: + steps: + - checkout: FeatureFlightingGithub + - checkout: self + - powershell: | + [string] $branchName = "refs/heads/master" + [string] $mainBranchName = "refs/heads/main" + [string] $branchNameHotfix = "hotfix" + if ($env:BUILD_SOURCEBRANCH -eq $branchName -Or $env:BUILD_SOURCEBRANCH -contains $mainBranchName -Or $env:BUILD_SOURCEBRANCH -contains $branchNameHotfix) + { + Write-Host $branchName "branch check passed. Release triggered" from $env:BUILD_SOURCEBRANCH branch. + } + else + { + [string] $text1 = "##vso[task.logissue type=error;]" + [string] $text2 = "Branch Policy Violation:" + [string] $text3 = " !=" + [string] $text4 = " | " + [string] $text5 = "branch. Deployment stopped from" + [string] $text6 = "branch." + + Write-Host "$text1 $text2 $env:BUILD_SOURCEBRANCH $text3 $branchName $text4 $mainBranchName $text5 $env:BUILD_SOURCEBRANCH $text6" + + exit 1 + } + displayName: 'Stop Release if not from master | main branch' + enabled: false + - task: AzurePowerShell@5 + displayName: "Add Az IP Agent on UAT EUS KeyVault" + inputs: + azureSubscription: "FXP-Azure-Subscription (SPA)" + ScriptType: InlineScript + azurePowerShellVersion: "LatestVersion" + Inline: | + $VerbosePreference = "SilentlyContinue" + Set-AzContext -SubscriptionId '$(Subscription)' + # Installing MSIdentityTools Module + Write-Host "Installing MSIdentityTools Module to fetch the Azure published IP ranges" + Install-Module -Name MSIdentityTools -Scope CurrentUser -Force + # Allowed IP address. + Write-Host "Getting IP address of Azure DevOps agent" + $IPAddress = (Invoke-WebRequest myexternalip.com/raw -UseBasicParsing).Content + $IPAddressRange = '{0}/32' -f $IPAddress + # Allow current public IP address. + Add-AzKeyVaultNetworkRule -ResourceId '/subscriptions/$(Subscription)/resourceGroups/$(ResourceGroup)/providers/Microsoft.KeyVault/vaults/$(KeyVault-EUS)' -IpAddressRange $IPAddressRange -SubscriptionId '05a315f7-744f-4692-b9dd-1aed7c6cee64' + Write-Host "Successfully appended the IP Address for Azure DevOps" -ForegroundColor Green + FailOnStandardError: true + - task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Download Secrets' + inputs: + azureSubscription: 'FXP-Azure-Subscription (SPA)' + KeyVaultName: '$(KeyVault-EUS)' + SecretsFilter: 'Authentication-Secret,MS-Graph-Secret' + - template: templates/app-service-deploy.yml + parameters: + KeyVault: $(KeyVault-EUS) + AppService: $(AppService-EUS) + ResourceGroup: $(ResourceGroup) + FunctionalTestRunSettingsFile: 'PreProduction.runsettings' + AppServiceStaging: $(AppService-EUS-Staging) + DeploymentAppSettings: '-AppConfiguration:ConfigurationEnvLabel Feature-Flight-Management-Config-PPE -AppConfiguration:FeatureFlightsLabel PPE -Keyvault:EndpointUrl https://kv-exp-ppe-eus.vault.azure.net/ -FeatureManagement:* true' + - task: AzurePowerShell@5 + displayName: "Delete Az IP Agent Address on UAT EUS KeyVault" + inputs: + azureSubscription: "FXP-Azure-Subscription (SPA)" + ScriptType: InlineScript + azurePowerShellVersion: "LatestVersion" + Inline: | + $VerbosePreference = "SilentlyContinue" + Set-AzContext -SubscriptionId '$(Subscription)' + # Installing MSIdentityTools Module + Write-Host "Installing MSIdentityTools Module to fetch the Azure published IP ranges" + Install-Module -Name MSIdentityTools -Scope CurrentUser -Force + # Allowed IP address. + Write-Host "Getting IP address of Azure DevOps agent" + $IPAddress = (Invoke-WebRequest myexternalip.com/raw -UseBasicParsing).Content + $IPAddressRange = '{0}/32' -f $IPAddress + # Delete current public IP address. + Remove-AzKeyVaultNetworkRule -ResourceId '/subscriptions/$(Subscription)/resourceGroups/$(ResourceGroup)/providers/Microsoft.KeyVault/vaults/$(KeyVault-EUS)' -IpAddressRange $IPAddressRange -SubscriptionId '05a315f7-744f-4692-b9dd-1aed7c6cee64' + Write-Host "Successfully deleted the IP Address for Azure DevOps" -ForegroundColor Green + FailOnStandardError: true diff --git a/assets/pipeline/ci-feature-flighting.yml b/assets/pipeline/ci-feature-flighting.yml new file mode 100644 index 0000000..8878320 --- /dev/null +++ b/assets/pipeline/ci-feature-flighting.yml @@ -0,0 +1,61 @@ +resources: + repositories: + - repository: FeatureFlightingGithub + type: github + endpoint: github.com + name: microsoft/FeatureFlightingManagement + trigger: + - main + +trigger: none +name: Feature-Flighting-$(Date:yyyyMMdd)$(Rev:.rr) +jobs: +- job: Build + displayName: Agent job 1 + pool: + vmImage: 'windows-2019' + steps: + - checkout: FeatureFlightingGithub + - task: NuGetToolInstaller@1 + displayName: Use NuGet 4.3.0 + inputs: + versionSpec: 4.3.0 + checkLatest: true + - task: UseDotNet@2 + displayName: Use .Net Core sdk 3.1.x + inputs: + version: 3.1.x + includePreviewVersions: true + - task: DotNetCoreCLI@2 + displayName: Restore API (Microsoft.FeatureFlighting.sln) + inputs: + command: restore + projects: '**/Microsoft.FeatureFlighting.sln' + - task: DotNetCoreCLI@2 + displayName: Build API (Microsoft.FeatureFlighting.sln) + inputs: + projects: '**/Microsoft.FeatureFlighting.sln' + - task: DotNetCoreCLI@2 + displayName: Test API (Microsoft.FeatureFlighting.sln) + enabled: false + inputs: + command: test + projects: '**/*Tests.csproj' + arguments: --collect "Code coverage" + workingDirectory: src/service/ + - task: DotNetCoreCLI@2 + displayName: Restore Functional Tests (Microsoft.FXP.Flighting.Tests.FunctionalTest.csproj) + enabled: false + inputs: + command: restore + projects: tests/Microsoft.FXP.Experimentation.Tests/Microsoft.FXP.Flighting.Tests.FunctionalTest/Microsoft.FXP.Flighting.Tests.FunctionalTest.csproj + selectOrConfig: config + feedRestore: c94f6383-c859-4345-ad90-73d2e3bcb70f + nugetConfigPath: src/Microsoft.PS.FlightingService/NuGet.Config + - task: DotNetCoreCLI@2 + enabled: false + displayName: Build Functional Tests (Microsoft.FXP.Flighting.Tests.FunctionalTest.csproj) + inputs: + projects: tests/Microsoft.FXP.Experimentation.Tests/Microsoft.FXP.Flighting.Tests.FunctionalTest/Microsoft.FXP.Flighting.Tests.FunctionalTest.csproj + + diff --git a/src/service/API/Extensions/ServicesExtensions.cs b/src/service/API/Extensions/ServicesExtensions.cs index f2e6e34..8e2a9e4 100644 --- a/src/service/API/Extensions/ServicesExtensions.cs +++ b/src/service/API/Extensions/ServicesExtensions.cs @@ -29,23 +29,57 @@ internal static class ServicesExtensions /// public static void AddAuthentication(this IServiceCollection services, IConfiguration configuration) { + var primaryAudience = configuration["Authentication:Audience"]; + var clientId = configuration["ClientInfo:ClientId"]; + var tenantId = configuration["TenantInfo:Tenant"]; + var instance = configuration["InstanceInfo:Instance"]; + + // Accept the configured audience and its api:// URI form (v1.0 and v2.0 tokens), plus any + // extra audiences from Authentication:AdditionalAudiences (comma-separated), each in raw and api:// forms. + var additionalAudiences = !string.IsNullOrWhiteSpace(configuration["Authentication:AdditionalAudiences"]) + ? configuration["Authentication:AdditionalAudiences"].Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + : Array.Empty(); + var validAudiences = new[] { primaryAudience, clientId, $"api://{primaryAudience}", $"api://{clientId}" } + .Concat(additionalAudiences) + .Concat(additionalAudiences.Select(a => $"api://{a}")) + .Where(a => !string.IsNullOrWhiteSpace(a)) + .Distinct() + .ToArray(); + + // Inbound token validation via MISE 2.x with the default module set. services.AddAuthentication(MiseAuthenticationDefaults.AuthenticationScheme) .AddMiseWithDefaultModules(configuration, miseOptions => { - var primaryAudience = configuration["Authentication:Audience"]; - IList validAudiences = !string.IsNullOrWhiteSpace(configuration["Authentication:AdditionalAudiences"]) - ? configuration["Authentication:AdditionalAudiences"].Split(',').ToList() - : new List(); - validAudiences.Add(primaryAudience); - miseOptions.AzureAd ??= new MiseAuthenticationOptions(); - miseOptions.AzureAd.Authority = configuration["Authentication:Authority"]; + miseOptions.AzureAd.Instance = instance; + miseOptions.AzureAd.TenantId = tenantId; + miseOptions.AzureAd.ClientId = clientId; + miseOptions.AzureAd.Audience = primaryAudience; miseOptions.AzureAd.Audiences = validAudiences; - miseOptions.AzureAd.ClientId = configuration["ClientInfo:ClientId"]; - miseOptions.AzureAd.Instance = configuration["InstanceInfo:Instance"]; - miseOptions.AzureAd.TenantId = configuration["TenantInfo:Tenant"]; - }, MiseAuthenticationDefaults.AuthenticationScheme); + // Explicit inbound policy accepting both app and user Bearer tokens. + // Required for MISE 2.x to validate inbound tokens (the default policy alone rejects them). + var inboundPolicy = new MiseInboundPolicyOptions + { + Label = "FeatureFlightingInbound", + Instance = instance, + TenantId = tenantId, + Audiences = validAudiences, + }; + + var bearerTokenTypeOptions = new TokenTypeOptions + { + AppToken = true, + UserToken = true, + AllowMissingIdTypeClaim = true, + }; + var bearerProtocol = new ProtocolOptions(); + bearerProtocol.TokenTypes["AccessToken"] = bearerTokenTypeOptions; + bearerProtocol.TokenTypes["AppToken"] = bearerTokenTypeOptions; + inboundPolicy.Protocols[Microsoft.Identity.ServiceEssentials.Authentication.Protocol.BearerConstants.ProtocolName] = bearerProtocol; + + miseOptions.AzureAd.InboundPolicies = new List { inboundPolicy }; + }, MiseAuthenticationDefaults.AuthenticationScheme); } /// diff --git a/src/service/API/Startup.cs b/src/service/API/Startup.cs index 1256445..3a9e2b5 100644 --- a/src/service/API/Startup.cs +++ b/src/service/API/Startup.cs @@ -16,8 +16,7 @@ using Microsoft.FeatureFlighting.API.Controllers; using AppInsights.EnterpriseTelemetry.Web.Extension; using AppInsights.EnterpriseTelemetry.Web.Extension.Filters; -using Microsoft.Identity.ServiceEssentials; - + namespace Microsoft.PS.Services.FlightingService.Api { /// @@ -83,7 +82,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); - app.UseMise(); app.UseEndpoints(endpoints => endpoints.MapControllers()); } From 995868bbcde92fffc446a72564cb177d784d6f63 Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 18:06:27 +0530 Subject: [PATCH 06/13] Remove Swashbuckle and all Swagger/OpenAPI references from API Dropped the Swashbuckle.AspNetCore package reference, the AddSwagger service registration and its UseSwagger/UseSwaggerUI middleware, and the associated Microsoft.OpenApi usings. Build clean, all 219 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- .../API/Extensions/ServicesExtensions.cs | 57 ------------------- .../API/Microsoft.FeatureFlighting.API.csproj | 1 - src/service/API/Startup.cs | 7 --- 3 files changed, 65 deletions(-) diff --git a/src/service/API/Extensions/ServicesExtensions.cs b/src/service/API/Extensions/ServicesExtensions.cs index 8e2a9e4..f141abb 100644 --- a/src/service/API/Extensions/ServicesExtensions.cs +++ b/src/service/API/Extensions/ServicesExtensions.cs @@ -2,7 +2,6 @@ using System.IO; using System.Linq; using System.Reflection; -using Microsoft.OpenApi.Models; using Microsoft.AspNetCore.Http; using System.Collections.Generic; using Microsoft.FeatureManagement; @@ -82,62 +81,6 @@ public static void AddAuthentication(this IServiceCollection services, IConfigur }, MiseAuthenticationDefaults.AuthenticationScheme); } - /// - /// Adds Swagger documenation - /// - /// - /// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle - /// - public static void AddSwagger(this IServiceCollection services) - { - services.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new OpenApiInfo - { - Title = "Flighting Service", - Version = "v2", - Contact = new OpenApiContact - { - Email = "fxpswe@microsoft.com", - Name = "Field Experience Engineering Team", - Url = new System.Uri("https://aka.ms/fxpdocs") - }, - Description = "APIs for managing and evaluating feature flags. Powered by Azure Configuration (Feature Management)" - }); - c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme - { - In = ParameterLocation.Header, - Description = "Please insert JWT with Bearer into field", - Name = "Authorization", - Type = SecuritySchemeType.ApiKey - }); - c.AddSecurityRequirement(new OpenApiSecurityRequirement { - { - new OpenApiSecurityScheme() - { - Reference = new OpenApiReference() - { - Type = ReferenceType.SecurityScheme, - Id = "Bearer" - } - }, - System.Array.Empty() - } - }); - try - { - string documentationFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; - string documentationPath = Path.Combine(AppContext.BaseDirectory, documentationFile); - c.IncludeXmlComments(documentationPath); - } - catch - { - // Do nothing if documentation fails - } - }); - services.AddEndpointsApiExplorer(); - } - /// /// Adds telemetry to API /// diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index 1bb459e..e1ee866 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -36,7 +36,6 @@ - diff --git a/src/service/API/Startup.cs b/src/service/API/Startup.cs index 3a9e2b5..0fc9afe 100644 --- a/src/service/API/Startup.cs +++ b/src/service/API/Startup.cs @@ -44,7 +44,6 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(Configuration); - services.AddSwagger(); services.AddTelememtry(Configuration); AddMvc(services); services.AddHttpClients(Configuration); @@ -60,12 +59,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { - app.UseSwagger(); - app.UseSwaggerUI(c => - { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "Flighting Service V2"); - c.RoutePrefix = string.Empty; - }); app.UseDeveloperExceptionPage(); } else From af7c6c0ecf8247b2ef87dde8102ff7070a1c2531 Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 18:39:36 +0530 Subject: [PATCH 07/13] Upgrade NuGet.Packaging/Protocol 6.12.1 -> 7.6.0 Build clean, all 219 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- src/service/API/Microsoft.FeatureFlighting.API.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index e1ee866..7c86923 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -34,8 +34,8 @@ - - + + From 0fe77f9889dd971e0020992195c6be509656e962 Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 18:43:48 +0530 Subject: [PATCH 08/13] Upgrade RulesEngine 5.0.3 -> 6.0.1 Build clean, all 219 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- src/service/Domain/Microsoft.FeatureFlighting.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj index dd1a76d..2eb49b9 100644 --- a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj +++ b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj @@ -18,7 +18,7 @@ - + From e2097dcfac28d7762f206e87dd9e865765ab8f8e Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 18:46:24 +0530 Subject: [PATCH 09/13] Upgrade Autofac 6.3.0 -> 9.3.1 and Autofac.Extensions.DependencyInjection 7.2.0 -> 11.0.2 Build clean, all 219 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- src/service/API/Microsoft.FeatureFlighting.API.csproj | 2 +- src/service/Common/Microsoft.FeatureFlighting.Common.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index 7c86923..830dc13 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/service/Common/Microsoft.FeatureFlighting.Common.csproj b/src/service/Common/Microsoft.FeatureFlighting.Common.csproj index 208fc46..004ee61 100644 --- a/src/service/Common/Microsoft.FeatureFlighting.Common.csproj +++ b/src/service/Common/Microsoft.FeatureFlighting.Common.csproj @@ -7,7 +7,7 @@ - + From baaab8210255d40974489ce4a52b0fea7636e1ab Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 18:48:49 +0530 Subject: [PATCH 10/13] Upgrade Azure AppConfiguration packages 4.5.1 -> 8.5.0 Microsoft.Azure.AppConfiguration.AspNetCore and Microsoft.Extensions.Configuration.AzureAppConfiguration both to 8.5.0. Build clean, all 219 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- src/service/API/Microsoft.FeatureFlighting.API.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index 830dc13..c532b6b 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -23,8 +23,8 @@ - - + + From 1258cb70d38a50a81a3c5c9c996e6b8643c34e4c Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 18:51:04 +0530 Subject: [PATCH 11/13] Upgrade Microsoft.FeatureManagement(.AspNetCore) 2.x -> 4.6.0 Bumped Microsoft.FeatureManagement 2.6.1 -> 4.6.0 (Domain + API) and Microsoft.FeatureManagement.AspNetCore 2.4.0 -> 4.6.0 (API). Filter API (IFeatureFilter/FeatureFilterEvaluationContext/IFilterParametersBinder) remained source-compatible. Build clean, all 219 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- src/service/API/Microsoft.FeatureFlighting.API.csproj | 4 ++-- src/service/Domain/Microsoft.FeatureFlighting.Core.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index c532b6b..9f244d3 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -25,8 +25,8 @@ - - + + diff --git a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj index 2eb49b9..fe50306 100644 --- a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj +++ b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj @@ -15,7 +15,7 @@ - + From fe808e3c959c18bdb9ba41b0f40ec2125c76d590 Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 18:54:05 +0530 Subject: [PATCH 12/13] Upgrade Microsoft.Identity.Client 4.84.2 -> 4.86.1 Bumped across all 7 project/test references to the latest public stable on nuget.org. The 16.0.14415.15073 reported by 'dotnet list --outdated' is an internal-feed-only build not available on nuget.org, so it was intentionally not used to keep this public repo restorable from nuget.org. Build clean, all 219 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- src/service/API/Microsoft.FeatureFlighting.API.csproj | 2 +- src/service/Domain/Microsoft.FeatureFlighting.Core.csproj | 2 +- .../Microsoft.FeatureFlighting.Infrastructure.csproj | 2 +- src/service/Services/Microsoft.FeatureFlighting.Services.csproj | 2 +- .../Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj | 2 +- .../Microsoft.PS.FlightingService.Core.Tests.csproj | 2 +- .../Microsoft.FeatureFlighting.Infrastructure.Tests.csproj | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index 9f244d3..6c70716 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -27,7 +27,7 @@ - + diff --git a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj index fe50306..34010d2 100644 --- a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj +++ b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj index 78cc371..66ba1e8 100644 --- a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj +++ b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/service/Services/Microsoft.FeatureFlighting.Services.csproj b/src/service/Services/Microsoft.FeatureFlighting.Services.csproj index 094ab77..49030d4 100644 --- a/src/service/Services/Microsoft.FeatureFlighting.Services.csproj +++ b/src/service/Services/Microsoft.FeatureFlighting.Services.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj index a20823b..b3fdb94 100644 --- a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj +++ b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj index 2e1cc30..c1dca22 100644 --- a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj +++ b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj @@ -13,7 +13,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj index a715404..2eb02b2 100644 --- a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj +++ b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj @@ -21,7 +21,7 @@ - + From cfdd415bcc2c8395a6512649a279c6010413e788 Mon Sep 17 00:00:00 2001 From: Purva Patki Date: Thu, 23 Jul 2026 19:01:41 +0530 Subject: [PATCH 13/13] Upgrade Microsoft.Graph 3.0.1 -> 6.2.0 with SDK v6 migration Migrated GraphGroupVerificationService to the Graph SDK v6 (Kiota) API: - IGraphServiceClient -> GraphServiceClient - Replaced removed DelegateAuthenticationProvider with a custom IAuthenticationProvider (MsalConfidentialClientAuthenticationProvider) that sets the bearer token from the MSAL confidential client - Replaced removed .Request()/NextPageRequest fluent+paging with GetAsync() + PageIterator - Models now from Microsoft.Graph.Models (User, DirectoryObject) Build clean, all 219 tests pass. Graph request/paging/auth paths are not unit-tested (require live Graph); integration verification recommended. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c975713-01f9-4b4a-a6d9-3fc334559698 --- .../Graph/GraphGroupVerificationService.cs | 85 ++++++++++++------- ...oft.FeatureFlighting.Infrastructure.csproj | 2 +- ...Microsoft.FeatureFlighting.Services.csproj | 2 +- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/service/Infrastructure/Graph/GraphGroupVerificationService.cs b/src/service/Infrastructure/Graph/GraphGroupVerificationService.cs index 0ea44d5..30e23ad 100644 --- a/src/service/Infrastructure/Graph/GraphGroupVerificationService.cs +++ b/src/service/Infrastructure/Graph/GraphGroupVerificationService.cs @@ -2,6 +2,9 @@ using System.Linq; using System.Text; using Microsoft.Graph; +using Microsoft.Graph.Models; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Abstractions.Authentication; using System.Threading.Tasks; using System.Net.Http.Headers; using Microsoft.Identity.Client; @@ -25,7 +28,7 @@ namespace Microsoft.FeatureFlighting.Infrastructure.Graph /// /> internal class GraphGroupVerificationService : IGroupVerificationService, IBackgroundCacheable> { - private readonly IGraphServiceClient _graphServiceClient; + private readonly GraphServiceClient _graphServiceClient; private readonly ICacheFactory _cacheFactory; private readonly bool _isCachingEnabled; private readonly int _cacheInterval; @@ -126,7 +129,7 @@ private async Task> GetGroupMembers(string securityGroupId, Logger return groupMembers ?? new(); } - private IGraphServiceClient CreateGraphClient(IConfiguration configuration) + private GraphServiceClient CreateGraphClient(IConfiguration configuration) { try { @@ -161,15 +164,8 @@ private IGraphServiceClient CreateGraphClient(IConfiguration configuration) _cache.Add(confidentialAppCacheKey, client); #endif - IGraphServiceClient graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) => - { - AuthenticationResult authResult = await client - .AcquireTokenForClient(scopes) - .ExecuteAsync(); - - requestMessage.Headers.Authorization = - new AuthenticationHeaderValue("Bearer", authResult.AccessToken); - })); + GraphServiceClient graphServiceClient = new GraphServiceClient( + new MsalConfidentialClientAuthenticationProvider(client, scopes)); return graphServiceClient; } catch (Exception ex) @@ -234,23 +230,26 @@ public async Task>> CreateCacheableObject string cacheKey = cacheParameters.CacheKey; string groupId = cacheParameters.ObjectId; - var transitiveMembers = await _graphServiceClient.Groups[groupId] - .TransitiveMembers - .Request() - .GetAsync() - .ConfigureAwait(false); - - var groupMembers = transitiveMembers?.ToList() ?? new(); - while (transitiveMembers != null && transitiveMembers.NextPageRequest != null) - { - transitiveMembers = await transitiveMembers.NextPageRequest.GetAsync().ConfigureAwait(false); - if (transitiveMembers != null) - groupMembers.AddRange(transitiveMembers?.ToList() ?? new()); - } - - List userPrincipalNames = groupMembers - .Where(member => member is User)? - .Select(member => ((User)member).UserPrincipalName)? + var transitiveMembersResponse = await _graphServiceClient.Groups[groupId] + .TransitiveMembers + .GetAsync() + .ConfigureAwait(false); + + var groupMembers = new List(); + if (transitiveMembersResponse?.Value != null) + { + var pageIterator = PageIterator + .CreatePageIterator(_graphServiceClient, transitiveMembersResponse, (member) => + { + groupMembers.Add(member); + return true; + }); + await pageIterator.IterateAsync().ConfigureAwait(false); + } + + List userPrincipalNames = groupMembers + .Where(member => member is User)? + .Select(member => ((User)member).UserPrincipalName)? .ToList() ?? new(); BackgroundCacheableObject> cacheableGroupMembers = new() @@ -261,11 +260,33 @@ public async Task>> CreateCacheableObject return cacheableGroupMembers; } - public async Task RebuildCache(BackgroundCacheParameters cacheParameters, LoggerTrackingIds trackingIds) - { + public async Task RebuildCache(BackgroundCacheParameters cacheParameters, LoggerTrackingIds trackingIds) + { var cacheableObject = await CreateCacheableObject(cacheParameters, trackingIds).ConfigureAwait(false); if (cacheableObject.Object != null && cacheableObject.Object.Any()) - await SetCacheObject(cacheableObject, trackingIds).ConfigureAwait(false); - } + await SetCacheObject(cacheableObject, trackingIds).ConfigureAwait(false); + } + + private sealed class MsalConfidentialClientAuthenticationProvider : IAuthenticationProvider + { + private readonly IConfidentialClientApplication _client; + private readonly string[] _scopes; + + public MsalConfidentialClientAuthenticationProvider(IConfidentialClientApplication client, string[] scopes) + { + _client = client; + _scopes = scopes; + } + + public async Task AuthenticateRequestAsync(RequestInformation request, Dictionary additionalAuthenticationContext = null, CancellationToken cancellationToken = default) + { + AuthenticationResult authResult = await _client + .AcquireTokenForClient(_scopes) + .ExecuteAsync(cancellationToken) + .ConfigureAwait(false); + + request.Headers.Add("Authorization", $"Bearer {authResult.AccessToken}"); + } + } } } diff --git a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj index 66ba1e8..8588646 100644 --- a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj +++ b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/service/Services/Microsoft.FeatureFlighting.Services.csproj b/src/service/Services/Microsoft.FeatureFlighting.Services.csproj index 49030d4..7145b36 100644 --- a/src/service/Services/Microsoft.FeatureFlighting.Services.csproj +++ b/src/service/Services/Microsoft.FeatureFlighting.Services.csproj @@ -9,7 +9,7 @@ - +