From 34a1895eee0a9cf1830f384a07be25aff32fb5d9 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> Date: Fri, 19 Jul 2024 00:50:59 +0800 Subject: [PATCH 01/15] version bump 3.5.0 (#475) --- .../Microsoft.FeatureManagement.AspNetCore.csproj | 2 +- .../Microsoft.FeatureManagement.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj index 7e6b3226..c14d391f 100644 --- a/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj +++ b/src/Microsoft.FeatureManagement.AspNetCore/Microsoft.FeatureManagement.AspNetCore.csproj @@ -4,7 +4,7 @@ 3 - 4 + 5 0 diff --git a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj index 95e64f26..62e3ed9d 100644 --- a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj +++ b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj @@ -4,7 +4,7 @@ 3 - 4 + 5 0 From d069049c70f84b429f5232765cad08dfb4ca00f8 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:56:34 +0800 Subject: [PATCH 02/15] fix typo in comment (#480) --- .../Telemetry/VariantAssignmentReason.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.FeatureManagement/Telemetry/VariantAssignmentReason.cs b/src/Microsoft.FeatureManagement/Telemetry/VariantAssignmentReason.cs index a4db27d4..0e2ce56a 100644 --- a/src/Microsoft.FeatureManagement/Telemetry/VariantAssignmentReason.cs +++ b/src/Microsoft.FeatureManagement/Telemetry/VariantAssignmentReason.cs @@ -9,7 +9,7 @@ namespace Microsoft.FeatureManagement.Telemetry public enum VariantAssignmentReason { /// - /// Variant allocation did not happend. No variant is assigned. + /// Variant allocation did not happen. No variant is assigned. /// None, From de9eeed4f0149eff1613fdf284b934ddab09657f Mon Sep 17 00:00:00 2001 From: Amer Jusupovic <32405726+amerjusupovic@users.noreply.github.com> Date: Thu, 25 Jul 2024 13:29:53 -0700 Subject: [PATCH 03/15] Use GitHub workflow for PR builds (#481) * add github workflow ci.yml, remove old pipelines * test workflow failure * revert test --- .github/workflows/ci.yml | 53 +++++++++ .pipelines/OneBranch.Official.yml | 175 ------------------------------ .pipelines/windows-buddy.yml | 125 --------------------- 3 files changed, 53 insertions(+), 300 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .pipelines/OneBranch.Official.yml delete mode 100644 .pipelines/windows-buddy.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..3701da6c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: FeatureManagement-Dotnet CI + +on: + push: + branches: + - main + - preview + - release/* + pull_request: + branches: + - main + - preview + - release/* + +permissions: + security-events: write + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install .NET + run: pwsh build/install-dotnet.ps1 -RestoreOnly + + - name: Restore + run: pwsh build.ps1 -RestoreOnly + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: 'csharp' + + - name: Dotnet Build + run: pwsh build.ps1 + + - name: Dotnet Pack + run: pwsh pack.ps1 + + - name: Dotnet Test + run: pwsh test.ps1 + + - name: Publish Test Results + uses: actions/upload-artifact@v4 + with: + name: Unit Test Results + path: ${{ github.workspace }}/tests/**/*.trx + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.pipelines/OneBranch.Official.yml b/.pipelines/OneBranch.Official.yml deleted file mode 100644 index 15c44d0e..00000000 --- a/.pipelines/OneBranch.Official.yml +++ /dev/null @@ -1,175 +0,0 @@ -trigger: none - -parameters: # parameters are shown up in ADO UI in a build queue time -- name: 'debug' - displayName: 'Enable debug output' - type: boolean - default: false - -variables: - CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] # needed for onebranch.pipeline.version task - system.debug: ${{ parameters.debug }} - ENABLE_PRS_DELAYSIGN: 1 - ROOT: $(Build.SourcesDirectory) - REPOROOT: $(Build.SourcesDirectory) - OUTPUTROOT: $(REPOROOT)\out - CDP_USER_SOURCE_FOLDER_CONTAINER_PATH: $(Build.SourcesDirectory) - CDP_DEFINITION_BUILD_COUNT_DAY: $[counter(format('{0:yyyyMMdd}', pipeline.startTime), 1)] - CDP_DEFINITION_BUILD_COUNT_MONTH: $[counter(format('{0:yyyyMM}', pipeline.startTime), 1)] - CDP_DEFINITION_BUILD_COUNT_YEAR: $[counter(format('{0:yyyy}', pipeline.startTime), 1)] - NUGET_XMLDOC_MODE: none - - # Docker image which is used to build the project - WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' - -resources: - repositories: - - repository: templates - type: git - name: OneBranch.Pipelines/GovernedTemplates - ref: refs/heads/main - -extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates - parameters: - cloudvault: - enabled: false - globalSdl: - tsa: - enabled: false # onebranch publish all sdl results to TSA. If TSA is disabled all SDL tools will forced into 'break' build mode. - # credscan: - # suppressionsFile: $(Build.SourcesDirectory)\.config\CredScanSuppressions.json - binskim: - break: true # always break the build on binskim issues in addition to TSA upload - policheck: - break: true # always break the build on policheck issues. You can disable it by setting to 'false' - # baseline: - # baselineFile: $(Build.SourcesDirectory)\.gdn\global.gdnbaselines - cg: - failOnAlert: false - - stages: - - stage: build - jobs: - - job: main - pool: - type: windows - - variables: - ob_outputDirectory: '$(REPOROOT)\out' # this directory is uploaded to pipeline artifacts, reddog and cloudvault - ob_sdl_binskim_break: true - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}: # conditionally enable symbolsPublishing for master branch only - ob_symbolsPublishing_enabled: true - # ob_sdl_baseline_baselineFile: $(Build.SourcesDirectory)\.gdn\build.official.gdnbaselines - # ob_sdl_codeSignValidation_excludes: -|**\*.js # Example -|**\*.js;-|**\Test*\** - ob_artifactBaseName: 'drop' - ob_sdl_cg_failOnAlert: false - - steps: - - task: CmdLine@2 - displayName: 'Install .NET' - inputs: - script: $(Build.SourcesDirectory)\build\CallPowerShell.cmd build/install-dotnet.ps1 -RestoreOnly - workingDirectory: '$(Build.SourcesDirectory)' - - - task: CmdLine@2 - displayName: 'Restore' - inputs: - script: $(Build.SourcesDirectory)\build\CallPowerShell.cmd build.ps1 -RestoreOnly - workingDirectory: '$(Build.SourcesDirectory)' - - - task: onebranch.pipeline.version@1 # generates automatic version - displayName: 'Setup BuildNumber' - inputs: - system: 'BuildRevision' - major: '1' - minor: '0' - name: 'FeatureManagement-Dotnet' - # exclude_commit: true - - - - - task: CmdLine@2 - displayName: 'Dotnet Build' - inputs: - script: $(Build.SourcesDirectory)\build\CallPowerShell.cmd build.ps1 - workingDirectory: '$(Build.SourcesDirectory)' - - - task: CopyFiles@2 - inputs: - SourceFolder: '$(Build.SourcesDirectory)\buildlogs' - Contents: | - **/* - TargetFolder: '$(Build.SourcesDirectory)\out\outputs\build\Build Logs' - - - - - task: onebranch.pipeline.signing@1 - displayName: 'Signing' - inputs: - command: 'sign' - signing_environment: 'azure-ado' - signing_profile: 'external_distribution ' - files_to_sign: '*/bin/Release/**/*' - search_root: '$(Build.SourcesDirectory)\src' - - - - task: CopyFiles@2 - inputs: - SourceFolder: '$(Build.SourcesDirectory)\src' - Contents: | - */bin/Release/**/* - TargetFolder: '$(Build.SourcesDirectory)\out\outputs\build\Binaries' - - - task: CmdLine@2 - displayName: 'Dotnet Pack' - inputs: - script: $(Build.SourcesDirectory)\build\CallPowerShell.cmd pack.ps1 - workingDirectory: '$(Build.SourcesDirectory)' - - - task: CopyFiles@2 - inputs: - SourceFolder: '$(Build.SourcesDirectory)\buildlogs' - Contents: | - **/* - TargetFolder: '$(Build.SourcesDirectory)\out\outputs\package\Build Logs' - - - - - task: onebranch.pipeline.signing@1 - displayName: 'Signing' - inputs: - command: 'sign' - signing_environment: 'azure-ado' - signing_profile: 'external_distribution ' - files_to_sign: '*/bin/PackageOutput/**/*.nupkg' - search_root: '$(Build.SourcesDirectory)\src' - - - - task: CopyFiles@2 - inputs: - SourceFolder: '$(Build.SourcesDirectory)\src' - Contents: | - */bin/PackageOutput/**/*.nupkg - TargetFolder: '$(Build.SourcesDirectory)\out\outputs\package\Packages' - - - task: CmdLine@2 - displayName: 'Dotnet Test' - inputs: - script: '$(Build.SourcesDirectory)\build/CallPowerShell.cmd test.ps1|| exit /b 0' - workingDirectory: '$(Build.SourcesDirectory)' - - - task: CopyFiles@2 - inputs: - SourceFolder: '$(Build.SourcesDirectory)\tests' - Contents: '**/*.trx' - TargetFolder: '$(Build.SourcesDirectory)\out\outputs\test\_post_command__run_log_alerts_schedular_tests\_testresults' - - - task: PublishTestResults@2 - displayName: 'Unit Tests' - inputs: - testResultsFormat: 'vstest' - testResultsFiles: '**/*.trx' - searchFolder: '' - failTaskOnFailedTests: False - testRunTitle: Unit Tests \ No newline at end of file diff --git a/.pipelines/windows-buddy.yml b/.pipelines/windows-buddy.yml deleted file mode 100644 index 48e9a699..00000000 --- a/.pipelines/windows-buddy.yml +++ /dev/null @@ -1,125 +0,0 @@ - -pr: -- main -- release/* - -trigger: -- none - -parameters: # parameters are shown up in ADO UI in a build queue time -- name: 'debug' - displayName: 'Enable debug output' - type: boolean - default: false - -jobs: -- job: main - pool: - type: windows - isCustom: true - name: Azure Pipelines - vmImage: 'windows-latest' - - variables: - Codeql.Enabled: true - - steps: - - task: AntiMalware@4 - inputs: - InputType: 'Basic' - ScanType: 'CustomScan' - FileDirPath: '$(Build.StagingDirectory)' - TreatSignatureUpdateFailureAs: 'Warning' - SignatureFreshness: 'UpToDate' - TreatStaleSignatureAs: 'Error' - - - task: CredScan@3 - - - task: nuget-security-analysis@0 - - - task: CmdLine@2 - displayName: 'Install .NET' - inputs: - script: build\CallPowerShell.cmd build/install-dotnet.ps1 -RestoreOnly - workingDirectory: '$(Build.SourcesDirectory)' - - - task: CmdLine@2 - displayName: 'Restore' - inputs: - script: $(Build.SourcesDirectory)\build\CallPowerShell.cmd build.ps1 -RestoreOnly - workingDirectory: '$(Build.SourcesDirectory)' - - - task: CodeQL3000Init@0 - displayName: 'Initialize CodeQL' - - - task: CmdLine@2 - displayName: 'Dotnet Build' - inputs: - script: $(Build.SourcesDirectory)\build\CallPowerShell.cmd build.ps1 - workingDirectory: '$(Build.SourcesDirectory)' - - - task: CopyFiles@2 - inputs: - SourceFolder: '$(Build.SourcesDirectory)\buildlogs' - Contents: | - **/* - TargetFolder: '$(Build.SourcesDirectory)\out\outputs\build\Build Logs' - - - task: CmdLine@2 - displayName: 'Dotnet Pack' - inputs: - script: $(Build.SourcesDirectory)\build\CallPowerShell.cmd pack.ps1 - workingDirectory: '$(Build.SourcesDirectory)' - - - task: CopyFiles@2 - inputs: - SourceFolder: '$(Build.SourcesDirectory)\buildlogs' - Contents: | - **/* - TargetFolder: '$(Build.SourcesDirectory)\out\outputs\package\Build Logs' - - - task: CmdLine@2 - displayName: 'Dotnet Test' - inputs: - script: '$(Build.SourcesDirectory)\build/CallPowerShell.cmd test.ps1|| exit /b 0' - workingDirectory: '$(Build.SourcesDirectory)' - - - - task: CopyFiles@2 - inputs: - SourceFolder: '$(Build.SourcesDirectory)\tests' - Contents: '**/*.trx' - TargetFolder: '$(Build.SourcesDirectory)\out\outputs\test\_post_command__run_log_alerts_schedular_tests\_testresults' - - - task: PublishTestResults@2 - displayName: 'Unit Tests' - inputs: - testResultsFormat: 'vstest' - testResultsFiles: '**/*.trx' - searchFolder: '' - failTaskOnFailedTests: True - testRunTitle: Unit Tests - - - task: ComponentGovernanceComponentDetection@0 - displayName: "Component Detection" - inputs: - scanType: 'Register' - verbosity: 'Verbose' - alertWarningLevel: 'High' - - - task: BinSkim@4 - inputs: - InputType: 'Basic' - Function: 'analyze' - TargetPattern: 'guardianGlob' - AnalyzeTargetGlob: '$(Build.SourcesDirectory)\**.dll;$(Build.SourcesDirectory)\**.exe;' - - - task: PublishPipelineArtifact@1 - displayName: 'Publish Artifacts' - inputs: - targetPath: '$(Build.SourcesDirectory)\out\outputs' - artifact: 'drop' - publishLocation: 'pipeline' - - - task: CodeQL3000Finalize@0 - displayName: 'Finalize CodeQL' From 3b838a4dae264f857bb9ebbe1220b179603ceb8d Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> Date: Fri, 16 Aug 2024 01:21:27 +0800 Subject: [PATCH 04/15] use TimeProvider (#452) --- .../FeatureFilters/ISystemClock.cs | 20 ------------------- .../FeatureFilters/TimeWindowFilter.cs | 6 +++--- .../Microsoft.FeatureManagement.csproj | 3 ++- .../Tests.FeatureManagement/OnDemandClock.cs | 10 +++++++--- 4 files changed, 12 insertions(+), 27 deletions(-) delete mode 100644 src/Microsoft.FeatureManagement/FeatureFilters/ISystemClock.cs diff --git a/src/Microsoft.FeatureManagement/FeatureFilters/ISystemClock.cs b/src/Microsoft.FeatureManagement/FeatureFilters/ISystemClock.cs deleted file mode 100644 index 1fc9b667..00000000 --- a/src/Microsoft.FeatureManagement/FeatureFilters/ISystemClock.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// - -using System; - -namespace Microsoft.FeatureManagement.FeatureFilters -{ - /// - /// Abstracts the system clock to facilitate testing. - /// .NET8 offers an abstract class TimeProvider. After we stop supporting .NET version less than .NET8, this ISystemClock should retire. - /// - internal interface ISystemClock - { - /// - /// Retrieves the current system time in UTC. - /// - public DateTimeOffset UtcNow { get; } - } -} diff --git a/src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs b/src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs index fb1f6f01..62b5f4a5 100644 --- a/src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs +++ b/src/Microsoft.FeatureManagement/FeatureFilters/TimeWindowFilter.cs @@ -39,7 +39,7 @@ public TimeWindowFilter(ILoggerFactory loggerFactory = null) /// /// This property allows the time window filter in our test suite to use simulated time. /// - internal ISystemClock SystemClock { get; set; } + internal TimeProvider SystemClock { get; set; } /// /// Binds configuration representing filter parameters to . @@ -74,7 +74,7 @@ public Task EvaluateAsync(FeatureFilterEvaluationContext context) // Check if prebound settings available, otherwise bind from parameters. TimeWindowFilterSettings settings = (TimeWindowFilterSettings)context.Settings ?? (TimeWindowFilterSettings)BindParameters(context.Parameters); - DateTimeOffset now = SystemClock?.UtcNow ?? DateTimeOffset.UtcNow; + DateTimeOffset now = SystemClock?.GetUtcNow() ?? DateTimeOffset.UtcNow; if (!settings.Start.HasValue && !settings.End.HasValue) { @@ -129,7 +129,7 @@ public Task EvaluateAsync(FeatureFilterEvaluationContext context) private DateTimeOffset? ReloadClosestStart(TimeWindowFilterSettings settings) { - DateTimeOffset now = SystemClock?.UtcNow ?? DateTimeOffset.UtcNow; + DateTimeOffset now = SystemClock?.GetUtcNow() ?? DateTimeOffset.UtcNow; DateTimeOffset? closestStart = RecurrenceEvaluator.CalculateClosestStart(now, settings); diff --git a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj index 62e3ed9d..3abf1568 100644 --- a/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj +++ b/src/Microsoft.FeatureManagement/Microsoft.FeatureManagement.csproj @@ -35,10 +35,11 @@ - + + diff --git a/tests/Tests.FeatureManagement/OnDemandClock.cs b/tests/Tests.FeatureManagement/OnDemandClock.cs index c639a3e3..59c8c0d8 100644 --- a/tests/Tests.FeatureManagement/OnDemandClock.cs +++ b/tests/Tests.FeatureManagement/OnDemandClock.cs @@ -1,10 +1,14 @@ -using Microsoft.FeatureManagement.FeatureFilters; -using System; +using System; namespace Tests.FeatureManagement { - class OnDemandClock : ISystemClock + class OnDemandClock : TimeProvider { public DateTimeOffset UtcNow { get; set; } + + public override DateTimeOffset GetUtcNow() + { + return UtcNow; + } } } From 882c7b74357304bf799abede2c98577724343985 Mon Sep 17 00:00:00 2001 From: Ross Grambo Date: Fri, 23 Aug 2024 10:27:41 -0700 Subject: [PATCH 05/15] Adjusts builder extension methods to be friendlier (#487) * Adds and adjusts builder extension methods * Removed UseFeatureManagement and adjusted name of AddAppInsightsTelemetryPublisher * Adjusts examples --- examples/EvaluationDataToApplicationInsights/Program.cs | 2 +- examples/VariantServiceDemo/Program.cs | 2 +- .../AspNetCoreFeatureManagementBuilderExtensions.cs | 8 ++++++++ .../FeatureManagementBuilderExtensions.cs | 8 ++++++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/EvaluationDataToApplicationInsights/Program.cs b/examples/EvaluationDataToApplicationInsights/Program.cs index bf83d5d6..dbc856fc 100644 --- a/examples/EvaluationDataToApplicationInsights/Program.cs +++ b/examples/EvaluationDataToApplicationInsights/Program.cs @@ -30,7 +30,7 @@ // Wire up evaluation event emission builder.Services.AddFeatureManagement() .WithTargeting() - .AddApplicationInsightsTelemetryPublisher(); + .AddApplicationInsightsTelemetry(); // // Default code from .NET template below diff --git a/examples/VariantServiceDemo/Program.cs b/examples/VariantServiceDemo/Program.cs index 843cd1ce..8ac9a031 100644 --- a/examples/VariantServiceDemo/Program.cs +++ b/examples/VariantServiceDemo/Program.cs @@ -37,7 +37,7 @@ builder.Services.AddFeatureManagement() .WithTargeting() .WithVariantService("Calculator") - .AddApplicationInsightsTelemetryPublisher(); + .AddApplicationInsightsTelemetry(); var app = builder.Build(); diff --git a/src/Microsoft.FeatureManagement.AspNetCore/AspNetCoreFeatureManagementBuilderExtensions.cs b/src/Microsoft.FeatureManagement.AspNetCore/AspNetCoreFeatureManagementBuilderExtensions.cs index 9091a4b0..43aa6b46 100644 --- a/src/Microsoft.FeatureManagement.AspNetCore/AspNetCoreFeatureManagementBuilderExtensions.cs +++ b/src/Microsoft.FeatureManagement.AspNetCore/AspNetCoreFeatureManagementBuilderExtensions.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -55,6 +57,12 @@ public static IFeatureManagementBuilder UseDisabledFeaturesHandler(this IFeature /// A that can be used to customize feature management functionality. public static IFeatureManagementBuilder WithTargeting(this IFeatureManagementBuilder builder) { + // Add HttpContextAccessor if it doesn't already exist + if (!builder.Services.Any(service => service.ServiceType == typeof(IHttpContextAccessor))) + { + builder.Services.AddHttpContextAccessor(); + } + // // 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)) diff --git a/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights/FeatureManagementBuilderExtensions.cs b/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights/FeatureManagementBuilderExtensions.cs index 002d2bfc..503f4776 100644 --- a/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights/FeatureManagementBuilderExtensions.cs +++ b/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights/FeatureManagementBuilderExtensions.cs @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // +using Microsoft.ApplicationInsights.Extensibility; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.FeatureManagement.Telemetry.ApplicationInsights; @@ -13,11 +15,11 @@ namespace Microsoft.FeatureManagement public static class FeatureManagementBuilderExtensions { /// - /// Adds the using to the feature management builder. + /// Adds the and the using to the feature management builder. /// /// The feature management builder. /// The feature management builder. - public static IFeatureManagementBuilder AddApplicationInsightsTelemetryPublisher(this IFeatureManagementBuilder builder) + public static IFeatureManagementBuilder AddApplicationInsightsTelemetry(this IFeatureManagementBuilder builder) { if (builder == null) { @@ -29,6 +31,8 @@ public static IFeatureManagementBuilder AddApplicationInsightsTelemetryPublisher throw new ArgumentException($"The provided builder's services must not be null.", nameof(builder)); } + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); if (!builder.Services.Any((ServiceDescriptor d) => d.ServiceType == typeof(IHostedService) && d.ImplementationType == typeof(ApplicationInsightsHostedService))) From 9284d276930395d6b8cb06c2fb7c3a96dc23df69 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:06:13 +0800 Subject: [PATCH 06/15] Use ITargetingContext when calling GetVariantAsync (#484) * add variant feature manager extensions * use TContext to avoid future breaking change * TargetingContext in EvaluationEvent * update comments & not use ambient context in contextual case * update comment * use ITargetingContext & check runtime context type * use TargetingCotnext for private method * use var instead of type * revert change on ContextualTestFilter * update comment * update comment --- .../FeatureManager.cs | 30 +++++++----- .../FeatureManagerSnapshot.cs | 2 +- .../IFeatureManager.cs | 2 +- .../IVariantFeatureManager.cs | 6 +-- .../VariantFeatureManagerExtensions.cs | 28 +++++++++++ tests/Tests.FeatureManagement/AppContext.cs | 9 +++- .../FeatureManagementTest.cs | 49 ++++++++++++++++++- tests/Tests.FeatureManagement/Features.cs | 1 + .../Tests.FeatureManagement/appsettings.json | 28 +++++++++++ 9 files changed, 135 insertions(+), 20 deletions(-) create mode 100644 src/Microsoft.FeatureManagement/VariantFeatureManagerExtensions.cs diff --git a/src/Microsoft.FeatureManagement/FeatureManager.cs b/src/Microsoft.FeatureManagement/FeatureManager.cs index 40a0f0a7..d9e8a99d 100644 --- a/src/Microsoft.FeatureManagement/FeatureManager.cs +++ b/src/Microsoft.FeatureManagement/FeatureManager.cs @@ -144,7 +144,7 @@ public async Task IsEnabledAsync(string feature) /// Checks whether a given feature is enabled. /// /// The name of the feature to check. - /// A context providing information that can be used to evaluate whether a feature should be on or off. + /// A context that provides information to evaluate whether a feature should be on or off. /// True if the feature is enabled, otherwise false. public async Task IsEnabledAsync(string feature, TContext appContext) { @@ -170,7 +170,7 @@ public async ValueTask IsEnabledAsync(string feature, CancellationToken ca /// Checks whether a given feature is enabled. /// /// The name of the feature to check. - /// A context providing information that can be used to evaluate whether a feature should be on or off. + /// A context that provides information to evaluate whether a feature should be on or off. /// The cancellation token to cancel the operation. /// True if the feature is enabled, otherwise false. public async ValueTask IsEnabledAsync(string feature, TContext appContext, CancellationToken cancellationToken = default) @@ -216,7 +216,7 @@ public async ValueTask GetVariantAsync(string feature, CancellationToke throw new ArgumentNullException(nameof(feature)); } - EvaluationEvent evaluationEvent = await EvaluateFeature(feature, context: null, useContext: false, cancellationToken); + EvaluationEvent evaluationEvent = await EvaluateFeature(feature, context: null, useContext: false, cancellationToken); return evaluationEvent.Variant; } @@ -225,10 +225,10 @@ public async ValueTask GetVariantAsync(string feature, CancellationToke /// Gets the assigned variant for a specific feature. /// /// The name of the feature to evaluate. - /// An instance of used to evaluate which variant the user will be assigned. + /// A context that provides information to evaluate which variant will be assigned to the user. /// The cancellation token to cancel the operation. /// A variant assigned to the user based on the feature's configured allocation. - public async ValueTask GetVariantAsync(string feature, TargetingContext context, CancellationToken cancellationToken = default) + public async ValueTask GetVariantAsync(string feature, ITargetingContext context, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(feature)) { @@ -262,15 +262,19 @@ private async ValueTask EvaluateFeature(string featur // // Determine Targeting Context - TargetingContext targetingContext; + TargetingContext targetingContext = null; - if (useContext) + if (!useContext) { - targetingContext = context as TargetingContext; + targetingContext = await ResolveTargetingContextAsync(cancellationToken).ConfigureAwait(false); } - else + else if (context is ITargetingContext targetingInfo) { - targetingContext = await ResolveTargetingContextAsync(cancellationToken).ConfigureAwait(false); + targetingContext = new TargetingContext + { + UserId = targetingInfo.UserId, + Groups = targetingInfo.Groups + }; } evaluationEvent.TargetingContext = targetingContext; @@ -314,7 +318,7 @@ private async ValueTask EvaluateFeature(string featur if (useContext) { - message = $"A {nameof(TargetingContext)} required for variant assignment was not provided."; + message = $"The context of type {context.GetType().Name} does not implement {nameof(ITargetingContext)} for variant assignment."; } else if (TargetingContextAccessor == null) { @@ -496,7 +500,7 @@ private async ValueTask IsEnabledAsync(FeatureDefinition feature if (useAppContext) { - filter = GetFeatureFilterMetadata(featureFilterConfiguration.Name, typeof(TContext)) ?? + filter = GetFeatureFilterMetadata(featureFilterConfiguration.Name, appContext.GetType()) ?? GetFeatureFilterMetadata(featureFilterConfiguration.Name); } else @@ -538,7 +542,7 @@ private async ValueTask IsEnabledAsync(FeatureDefinition feature // IContextualFeatureFilter if (useAppContext) { - ContextualFeatureFilterEvaluator contextualFilter = GetContextualFeatureFilter(featureFilterConfiguration.Name, typeof(TContext)); + ContextualFeatureFilterEvaluator contextualFilter = GetContextualFeatureFilter(featureFilterConfiguration.Name, appContext.GetType()); if (contextualFilter != null && await contextualFilter.EvaluateAsync(context, appContext).ConfigureAwait(false) == targetEvaluation) diff --git a/src/Microsoft.FeatureManagement/FeatureManagerSnapshot.cs b/src/Microsoft.FeatureManagement/FeatureManagerSnapshot.cs index 6018931d..384bb2b1 100644 --- a/src/Microsoft.FeatureManagement/FeatureManagerSnapshot.cs +++ b/src/Microsoft.FeatureManagement/FeatureManagerSnapshot.cs @@ -97,7 +97,7 @@ public async ValueTask GetVariantAsync(string feature, CancellationToke return variant; } - public async ValueTask GetVariantAsync(string feature, TargetingContext context, CancellationToken cancellationToken) + public async ValueTask GetVariantAsync(string feature, ITargetingContext context, CancellationToken cancellationToken) { string cacheKey = GetVariantCacheKey(feature); diff --git a/src/Microsoft.FeatureManagement/IFeatureManager.cs b/src/Microsoft.FeatureManagement/IFeatureManager.cs index 1b4ea0cf..5f1006f5 100644 --- a/src/Microsoft.FeatureManagement/IFeatureManager.cs +++ b/src/Microsoft.FeatureManagement/IFeatureManager.cs @@ -28,7 +28,7 @@ public interface IFeatureManager /// Checks whether a given feature is enabled. /// /// The name of the feature to check. - /// A context providing information that can be used to evaluate whether a feature should be on or off. + /// A context that provides information to evaluate whether a feature should be on or off. /// True if the feature is enabled, otherwise false. Task IsEnabledAsync(string feature, TContext context); } diff --git a/src/Microsoft.FeatureManagement/IVariantFeatureManager.cs b/src/Microsoft.FeatureManagement/IVariantFeatureManager.cs index 0b78a237..505b6652 100644 --- a/src/Microsoft.FeatureManagement/IVariantFeatureManager.cs +++ b/src/Microsoft.FeatureManagement/IVariantFeatureManager.cs @@ -32,7 +32,7 @@ public interface IVariantFeatureManager /// Checks whether a given feature is enabled. /// /// The name of the feature to check. - /// A context providing information that can be used to evaluate whether a feature should be on or off. + /// A context that provides information to evaluate whether a feature should be on or off. /// The cancellation token to cancel the operation. /// True if the feature is enabled, otherwise false. ValueTask IsEnabledAsync(string feature, TContext context, CancellationToken cancellationToken = default); @@ -49,9 +49,9 @@ public interface IVariantFeatureManager /// Gets the assigned variant for a specific feature. /// /// The name of the feature to evaluate. - /// An instance of used to evaluate which variant the user will be assigned. + /// A context that provides information to evaluate which variant will be assigned to the user. /// The cancellation token to cancel the operation. /// A variant assigned to the user based on the feature's configured allocation. - ValueTask GetVariantAsync(string feature, TargetingContext context, CancellationToken cancellationToken = default); + ValueTask GetVariantAsync(string feature, ITargetingContext context, CancellationToken cancellationToken = default); } } diff --git a/src/Microsoft.FeatureManagement/VariantFeatureManagerExtensions.cs b/src/Microsoft.FeatureManagement/VariantFeatureManagerExtensions.cs new file mode 100644 index 00000000..97385729 --- /dev/null +++ b/src/Microsoft.FeatureManagement/VariantFeatureManagerExtensions.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +using Microsoft.FeatureManagement.FeatureFilters; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.FeatureManagement +{ + /// + /// Extensions for . + /// + public static class VariantFeatureManagerExtensions + { + /// + /// Gets the assigned variant for a specific feature. + /// + /// The instance. + /// The name of the feature to evaluate. + /// An instance of used to evaluate which variant the user will be assigned. + /// The cancellation token to cancel the operation. + /// A variant assigned to the user based on the feature's configured allocation. + public static ValueTask GetVariantAsync(this IVariantFeatureManager variantFeatureManager, string feature, TargetingContext context, CancellationToken cancellationToken = default) + { + return variantFeatureManager.GetVariantAsync(feature, context, cancellationToken); + } + } +} diff --git a/tests/Tests.FeatureManagement/AppContext.cs b/tests/Tests.FeatureManagement/AppContext.cs index 5431ac52..a55538e5 100644 --- a/tests/Tests.FeatureManagement/AppContext.cs +++ b/tests/Tests.FeatureManagement/AppContext.cs @@ -1,10 +1,17 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // +using Microsoft.FeatureManagement.FeatureFilters; +using System.Collections.Generic; + namespace Tests.FeatureManagement { - class AppContext : IAccountContext + class AppContext : IAccountContext, ITargetingContext { public string AccountId { get; set; } + + public string UserId { get; set; } + + public IEnumerable Groups { get; set; } } } diff --git a/tests/Tests.FeatureManagement/FeatureManagementTest.cs b/tests/Tests.FeatureManagement/FeatureManagementTest.cs index e1a6efe1..48551376 100644 --- a/tests/Tests.FeatureManagement/FeatureManagementTest.cs +++ b/tests/Tests.FeatureManagement/FeatureManagementTest.cs @@ -503,7 +503,7 @@ public async Task UsesContext() IFeatureManager featureManager = provider.GetRequiredService(); - AppContext context = new AppContext(); + var context = new AppContext(); context.AccountId = "NotEnabledAccount"; @@ -1641,6 +1641,53 @@ public async Task VariantBasedInjection() } ); } + + [Fact] + public async Task VariantFeatureFlagWithContextualFeatureFilter() + { + IConfiguration configuration = new ConfigurationBuilder() + .AddJsonFile("appsettings.json") + .Build(); + + IServiceCollection services = new ServiceCollection(); + + services.AddSingleton(configuration) + .AddFeatureManagement() + .AddFeatureFilter(); + + ServiceProvider serviceProvider = services.BuildServiceProvider(); + + ContextualTestFilter contextualTestFeatureFilter = (ContextualTestFilter)serviceProvider.GetRequiredService>().First(f => f is ContextualTestFilter); + + contextualTestFeatureFilter.ContextualCallback = (ctx, accountContext) => + { + var allowedAccounts = new List(); + + ctx.Parameters.Bind("AllowedAccounts", allowedAccounts); + + return allowedAccounts.Contains(accountContext.AccountId); + }; + + IVariantFeatureManager featureManager = serviceProvider.GetRequiredService(); + + var context = new AppContext(); + + context.AccountId = "NotEnabledAccount"; + + Assert.False(await featureManager.IsEnabledAsync(Features.ContextualFeatureWithVariant, context)); + + Variant variant = await featureManager.GetVariantAsync(Features.ContextualFeatureWithVariant, context); + + Assert.Equal("Small", variant.Name); + + context.AccountId = "abc"; + + Assert.True(await featureManager.IsEnabledAsync(Features.ContextualFeatureWithVariant, context)); + + variant = await featureManager.GetVariantAsync(Features.ContextualFeatureWithVariant, context); + + Assert.Equal("Big", variant.Name); + } } public class FeatureManagementTelemetryTest diff --git a/tests/Tests.FeatureManagement/Features.cs b/tests/Tests.FeatureManagement/Features.cs index 51eef015..9562c9bb 100644 --- a/tests/Tests.FeatureManagement/Features.cs +++ b/tests/Tests.FeatureManagement/Features.cs @@ -30,5 +30,6 @@ static class Features public const string VariantImplementationFeature = "VariantImplementationFeature"; public const string OnTelemetryTestFeature = "OnTelemetryTestFeature"; public const string OffTelemetryTestFeature = "OffTelemetryTestFeature"; + public const string ContextualFeatureWithVariant = "ContextualFeatureWithVariant"; } } diff --git a/tests/Tests.FeatureManagement/appsettings.json b/tests/Tests.FeatureManagement/appsettings.json index cf72cce4..0556fdf0 100644 --- a/tests/Tests.FeatureManagement/appsettings.json +++ b/tests/Tests.FeatureManagement/appsettings.json @@ -530,6 +530,34 @@ "telemetry": { "enabled": true } + }, + { + "id": "ContextualFeatureWithVariant", + "enabled": true, + "conditions": { + "client_filters": [ + { + "name": "ContextualTest", + "parameters": { + "AllowedAccounts": [ + "abc" + ] + } + } + ] + }, + "variants": [ + { + "name": "Big" + }, + { + "name": "Small" + } + ], + "allocation": { + "default_when_enabled": "Big", + "default_when_disabled": "Small" + } } ] } From 400796d2aa02820463b61b95443ee3aa638647d9 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:58:11 +0800 Subject: [PATCH 07/15] remove configuration reference from variant feature flag (#488) --- .../ConfigurationFeatureDefinitionProvider.cs | 1 - .../FeatureManager.cs | 18 ----------- .../MicrosoftFeatureManagementFields.cs | 1 - .../ServiceCollectionExtensions.cs | 2 -- .../VariantDefinition.cs | 5 --- .../FeatureManagementTest.cs | 6 ---- tests/Tests.FeatureManagement/Features.cs | 1 - .../Tests.FeatureManagement/appsettings.json | 32 ++----------------- 8 files changed, 2 insertions(+), 64 deletions(-) diff --git a/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs b/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs index d487eee5..835c6d8e 100644 --- a/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs +++ b/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs @@ -474,7 +474,6 @@ private FeatureDefinition ParseMicrosoftSchemaFeatureDefinition(IConfigurationSe { Name = section[MicrosoftFeatureManagementFields.Name], ConfigurationValue = section.GetSection(MicrosoftFeatureManagementFields.VariantDefinitionConfigurationValue), - ConfigurationReference = section[MicrosoftFeatureManagementFields.VariantDefinitionConfigurationReference], StatusOverride = statusOverride }; diff --git a/src/Microsoft.FeatureManagement/FeatureManager.cs b/src/Microsoft.FeatureManagement/FeatureManager.cs index d9e8a99d..10baef9d 100644 --- a/src/Microsoft.FeatureManagement/FeatureManager.cs +++ b/src/Microsoft.FeatureManagement/FeatureManager.cs @@ -104,11 +104,6 @@ public IEnumerable SessionManagers /// public ILogger Logger { get; set; } - /// - /// The configuration reference for feature variants. - /// - public IConfiguration Configuration { get; set; } - /// /// The targeting context accessor for feature variant allocation. /// @@ -860,19 +855,6 @@ private Variant GetVariantFromVariantDefinition(VariantDefinition variantDefinit { variantConfiguration = variantDefinition.ConfigurationValue; } - else if (!string.IsNullOrEmpty(variantDefinition.ConfigurationReference)) - { - if (Configuration == null) - { - Logger?.LogWarning($"Cannot use {nameof(variantDefinition.ConfigurationReference)} as no instance of {nameof(IConfiguration)} is present."); - - return null; - } - else - { - variantConfiguration = Configuration.GetSection(variantDefinition.ConfigurationReference); - } - } return new Variant() { diff --git a/src/Microsoft.FeatureManagement/MicrosoftFeatureManagementFields.cs b/src/Microsoft.FeatureManagement/MicrosoftFeatureManagementFields.cs index f07bc694..bac65418 100644 --- a/src/Microsoft.FeatureManagement/MicrosoftFeatureManagementFields.cs +++ b/src/Microsoft.FeatureManagement/MicrosoftFeatureManagementFields.cs @@ -42,7 +42,6 @@ internal static class MicrosoftFeatureManagementFields // Variants keywords public const string VariantsSectionName = "variants"; public const string VariantDefinitionConfigurationValue = "configuration_value"; - public const string VariantDefinitionConfigurationReference = "configuration_reference"; public const string VariantDefinitionStatusOverride = "status_override"; // Telemetry keywords diff --git a/src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs b/src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs index 41149673..df7d3d00 100644 --- a/src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs +++ b/src/Microsoft.FeatureManagement/ServiceCollectionExtensions.cs @@ -50,7 +50,6 @@ public static IFeatureManagementBuilder AddFeatureManagement(this IServiceCollec SessionManagers = sp.GetRequiredService>(), Cache = sp.GetRequiredService(), Logger = sp.GetRequiredService().CreateLogger(), - Configuration = sp.GetService(), TargetingContextAccessor = sp.GetService(), AssignerOptions = sp.GetRequiredService>().Value }); @@ -137,7 +136,6 @@ public static IFeatureManagementBuilder AddScopedFeatureManagement(this IService SessionManagers = sp.GetRequiredService>(), Cache = sp.GetRequiredService(), Logger = sp.GetRequiredService().CreateLogger(), - Configuration = sp.GetService(), TargetingContextAccessor = sp.GetService(), AssignerOptions = sp.GetRequiredService>().Value }); diff --git a/src/Microsoft.FeatureManagement/VariantDefinition.cs b/src/Microsoft.FeatureManagement/VariantDefinition.cs index 77bd6d7d..138d2fc5 100644 --- a/src/Microsoft.FeatureManagement/VariantDefinition.cs +++ b/src/Microsoft.FeatureManagement/VariantDefinition.cs @@ -21,11 +21,6 @@ public class VariantDefinition /// public IConfigurationSection ConfigurationValue { get; set; } - /// - /// A reference pointing to the configuration for this variant of the feature. - /// - public string ConfigurationReference { get; set; } - /// /// Overrides the state of the feature if this variant has been assigned. /// diff --git a/tests/Tests.FeatureManagement/FeatureManagementTest.cs b/tests/Tests.FeatureManagement/FeatureManagementTest.cs index 48551376..d8adf251 100644 --- a/tests/Tests.FeatureManagement/FeatureManagementTest.cs +++ b/tests/Tests.FeatureManagement/FeatureManagementTest.cs @@ -1472,7 +1472,6 @@ public async Task UsesVariants() Variant variant = await featureManager.GetVariantAsync(Features.VariantFeaturePercentileOn, cancellationToken); Assert.Equal("Big", variant.Name); - Assert.Equal("green", variant.Configuration["Color"]); Assert.False(await featureManager.IsEnabledAsync(Features.VariantFeaturePercentileOn, cancellationToken)); variant = await featureManager.GetVariantAsync(Features.VariantFeaturePercentileOff, cancellationToken); @@ -1541,11 +1540,6 @@ public async Task VariantsInvalidScenarios() Assert.Null(variant); - // Verify that ConfigurationValue has priority over ConfigurationReference - variant = await featureManager.GetVariantAsync(Features.VariantFeatureBothConfigurations, cancellationToken); - - Assert.Equal("600px", variant.Configuration.Value); - // Verify that an exception is thrown for invalid StatusOverride value FeatureManagementException e = await Assert.ThrowsAsync(async () => { diff --git a/tests/Tests.FeatureManagement/Features.cs b/tests/Tests.FeatureManagement/Features.cs index 9562c9bb..22c22201 100644 --- a/tests/Tests.FeatureManagement/Features.cs +++ b/tests/Tests.FeatureManagement/Features.cs @@ -24,7 +24,6 @@ static class Features public const string VariantFeatureNoVariants = "VariantFeatureNoVariants"; public const string VariantFeatureNoAllocation = "VariantFeatureNoAllocation"; public const string VariantFeatureAlwaysOffNoAllocation = "VariantFeatureAlwaysOffNoAllocation"; - public const string VariantFeatureBothConfigurations = "VariantFeatureBothConfigurations"; public const string VariantFeatureInvalidStatusOverride = "VariantFeatureInvalidStatusOverride"; public const string VariantFeatureInvalidFromTo = "VariantFeatureInvalidFromTo"; public const string VariantImplementationFeature = "VariantImplementationFeature"; diff --git a/tests/Tests.FeatureManagement/appsettings.json b/tests/Tests.FeatureManagement/appsettings.json index 0556fdf0..a99a325d 100644 --- a/tests/Tests.FeatureManagement/appsettings.json +++ b/tests/Tests.FeatureManagement/appsettings.json @@ -6,17 +6,6 @@ }, "AllowedHosts": "*", - "ShoppingCart": { - "Big": { - "Size": 600, - "Color": "green" - }, - "Small": { - "Size": 300, - "Color": "gray" - } - }, - "feature_management": { "feature_flags": [ { @@ -209,7 +198,6 @@ "variants": [ { "name": "Big", - "configuration_reference": "ShoppingCart:Big", "status_override": "Disabled" } ], @@ -232,8 +220,7 @@ "enabled": true, "variants": [ { - "name": "Big", - "configuration_reference": "ShoppingCart:Big" + "name": "Big" } ], "allocation": { @@ -255,8 +242,7 @@ "enabled": false, "variants": [ { - "name": "Big", - "configuration_reference": "ShoppingCart:Big" + "name": "Big" } ], "allocation": { @@ -410,20 +396,6 @@ "enabled": true } }, - { - "id": "VariantFeatureBothConfigurations", - "enabled": true, - "variants": [ - { - "name": "Small", - "configuration_value": "600px", - "configuration_reference": "ShoppingCart:Small" - } - ], - "allocation": { - "default_when_enabled": "Small" - } - }, { "id": "VariantFeatureInvalidStatusOverride", "enabled": true, From 9732c8f4b2876e6b7bd5dd52a4fe657cb3e0a0a2 Mon Sep 17 00:00:00 2001 From: Ross Grambo Date: Wed, 4 Sep 2024 12:04:38 -0700 Subject: [PATCH 08/15] Renames and updates EvaluationDataToAppInsights example (#490) * Renames project and cleans up startup code + auth * Update examples/VariantAndTelemetryDemo/Program.cs Co-authored-by: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> --------- Co-authored-by: Zhiyuan Liang <141655842+zhiyuanliang-ms@users.noreply.github.com> --- Microsoft.FeatureManagement.sln | 2 +- README.md | 2 +- .../HttpContextTargetingContextAccessor.cs | 53 ------------------ .../Pages/RandomizeUser.cshtml | 4 -- .../Pages/RandomizeUser.cshtml.cs | 18 ------ .../Pages/Checkout.cshtml | 0 .../Pages/Checkout.cshtml.cs | 2 +- .../Pages/Error.cshtml | 0 .../Pages/Error.cshtml.cs | 2 +- .../Pages/Index.cshtml | 0 .../Pages/Index.cshtml.cs | 4 +- .../Pages/RandomizeUser.cshtml | 4 ++ .../Pages/RandomizeUser.cshtml.cs | 30 ++++++++++ .../Pages/Shared/_Layout.cshtml | 10 ++-- .../Pages/Shared/_Layout.cshtml.css | 0 .../Shared/_ValidationScriptsPartial.cshtml | 0 .../Pages/_ViewImports.cshtml | 4 +- .../Pages/_ViewStart.cshtml | 0 .../Program.cs | 21 +++---- .../README.md | 0 .../VariantAndTelemetryDemo.csproj} | 2 +- .../appsettings.Development.json | 0 .../appsettings.json | 0 .../wwwroot/css/site.css | 0 .../wwwroot/favicon.ico | Bin .../wwwroot/js/site.js | 0 .../wwwroot/lib/bootstrap/LICENSE | 0 .../lib/bootstrap/dist/css/bootstrap-grid.css | 0 .../bootstrap/dist/css/bootstrap-grid.css.map | 0 .../bootstrap/dist/css/bootstrap-grid.min.css | 0 .../dist/css/bootstrap-grid.min.css.map | 0 .../bootstrap/dist/css/bootstrap-grid.rtl.css | 0 .../dist/css/bootstrap-grid.rtl.css.map | 0 .../dist/css/bootstrap-grid.rtl.min.css | 0 .../dist/css/bootstrap-grid.rtl.min.css.map | 0 .../bootstrap/dist/css/bootstrap-reboot.css | 0 .../dist/css/bootstrap-reboot.css.map | 0 .../dist/css/bootstrap-reboot.min.css | 0 .../dist/css/bootstrap-reboot.min.css.map | 0 .../dist/css/bootstrap-reboot.rtl.css | 0 .../dist/css/bootstrap-reboot.rtl.css.map | 0 .../dist/css/bootstrap-reboot.rtl.min.css | 0 .../dist/css/bootstrap-reboot.rtl.min.css.map | 0 .../dist/css/bootstrap-utilities.css | 0 .../dist/css/bootstrap-utilities.css.map | 0 .../dist/css/bootstrap-utilities.min.css | 0 .../dist/css/bootstrap-utilities.min.css.map | 0 .../dist/css/bootstrap-utilities.rtl.css | 0 .../dist/css/bootstrap-utilities.rtl.css.map | 0 .../dist/css/bootstrap-utilities.rtl.min.css | 0 .../css/bootstrap-utilities.rtl.min.css.map | 0 .../lib/bootstrap/dist/css/bootstrap.css | 0 .../lib/bootstrap/dist/css/bootstrap.css.map | 0 .../lib/bootstrap/dist/css/bootstrap.min.css | 0 .../bootstrap/dist/css/bootstrap.min.css.map | 0 .../lib/bootstrap/dist/css/bootstrap.rtl.css | 0 .../bootstrap/dist/css/bootstrap.rtl.css.map | 0 .../bootstrap/dist/css/bootstrap.rtl.min.css | 0 .../dist/css/bootstrap.rtl.min.css.map | 0 .../lib/bootstrap/dist/js/bootstrap.bundle.js | 0 .../bootstrap/dist/js/bootstrap.bundle.js.map | 0 .../bootstrap/dist/js/bootstrap.bundle.min.js | 0 .../dist/js/bootstrap.bundle.min.js.map | 0 .../lib/bootstrap/dist/js/bootstrap.esm.js | 0 .../bootstrap/dist/js/bootstrap.esm.js.map | 0 .../bootstrap/dist/js/bootstrap.esm.min.js | 0 .../dist/js/bootstrap.esm.min.js.map | 0 .../lib/bootstrap/dist/js/bootstrap.js | 0 .../lib/bootstrap/dist/js/bootstrap.js.map | 0 .../lib/bootstrap/dist/js/bootstrap.min.js | 0 .../bootstrap/dist/js/bootstrap.min.js.map | 0 .../jquery-validation-unobtrusive/LICENSE.txt | 0 .../jquery.validate.unobtrusive.js | 0 .../jquery.validate.unobtrusive.min.js | 0 .../wwwroot/lib/jquery-validation/LICENSE.md | 0 .../dist/additional-methods.js | 0 .../dist/additional-methods.min.js | 0 .../jquery-validation/dist/jquery.validate.js | 0 .../dist/jquery.validate.min.js | 0 .../wwwroot/lib/jquery/LICENSE.txt | 0 .../wwwroot/lib/jquery/dist/jquery.js | 0 .../wwwroot/lib/jquery/dist/jquery.min.js | 0 .../wwwroot/lib/jquery/dist/jquery.min.map | 0 83 files changed, 59 insertions(+), 99 deletions(-) delete mode 100644 examples/EvaluationDataToApplicationInsights/HttpContextTargetingContextAccessor.cs delete mode 100644 examples/EvaluationDataToApplicationInsights/Pages/RandomizeUser.cshtml delete mode 100644 examples/EvaluationDataToApplicationInsights/Pages/RandomizeUser.cshtml.cs rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Checkout.cshtml (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Checkout.cshtml.cs (67%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Error.cshtml (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Error.cshtml.cs (92%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Index.cshtml (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Index.cshtml.cs (94%) create mode 100644 examples/VariantAndTelemetryDemo/Pages/RandomizeUser.cshtml create mode 100644 examples/VariantAndTelemetryDemo/Pages/RandomizeUser.cshtml.cs rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Shared/_Layout.cshtml (85%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Shared/_Layout.cshtml.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/Shared/_ValidationScriptsPartial.cshtml (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/_ViewImports.cshtml (66%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Pages/_ViewStart.cshtml (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/Program.cs (72%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/README.md (100%) rename examples/{EvaluationDataToApplicationInsights/EvaluationDataToApplicationInsights.csproj => VariantAndTelemetryDemo/VariantAndTelemetryDemo.csproj} (94%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/appsettings.Development.json (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/appsettings.json (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/css/site.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/favicon.ico (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/js/site.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/LICENSE (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery-validation/LICENSE.md (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery-validation/dist/additional-methods.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery-validation/dist/additional-methods.min.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery-validation/dist/jquery.validate.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery/LICENSE.txt (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery/dist/jquery.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery/dist/jquery.min.js (100%) rename examples/{EvaluationDataToApplicationInsights => VariantAndTelemetryDemo}/wwwroot/lib/jquery/dist/jquery.min.map (100%) diff --git a/Microsoft.FeatureManagement.sln b/Microsoft.FeatureManagement.sln index 3b8c8661..65481890 100644 --- a/Microsoft.FeatureManagement.sln +++ b/Microsoft.FeatureManagement.sln @@ -25,7 +25,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TargetingConsoleApp", "exam EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FeatureManagement.Telemetry.ApplicationInsights", "src\Microsoft.FeatureManagement.Telemetry.ApplicationInsights\Microsoft.FeatureManagement.Telemetry.ApplicationInsights.csproj", "{7964DC66-B2D3-412D-B18A-86D1E07D149D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EvaluationDataToApplicationInsights", "examples\EvaluationDataToApplicationInsights\EvaluationDataToApplicationInsights.csproj", "{1502529E-47E9-4306-98C4-BF6CF7C7C275}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VariantAndTelemetryDemo", "examples\VariantAndTelemetryDemo\VariantAndTelemetryDemo.csproj", "{1502529E-47E9-4306-98C4-BF6CF7C7C275}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorServerApp", "examples\BlazorServerApp\BlazorServerApp.csproj", "{12BAB5A6-4EEB-4917-B5D9-4AFB6253008E}" EndProject diff --git a/README.md b/README.md index 5c9718c4..22acae9f 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Feature management provides a way to develop and expose application functionalit * [ASP.NET Core Web App (Razor Page)](./examples/RazorPages) * [ASP.NET Core Web App (MVC)](./examples/FeatureFlagDemo) * [Blazor Server App](./examples/BlazorServerApp) -* [ASP.NET Core Web App with Feature Flag Telemetry](./examples/EvaluationDataToApplicationInsights) +* [ASP.NET Core Web App with Variants and Telemetry](./examples/VariantAndTelemetryDemo) * [ASP.NET Core Web App with Variant Service](./examples/VariantServiceDemo) ## Contributing diff --git a/examples/EvaluationDataToApplicationInsights/HttpContextTargetingContextAccessor.cs b/examples/EvaluationDataToApplicationInsights/HttpContextTargetingContextAccessor.cs deleted file mode 100644 index eeaa16b1..00000000 --- a/examples/EvaluationDataToApplicationInsights/HttpContextTargetingContextAccessor.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -// -using Microsoft.FeatureManagement.FeatureFilters; - -namespace EvaluationDataToApplicationInsights -{ - /// - /// 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); - } - - // - // Grab username from cookie - string username = httpContext.Request.Cookies["username"]; - - var groups = new List(); - - // - // Build targeting context based on user info - var targetingContext = new TargetingContext - { - UserId = username, - Groups = groups - }; - - // - // Cache for subsequent lookup - httpContext.Items[TargetingContextLookup] = targetingContext; - - return new ValueTask(targetingContext); - } - } -} diff --git a/examples/EvaluationDataToApplicationInsights/Pages/RandomizeUser.cshtml b/examples/EvaluationDataToApplicationInsights/Pages/RandomizeUser.cshtml deleted file mode 100644 index fa29a988..00000000 --- a/examples/EvaluationDataToApplicationInsights/Pages/RandomizeUser.cshtml +++ /dev/null @@ -1,4 +0,0 @@ -@page -@model EvaluationDataToApplicationInsights.Pages.RandomizeUserModel -@{ -} diff --git a/examples/EvaluationDataToApplicationInsights/Pages/RandomizeUser.cshtml.cs b/examples/EvaluationDataToApplicationInsights/Pages/RandomizeUser.cshtml.cs deleted file mode 100644 index dad3744d..00000000 --- a/examples/EvaluationDataToApplicationInsights/Pages/RandomizeUser.cshtml.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace EvaluationDataToApplicationInsights.Pages -{ - public class RandomizeUserModel : PageModel - { - public IActionResult OnGet() - { - // Clear Application Insights cookies and generate new username - Response.Cookies.Delete("ai_user"); - Response.Cookies.Delete("ai_session"); - Response.Cookies.Append("username", Random.Shared.Next().ToString()); - - return RedirectToPage("/Index"); - } - } -} diff --git a/examples/EvaluationDataToApplicationInsights/Pages/Checkout.cshtml b/examples/VariantAndTelemetryDemo/Pages/Checkout.cshtml similarity index 100% rename from examples/EvaluationDataToApplicationInsights/Pages/Checkout.cshtml rename to examples/VariantAndTelemetryDemo/Pages/Checkout.cshtml diff --git a/examples/EvaluationDataToApplicationInsights/Pages/Checkout.cshtml.cs b/examples/VariantAndTelemetryDemo/Pages/Checkout.cshtml.cs similarity index 67% rename from examples/EvaluationDataToApplicationInsights/Pages/Checkout.cshtml.cs rename to examples/VariantAndTelemetryDemo/Pages/Checkout.cshtml.cs index ceaaef99..ea8a9104 100644 --- a/examples/EvaluationDataToApplicationInsights/Pages/Checkout.cshtml.cs +++ b/examples/VariantAndTelemetryDemo/Pages/Checkout.cshtml.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Mvc.RazorPages; -namespace EvaluationDataToApplicationInsights.Pages +namespace VariantAndTelemetryDemo.Pages { public class CheckoutModel : PageModel { diff --git a/examples/EvaluationDataToApplicationInsights/Pages/Error.cshtml b/examples/VariantAndTelemetryDemo/Pages/Error.cshtml similarity index 100% rename from examples/EvaluationDataToApplicationInsights/Pages/Error.cshtml rename to examples/VariantAndTelemetryDemo/Pages/Error.cshtml diff --git a/examples/EvaluationDataToApplicationInsights/Pages/Error.cshtml.cs b/examples/VariantAndTelemetryDemo/Pages/Error.cshtml.cs similarity index 92% rename from examples/EvaluationDataToApplicationInsights/Pages/Error.cshtml.cs rename to examples/VariantAndTelemetryDemo/Pages/Error.cshtml.cs index f20de344..4aba79bc 100644 --- a/examples/EvaluationDataToApplicationInsights/Pages/Error.cshtml.cs +++ b/examples/VariantAndTelemetryDemo/Pages/Error.cshtml.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using System.Diagnostics; -namespace EvaluationDataToApplicationInsights.Pages +namespace VariantAndTelemetryDemo.Pages { [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [IgnoreAntiforgeryToken] diff --git a/examples/EvaluationDataToApplicationInsights/Pages/Index.cshtml b/examples/VariantAndTelemetryDemo/Pages/Index.cshtml similarity index 100% rename from examples/EvaluationDataToApplicationInsights/Pages/Index.cshtml rename to examples/VariantAndTelemetryDemo/Pages/Index.cshtml diff --git a/examples/EvaluationDataToApplicationInsights/Pages/Index.cshtml.cs b/examples/VariantAndTelemetryDemo/Pages/Index.cshtml.cs similarity index 94% rename from examples/EvaluationDataToApplicationInsights/Pages/Index.cshtml.cs rename to examples/VariantAndTelemetryDemo/Pages/Index.cshtml.cs index 0fbcf0b7..07b1d300 100644 --- a/examples/EvaluationDataToApplicationInsights/Pages/Index.cshtml.cs +++ b/examples/VariantAndTelemetryDemo/Pages/Index.cshtml.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.FeatureManagement; -namespace EvaluationDataToApplicationInsights.Pages +namespace VariantAndTelemetryDemo.Pages { public class IndexModel : PageModel { @@ -22,7 +22,7 @@ public IndexModel( public async Task OnGet() { - Username = Request.Cookies["username"]; + Username = HttpContext.User.Identity.Name; if (string.IsNullOrEmpty(Username)) { diff --git a/examples/VariantAndTelemetryDemo/Pages/RandomizeUser.cshtml b/examples/VariantAndTelemetryDemo/Pages/RandomizeUser.cshtml new file mode 100644 index 00000000..8aa505b1 --- /dev/null +++ b/examples/VariantAndTelemetryDemo/Pages/RandomizeUser.cshtml @@ -0,0 +1,4 @@ +@page +@model VariantAndTelemetryDemo.Pages.RandomizeUserModel +@{ +} diff --git a/examples/VariantAndTelemetryDemo/Pages/RandomizeUser.cshtml.cs b/examples/VariantAndTelemetryDemo/Pages/RandomizeUser.cshtml.cs new file mode 100644 index 00000000..781339d1 --- /dev/null +++ b/examples/VariantAndTelemetryDemo/Pages/RandomizeUser.cshtml.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using System.Security.Claims; + +namespace VariantAndTelemetryDemo.Pages +{ + public class RandomizeUserModel : PageModel + { + public IActionResult OnGet() + { + // Clear Application Insights cookies and + Response.Cookies.Delete("ai_user"); + Response.Cookies.Delete("ai_session"); + + // Generate new user claim + var claims = new List + { + new Claim(ClaimTypes.Name, Random.Shared.Next().ToString()) + }; + + var identity = new ClaimsIdentity(claims, "CookieAuth"); + var principal = new ClaimsPrincipal(identity); + + HttpContext.SignInAsync("CookieAuth", principal); + + return RedirectToPage("/Index"); + } + } +} diff --git a/examples/EvaluationDataToApplicationInsights/Pages/Shared/_Layout.cshtml b/examples/VariantAndTelemetryDemo/Pages/Shared/_Layout.cshtml similarity index 85% rename from examples/EvaluationDataToApplicationInsights/Pages/Shared/_Layout.cshtml rename to examples/VariantAndTelemetryDemo/Pages/Shared/_Layout.cshtml index c8d3f799..365b135c 100644 --- a/examples/EvaluationDataToApplicationInsights/Pages/Shared/_Layout.cshtml +++ b/examples/VariantAndTelemetryDemo/Pages/Shared/_Layout.cshtml @@ -6,10 +6,10 @@ - @ViewData["Title"] - EvaluationDataToApplicationInsights + @ViewData["Title"] - VariantAndTelemetryDemo - + @Html.Raw(JavaScriptSnippet.FullScript) @@ -20,7 +20,7 @@