From a2484f5f26a8d23e5f7aefdcf4ffba2ac14efce2 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Thu, 17 Apr 2025 11:33:15 -0700 Subject: [PATCH 1/3] fix isjson and separate exclusion logic --- .../Extensions/ContentTypeExtensions.cs | 56 ++++++++++--------- .../JsonKeyValueAdapter.cs | 2 +- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ContentTypeExtensions.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ContentTypeExtensions.cs index 2f739a52c..ca2a9d539 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ContentTypeExtensions.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ContentTypeExtensions.cs @@ -12,16 +12,12 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Extensions { internal static class ContentTypeExtensions { - private static readonly IEnumerable ExcludedJsonContentTypes = new[] - { - FeatureManagementConstants.ContentType, - KeyVaultConstants.ContentType - }; - public static bool IsAi(this ContentType contentType) { return contentType != null && contentType.IsJson() && + !contentType.IsFeatureFlag() && + !contentType.IsKeyVaultReference() && contentType.Parameters.ContainsKey("profile") && !string.IsNullOrEmpty(contentType.Parameters["profile"]) && contentType.Parameters["profile"].StartsWith(RequestTracingConstants.AIMimeProfile); @@ -31,6 +27,8 @@ public static bool IsAiChatCompletion(this ContentType contentType) { return contentType != null && contentType.IsJson() && + !contentType.IsFeatureFlag() && + !contentType.IsKeyVaultReference() && contentType.Parameters.ContainsKey("profile") && !string.IsNullOrEmpty(contentType.Parameters["profile"]) && contentType.Parameters["profile"].StartsWith(RequestTracingConstants.AIChatCompletionMimeProfile); @@ -45,37 +43,43 @@ public static bool IsJson(this ContentType contentType) string acceptedMainType = "application"; string acceptedSubType = "json"; - string mediaType = contentType.MediaType; - - if (!ExcludedJsonContentTypes.Contains(mediaType, StringComparer.OrdinalIgnoreCase)) - { - ReadOnlySpan mediaTypeSpan = mediaType.AsSpan(); - // Since contentType has been validated using System.Net.Mime.ContentType, - // mediaType will always have exactly 2 parts after splitting on '/' - int slashIndex = mediaTypeSpan.IndexOf('/'); + ReadOnlySpan mediaTypeSpan = contentType.MediaType.AsSpan(); - if (mediaTypeSpan.Slice(0, slashIndex).Equals(acceptedMainType.AsSpan(), StringComparison.OrdinalIgnoreCase)) - { - ReadOnlySpan subTypeSpan = mediaTypeSpan.Slice(slashIndex + 1); + // Since contentType has been validated using System.Net.Mime.ContentType, + // mediaType will always have exactly 2 parts after splitting on '/' + int slashIndex = mediaTypeSpan.IndexOf('/'); - while (!subTypeSpan.IsEmpty) - { - int plusIndex = subTypeSpan.IndexOf('+'); + if (mediaTypeSpan.Slice(0, slashIndex).Equals(acceptedMainType.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + ReadOnlySpan subTypeSpan = mediaTypeSpan.Slice(slashIndex + 1); - ReadOnlySpan currentSubType = plusIndex == -1 ? subTypeSpan : subTypeSpan.Slice(0, plusIndex); + while (!subTypeSpan.IsEmpty) + { + int plusIndex = subTypeSpan.IndexOf('+'); - if (currentSubType.Equals(acceptedSubType.AsSpan(), StringComparison.OrdinalIgnoreCase)) - { - return true; - } + ReadOnlySpan currentSubType = plusIndex == -1 ? subTypeSpan : subTypeSpan.Slice(0, plusIndex); - subTypeSpan = plusIndex == -1 ? ReadOnlySpan.Empty : subTypeSpan.Slice(plusIndex + 1); + if (currentSubType.Equals(acceptedSubType.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return true; } + + subTypeSpan = plusIndex == -1 ? ReadOnlySpan.Empty : subTypeSpan.Slice(plusIndex + 1); } } return false; } + + public static bool IsFeatureFlag(this ContentType contentType) + { + return contentType.MediaType.Equals(FeatureManagementConstants.ContentType); + } + + public static bool IsKeyVaultReference(this ContentType contentType) + { + return contentType.MediaType.Equals(KeyVaultConstants.ContentType); + } } } diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs index 87c28d698..36163a6f3 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs @@ -53,7 +53,7 @@ public bool CanProcess(ConfigurationSetting setting) if (setting.ContentType.TryParseContentType(out ContentType contentType)) { - return contentType.IsJson(); + return contentType.IsJson() && !contentType.IsFeatureFlag() && !contentType.IsKeyVaultReference(); } return false; From d3c8c6e6fdcaa133d0a498ed5b68aed2e8a0299d Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Thu, 17 Apr 2025 12:24:47 -0700 Subject: [PATCH 2/3] update adapters to use new extension --- .../AzureKeyVaultKeyValueAdapter.cs | 18 ++++++++++++++-- .../FeatureManagementKeyValueAdapter.cs | 21 ++++++++++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs index a272b413f..a0d350852 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs @@ -4,9 +4,12 @@ using Azure; using Azure.Data.AppConfiguration; using Azure.Security.KeyVault.Secrets; +using Microsoft.Extensions.Configuration.AzureAppConfiguration.Extensions; +using Microsoft.Extensions.Configuration.AzureAppConfiguration.FeatureManagement; using System; using System.Collections.Generic; using System.Linq; +using System.Net.Mime; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -72,8 +75,19 @@ KeyVaultReferenceException CreateKeyVaultReferenceException(string message, Conf public bool CanProcess(ConfigurationSetting setting) { - string contentType = setting?.ContentType?.Split(';')[0].Trim(); - return string.Equals(contentType, KeyVaultConstants.ContentType); + if (setting == null || + string.IsNullOrWhiteSpace(setting.Value) || + string.IsNullOrWhiteSpace(setting.ContentType)) + { + return false; + } + + if (setting.ContentType.TryParseContentType(out ContentType contentType)) + { + return contentType.IsKeyVaultReference(); + } + + return false; } public void OnChangeDetected(ConfigurationSetting setting = null) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs index b6d137f38..d9cd8307f 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Mime; using System.Security.Cryptography; using System.Text; using System.Text.Json; @@ -45,10 +46,24 @@ public Task>> ProcessKeyValue(Configura public bool CanProcess(ConfigurationSetting setting) { - string contentType = setting?.ContentType?.Split(';')[0].Trim(); + if (setting == null || + string.IsNullOrWhiteSpace(setting.Value) || + string.IsNullOrWhiteSpace(setting.ContentType)) + { + return false; + } + + if (setting.Key.StartsWith(FeatureManagementConstants.FeatureFlagMarker)) + { + return true; + } - return string.Equals(contentType, FeatureManagementConstants.ContentType) || - setting.Key.StartsWith(FeatureManagementConstants.FeatureFlagMarker); + if (setting.ContentType.TryParseContentType(out ContentType contentType)) + { + return contentType.IsFeatureFlag(); + } + + return false; } public bool NeedsRefresh() From b17c3f1eeafec37055958ad77fd96275a9a1a5e0 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Thu, 17 Apr 2025 14:10:20 -0700 Subject: [PATCH 3/3] PR comments --- .../AzureKeyVaultKeyValueAdapter.cs | 8 ++------ .../FeatureManagement/FeatureManagementKeyValueAdapter.cs | 8 ++------ .../JsonKeyValueAdapter.cs | 4 +++- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs index a0d350852..0498ba09e 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs @@ -82,12 +82,8 @@ public bool CanProcess(ConfigurationSetting setting) return false; } - if (setting.ContentType.TryParseContentType(out ContentType contentType)) - { - return contentType.IsKeyVaultReference(); - } - - return false; + return setting.ContentType.TryParseContentType(out ContentType contentType) + && contentType.IsKeyVaultReference(); } public void OnChangeDetected(ConfigurationSetting setting = null) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs index d9cd8307f..76ab04e4a 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs @@ -58,12 +58,8 @@ public bool CanProcess(ConfigurationSetting setting) return true; } - if (setting.ContentType.TryParseContentType(out ContentType contentType)) - { - return contentType.IsFeatureFlag(); - } - - return false; + return setting.ContentType.TryParseContentType(out ContentType contentType) && + contentType.IsFeatureFlag(); } public bool NeedsRefresh() diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs index 36163a6f3..74d2b882a 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs @@ -53,7 +53,9 @@ public bool CanProcess(ConfigurationSetting setting) if (setting.ContentType.TryParseContentType(out ContentType contentType)) { - return contentType.IsJson() && !contentType.IsFeatureFlag() && !contentType.IsKeyVaultReference(); + return contentType.IsJson() && + !contentType.IsFeatureFlag() && + !contentType.IsKeyVaultReference(); } return false;