Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ All notable changes to this project will be documented in this file.
- Removed the Newtonsoft.Json companion package and custom serializer abstraction.
- Made `AddObject` generic and added `JsonTypeInfo<T>` overloads for source-generated System.Text.Json metadata.
- Added `AddObjectAsFallback` for registering object configuration at the lowest precedence.
- Aligned object flattening with .NET 10 configuration semantics for null values, empty strings, empty objects, empty arrays, and null array elements.
- Aligned object configuration with .NET 10 JSON configuration semantics for null values, empty strings, empty objects, empty arrays, and null array elements.
- Reused the built-in JSON stream configuration provider instead of maintaining a custom JSON-to-configuration flattener and provider.

## 3.0.1 - 2024-07-12

Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.11" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.11" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.11" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="MinVer" Version="7.0.0" />
<PackageVersion Include="Moq" Version="4.18.4" />
Expand Down
148 changes: 0 additions & 148 deletions src/Objects/Internal/JsonConfigurationFlattener.cs

This file was deleted.

22 changes: 0 additions & 22 deletions src/Objects/Internal/ObjectConfigurationProvider.cs

This file was deleted.

20 changes: 0 additions & 20 deletions src/Objects/Internal/ObjectConfigurationSource.cs

This file was deleted.

45 changes: 41 additions & 4 deletions src/Objects/Internal/SystemTextJsonConfigurationSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
using System;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using Microsoft.Extensions.Configuration;

namespace Kralizek.Extensions.Configuration.Internal;

internal static class SystemTextJsonConfigurationSerializer
{
private static readonly JsonSerializerOptions JsonOptions = new();

public static JsonElement Serialize<T>(T source)
public static MemoryStream Serialize<T>(T source, string rootSectionName)
{
return JsonSerializer.SerializeToElement(source, JsonOptions);
return Serialize(rootSectionName, writer => JsonSerializer.Serialize(writer, source, JsonOptions));
}

public static JsonElement Serialize<T>(T source, JsonTypeInfo<T> jsonTypeInfo)
public static MemoryStream Serialize<T>(T source, JsonTypeInfo<T> jsonTypeInfo, string rootSectionName)
{
return JsonSerializer.SerializeToElement(source, jsonTypeInfo);
return Serialize(rootSectionName, writer => JsonSerializer.Serialize(writer, source, jsonTypeInfo));
}

private static MemoryStream Serialize(string rootSectionName, Action<Utf8JsonWriter> serialize)
{
var stream = new MemoryStream();

using (var writer = new Utf8JsonWriter(stream))
{
var rootSections = GetRootSections(rootSectionName);

foreach (var rootSection in rootSections)
{
writer.WriteStartObject();
writer.WritePropertyName(rootSection);
}

serialize(writer);

for (var index = 0; index < rootSections.Length; index++)
{
writer.WriteEndObject();
}
}

stream.Position = 0;

return stream;
}

private static string[] GetRootSections(string rootSectionName)
{
return string.IsNullOrEmpty(rootSectionName)
? Array.Empty<string>()
: rootSectionName.Split(new[] { ConfigurationPath.KeyDelimiter }, StringSplitOptions.None);
}
}
30 changes: 13 additions & 17 deletions src/Objects/ObjectConfigurationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.IO;
using System.Text.Json.Serialization.Metadata;
using Kralizek.Extensions.Configuration.Internal;
using Microsoft.Extensions.Configuration.Json;

// ReSharper disable CheckNamespace

Expand All @@ -12,7 +12,7 @@ public static class ObjectConfigurationExtensions
{
public static IConfigurationBuilder AddObject<T>(this IConfigurationBuilder configurationBuilder, T? objectToAdd, string? rootSectionName = "")
{
return AddObject(configurationBuilder, objectToAdd, rootSectionName, static value => SystemTextJsonConfigurationSerializer.Serialize(value));
return AddObject(configurationBuilder, objectToAdd, rootSectionName, static (value, rootSection) => SystemTextJsonConfigurationSerializer.Serialize(value, rootSection));
}

public static IConfigurationBuilder AddObject<T>(this IConfigurationBuilder configurationBuilder, T? objectToAdd, JsonTypeInfo<T> jsonTypeInfo, string? rootSectionName = "")
Expand All @@ -22,12 +22,12 @@ public static IConfigurationBuilder AddObject<T>(this IConfigurationBuilder conf
throw new ArgumentNullException(nameof(jsonTypeInfo));
}

return AddObject(configurationBuilder, objectToAdd, rootSectionName, value => SystemTextJsonConfigurationSerializer.Serialize(value, jsonTypeInfo));
return AddObject(configurationBuilder, objectToAdd, rootSectionName, (value, rootSection) => SystemTextJsonConfigurationSerializer.Serialize(value, jsonTypeInfo, rootSection));
}

public static IConfigurationBuilder AddObjectAsFallback<T>(this IConfigurationBuilder configurationBuilder, T? objectToAdd, string? rootSectionName = "")
{
return AddObjectAsFallback(configurationBuilder, objectToAdd, rootSectionName, static value => SystemTextJsonConfigurationSerializer.Serialize(value));
return AddObjectAsFallback(configurationBuilder, objectToAdd, rootSectionName, static (value, rootSection) => SystemTextJsonConfigurationSerializer.Serialize(value, rootSection));
}

public static IConfigurationBuilder AddObjectAsFallback<T>(this IConfigurationBuilder configurationBuilder, T? objectToAdd, JsonTypeInfo<T> jsonTypeInfo, string? rootSectionName = "")
Expand All @@ -37,10 +37,10 @@ public static IConfigurationBuilder AddObjectAsFallback<T>(this IConfigurationBu
throw new ArgumentNullException(nameof(jsonTypeInfo));
}

return AddObjectAsFallback(configurationBuilder, objectToAdd, rootSectionName, value => SystemTextJsonConfigurationSerializer.Serialize(value, jsonTypeInfo));
return AddObjectAsFallback(configurationBuilder, objectToAdd, rootSectionName, (value, rootSection) => SystemTextJsonConfigurationSerializer.Serialize(value, jsonTypeInfo, rootSection));
}

private static IConfigurationBuilder AddObject<T>(IConfigurationBuilder configurationBuilder, T? objectToAdd, string? rootSectionName, Func<T, JsonElement> serialize)
private static IConfigurationBuilder AddObject<T>(IConfigurationBuilder configurationBuilder, T? objectToAdd, string? rootSectionName, Func<T, string, Stream> serialize)
{
if (configurationBuilder is null)
{
Expand All @@ -52,12 +52,12 @@ private static IConfigurationBuilder AddObject<T>(IConfigurationBuilder configur
return configurationBuilder;
}

configurationBuilder.Add(CreateSource(objectToAdd, rootSectionName, serialize));
configurationBuilder.Sources.Add(CreateSource(objectToAdd, rootSectionName, serialize));

return configurationBuilder;
}

private static IConfigurationBuilder AddObjectAsFallback<T>(IConfigurationBuilder configurationBuilder, T? objectToAdd, string? rootSectionName, Func<T, JsonElement> serialize)
private static IConfigurationBuilder AddObjectAsFallback<T>(IConfigurationBuilder configurationBuilder, T? objectToAdd, string? rootSectionName, Func<T, string, Stream> serialize)
{
if (configurationBuilder is null)
{
Expand All @@ -74,15 +74,11 @@ private static IConfigurationBuilder AddObjectAsFallback<T>(IConfigurationBuilde
return configurationBuilder;
}

private static ObjectConfigurationSource CreateSource<T>(T objectToAdd, string? rootSectionName, Func<T, JsonElement> serialize)
private static JsonStreamConfigurationSource CreateSource<T>(T objectToAdd, string? rootSectionName, Func<T, string, Stream> serialize)
{
var rootSection = rootSectionName ?? string.Empty;

return new ObjectConfigurationSource(() =>
return new JsonStreamConfigurationSource
{
var json = serialize(objectToAdd);

return JsonConfigurationFlattener.Flatten(json, rootSection);
});
Stream = serialize(objectToAdd, rootSectionName ?? string.Empty)
};
}
}
1 change: 1 addition & 0 deletions src/Objects/Objects.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>
Expand Down
Loading