Make enums serialize as strings if using the reflection-based serializer. (#473)
* Make enums serialize as strings if using the reflection-based serializer. * Remove unnecessary partial * Use an explicit reflection-based converter for enums. * Update comments * Make the reflection-based enum converter public.
This commit is contained in:
parent
d7d9eab3f8
commit
1e8fb04037
2 changed files with 61 additions and 2 deletions
|
|
@ -5,8 +5,8 @@ using System.ComponentModel;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
#if !NET9_0_OR_GREATER
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
#endif
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
#if !NET9_0_OR_GREATER
|
||||
using ModelContextProtocol;
|
||||
|
|
@ -66,6 +66,31 @@ namespace ModelContextProtocol
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A JSON converter for enums that allows customizing the serialized string value of enum members
|
||||
/// using the <see cref="JsonStringEnumMemberNameAttribute"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a temporary workaround for lack of System.Text.Json's JsonStringEnumConverter<T>
|
||||
/// 9.x support for custom enum member naming. It will be replaced by the built-in functionality
|
||||
/// once .NET 9 is fully adopted.
|
||||
/// </remarks>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[RequiresUnreferencedCode("Requires unreferenced code to instantiate the generic enum converter.")]
|
||||
[RequiresDynamicCode("Requires dynamic code to instantiate the generic enum converter.")]
|
||||
public sealed class CustomizableJsonStringEnumConverter : JsonConverterFactory
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool CanConvert(Type typeToConvert) => typeToConvert.IsEnum;
|
||||
/// <inheritdoc/>
|
||||
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
Type converterType = typeof(CustomizableJsonStringEnumConverter<>).MakeGenericType(typeToConvert)!;
|
||||
var factory = (JsonConverterFactory)Activator.CreateInstance(converterType)!;
|
||||
return factory.CreateConverter(typeToConvert, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET9_0_OR_GREATER
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using ModelContextProtocol.Protocol;
|
||||
using ModelContextProtocol.Server;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
|
|
@ -34,14 +35,22 @@ public static partial class McpJsonUtilities
|
|||
/// Creates default options to use for MCP-related serialization.
|
||||
/// </summary>
|
||||
/// <returns>The configured options.</returns>
|
||||
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL3050:RequiresDynamicCode", Justification = "Converter is guarded by IsReflectionEnabledByDefault check.")]
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access", Justification = "Converter is guarded by IsReflectionEnabledByDefault check.")]
|
||||
private static JsonSerializerOptions CreateDefaultOptions()
|
||||
{
|
||||
// Copy the configuration from the source generated context.
|
||||
JsonSerializerOptions options = new(JsonContext.Default.Options);
|
||||
|
||||
// Chain with all supported types from MEAI
|
||||
// Chain with all supported types from MEAI.
|
||||
options.TypeInfoResolverChain.Add(AIJsonUtilities.DefaultOptions.TypeInfoResolver!);
|
||||
|
||||
// Add a converter for user-defined enums, if reflection is enabled by default.
|
||||
if (JsonSerializer.IsReflectionEnabledByDefault)
|
||||
{
|
||||
options.Converters.Add(new CustomizableJsonStringEnumConverter());
|
||||
}
|
||||
|
||||
options.MakeReadOnly();
|
||||
return options;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue