diff --git a/Microsoft.FeatureManagement.sln b/Microsoft.FeatureManagement.sln
index 8963b77b..6d7e1f18 100644
--- a/Microsoft.FeatureManagement.sln
+++ b/Microsoft.FeatureManagement.sln
@@ -27,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FeatureManagement
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EvaluationDataToApplicationInsights", "examples\EvaluationDataToApplicationInsights\EvaluationDataToApplicationInsights.csproj", "{1502529E-47E9-4306-98C4-BF6CF7C7C275}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore", "src\Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore\Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore.csproj", "{C647611B-A8E5-4AD7-9DBA-60DDE276644B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -73,6 +75,10 @@ Global
{1502529E-47E9-4306-98C4-BF6CF7C7C275}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1502529E-47E9-4306-98C4-BF6CF7C7C275}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1502529E-47E9-4306-98C4-BF6CF7C7C275}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C647611B-A8E5-4AD7-9DBA-60DDE276644B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C647611B-A8E5-4AD7-9DBA-60DDE276644B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C647611B-A8E5-4AD7-9DBA-60DDE276644B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C647611B-A8E5-4AD7-9DBA-60DDE276644B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Microsoft.FeatureManagement.AspNetCore/TargetingHttpContextMiddleware.cs b/src/Microsoft.FeatureManagement.AspNetCore/TargetingHttpContextMiddleware.cs
new file mode 100644
index 00000000..8dd2378f
--- /dev/null
+++ b/src/Microsoft.FeatureManagement.AspNetCore/TargetingHttpContextMiddleware.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+//
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+using Microsoft.FeatureManagement.FeatureFilters;
+using System;
+using System.Threading.Tasks;
+
+namespace Microsoft.FeatureManagement
+{
+ ///
+ /// Used to add targeting information to HTTP context.
+ ///
+ public class TargetingHttpContextMiddleware
+ {
+ private readonly RequestDelegate _next;
+ private readonly ILogger _logger;
+
+ private const string TargetingIdKey = $"Microsoft.FeatureManagement.TargetingId";
+
+ ///
+ /// Creates an instance of the TargetingHttpContextMiddleware
+ ///
+ public TargetingHttpContextMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) {
+ _next = next ?? throw new ArgumentNullException(nameof(next));
+ _logger = loggerFactory?.CreateLogger() ?? throw new ArgumentNullException(nameof(loggerFactory));
+ }
+
+ ///
+ /// Adds targeting information to the HTTP context.
+ ///
+ /// The to add the targeting information to.
+ /// The to retrieve the targeting information from.
+ /// Thrown if the provided context or targetingContextAccessor is null.
+ public async Task InvokeAsync(HttpContext context, ITargetingContextAccessor targetingContextAccessor)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ if (targetingContextAccessor == null)
+ {
+ throw new ArgumentNullException(nameof(targetingContextAccessor));
+ }
+
+ TargetingContext targetingContext = await targetingContextAccessor.GetContextAsync().ConfigureAwait(false);
+
+ if (targetingContext != null)
+ {
+ context.Items[TargetingIdKey] = targetingContext.UserId;
+ }
+ else
+ {
+ _logger.LogDebug("The targeting context accessor returned a null TargetingContext");
+ }
+
+ await _next(context);
+ }
+ }
+}
diff --git a/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore.csproj b/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore.csproj
new file mode 100644
index 00000000..2d8e6d4f
--- /dev/null
+++ b/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore.csproj
@@ -0,0 +1,51 @@
+
+
+
+
+
+ 4
+ 0
+ 0
+ -preview
+
+
+
+
+
+ net6.0
+ enable
+ true
+ false
+ ..\..\build\Microsoft.FeatureManagement.snk
+
+
+
+ Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore provides a solution for tagging Application Insights telemetry with Microsoft.FeatureManagement targeting information.
+ Microsoft
+ Microsoft
+ https://licenses.nuget.org/MIT
+ https://github.com/Azure/AppConfiguration
+ Release notes can be found at https://aka.ms/MicrosoftFeatureManagementReleaseNotes
+ Microsoft FeatureManagement FeatureFlags ApplicationInsights
+ https://aka.ms/AzureAppConfigurationPackageIcon
+ © Microsoft Corporation. All rights reserved.
+
+
+
+
+
+
+
+
+
+
+
+
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\XMLComments\$(MSBuildProjectName).xml
+
+
+
+
+
+
+
diff --git a/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore/TargetingTelemetryInitializer.cs b/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore/TargetingTelemetryInitializer.cs
new file mode 100644
index 00000000..5614a3f3
--- /dev/null
+++ b/src/Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore/TargetingTelemetryInitializer.cs
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+//
+
+using Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers;
+using Microsoft.ApplicationInsights.Channel;
+using Microsoft.ApplicationInsights.DataContracts;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.FeatureManagement.Telemetry.ApplicationInsights.AspNetCore
+{
+ ///
+ /// Used to add targeting information to outgoing Application Insights telemetry.
+ ///
+ public class TargetingTelemetryInitializer : TelemetryInitializerBase
+ {
+ private const string TargetingIdKey = $"Microsoft.FeatureManagement.TargetingId";
+
+ ///
+ /// Creates an instance of the TargetingTelemetryInitializer
+ ///
+ public TargetingTelemetryInitializer(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor)
+ {
+ }
+
+ ///
+ /// When telemetry is initialized, adds targeting information to all relevant telemetry.
+ ///
+ /// The to get the targeting information from.
+ /// The relevant to the telemetry.
+ /// The to be initialized.
+ /// Thrown if the any param is null.
+ protected override void OnInitializeTelemetry(HttpContext httpContext, RequestTelemetry requestTelemetry, ITelemetry telemetry)
+ {
+ if (telemetry == null)
+ {
+ throw new ArgumentNullException("telemetry");
+ }
+
+ if (httpContext == null)
+ {
+ throw new ArgumentNullException("httpContext");
+ }
+
+ // Extract the targeting id from the http context
+ string targetingId = null;
+
+ if (httpContext.Items.TryGetValue(TargetingIdKey, out object value))
+ {
+ targetingId = value?.ToString();
+ }
+
+ if (!string.IsNullOrEmpty(targetingId))
+ {
+ // Telemetry.Properties is deprecated in favor of ISupportProperties
+ if (telemetry is ISupportProperties telemetryWithSupportProperties)
+ {
+ telemetryWithSupportProperties.Properties["TargetingId"] = targetingId;
+ }
+ }
+ }
+ }
+}