Skip to content

Commit c43aab3

Browse files
Support comment in json key value (#685)
* support jsonc * remove unused reference * use private static option
1 parent ba88464 commit c43aab3

File tree

2 files changed

+90
-1
lines changed

2 files changed

+90
-1
lines changed

src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration
1515
{
1616
internal class JsonKeyValueAdapter : IKeyValueAdapter
1717
{
18+
private static readonly JsonDocumentOptions JsonParseOptions = new JsonDocumentOptions
19+
{
20+
CommentHandling = JsonCommentHandling.Skip
21+
};
22+
1823
public Task<IEnumerable<KeyValuePair<string, string>>> ProcessKeyValue(ConfigurationSetting setting, Uri endpoint, Logger logger, CancellationToken cancellationToken)
1924
{
2025
if (setting == null)
@@ -28,7 +33,7 @@ public Task<IEnumerable<KeyValuePair<string, string>>> ProcessKeyValue(Configura
2833

2934
try
3035
{
31-
using (JsonDocument document = JsonDocument.Parse(rootJson))
36+
using (JsonDocument document = JsonDocument.Parse(rootJson, JsonParseOptions))
3237
{
3338
keyValuePairs = new JsonFlattener().FlattenJson(document.RootElement);
3439
}

tests/Tests.AzureAppConfiguration/Unit/JsonContentTypeTests.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,90 @@ public void JsonContentTypeTests_JsonKeyValueAdapterCannotProcessKeyVaultReferen
276276
Assert.False(jsonKeyValueAdapter.CanProcess(setting));
277277
}
278278

279+
[Fact]
280+
public void JsonContentTypeTests_LoadJsonValuesWithComments()
281+
{
282+
List<ConfigurationSetting> _kvCollection = new List<ConfigurationSetting>
283+
{
284+
// Test various comment styles and positions
285+
ConfigurationModelFactory.ConfigurationSetting(
286+
key: "MixedCommentStyles",
287+
value: @"{
288+
// Single line comment at start
289+
""ApiSettings"": {
290+
""BaseUrl"": ""https://api.example.com"", // Inline single line
291+
/* Multi-line comment
292+
spanning multiple lines */
293+
""ApiKey"": ""secret-key"",
294+
""Endpoints"": [
295+
// Comment before array element
296+
""/users"",
297+
/* Comment between elements */
298+
""/orders"",
299+
""/products"" // Comment after element
300+
]
301+
},
302+
// Test edge cases
303+
""StringWithSlashes"": ""This is not a // comment"",
304+
""StringWithStars"": ""This is not a /* comment */"",
305+
""UrlValue"": ""https://example.com/path"", // This is a real comment
306+
""EmptyComment"": ""value"", //
307+
/**/
308+
""AfterEmptyComment"": ""value2""
309+
/* Final multi-line comment */
310+
}",
311+
contentType: "application/json"),
312+
// Test invalid JSON with comments
313+
ConfigurationModelFactory.ConfigurationSetting(
314+
key: "InvalidJsonWithComments",
315+
value: @"// This is a comment
316+
{ invalid json structure
317+
// Another comment
318+
missing quotes and braces",
319+
contentType: "application/json"),
320+
// Test only comments (should be invalid JSON)
321+
ConfigurationModelFactory.ConfigurationSetting(
322+
key: "OnlyComments",
323+
value: @"
324+
// Just comments
325+
/* No actual content */
326+
",
327+
contentType: "application/json")
328+
};
329+
330+
var mockClientManager = GetMockConfigurationClientManager(_kvCollection);
331+
332+
var config = new ConfigurationBuilder()
333+
.AddAzureAppConfiguration(options => options.ClientManager = mockClientManager)
334+
.Build();
335+
336+
// Verify mixed comment styles are properly parsed
337+
Assert.Equal("https://api.example.com", config["MixedCommentStyles:ApiSettings:BaseUrl"]);
338+
Assert.Equal("secret-key", config["MixedCommentStyles:ApiSettings:ApiKey"]);
339+
Assert.Equal("/users", config["MixedCommentStyles:ApiSettings:Endpoints:0"]);
340+
Assert.Equal("/orders", config["MixedCommentStyles:ApiSettings:Endpoints:1"]);
341+
Assert.Equal("/products", config["MixedCommentStyles:ApiSettings:Endpoints:2"]);
342+
343+
// Verify edge cases where comment-like text appears in strings
344+
Assert.Equal("This is not a // comment", config["MixedCommentStyles:StringWithSlashes"]);
345+
Assert.Equal("This is not a /* comment */", config["MixedCommentStyles:StringWithStars"]);
346+
Assert.Equal("https://example.com/path", config["MixedCommentStyles:UrlValue"]);
347+
Assert.Equal("value", config["MixedCommentStyles:EmptyComment"]);
348+
Assert.Equal("value2", config["MixedCommentStyles:AfterEmptyComment"]);
349+
350+
// Invalid JSON should fall back to string value
351+
Assert.Equal(@"// This is a comment
352+
{ invalid json structure
353+
// Another comment
354+
missing quotes and braces", config["InvalidJsonWithComments"]);
355+
356+
// Only comments should be treated as string value (invalid JSON)
357+
Assert.Equal(@"
358+
// Just comments
359+
/* No actual content */
360+
", config["OnlyComments"]);
361+
}
362+
279363
private IConfigurationClientManager GetMockConfigurationClientManager(List<ConfigurationSetting> _kvCollection)
280364
{
281365
var mockResponse = new Mock<Response>();

0 commit comments

Comments
 (0)