From d76d6998d0c4fe8aaea5b4131dc2b8b6b8859229 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sun, 6 Oct 2024 21:32:34 +0100 Subject: [PATCH 1/2] Housekeeping fix some of the code analyser warnings --- .../InterfaceStubGenerator.cs | 19 ++++++++++++++++--- Refit/ApiException.cs | 11 ++++++++++- Refit/CamelCaseUrlParameterKeyFormatter.cs | 5 +++++ Refit/PushStreamContent.cs | 7 ++++--- Refit/RestMethodInfo.cs | 12 ++++++------ 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs index ef31b0f15..0b627f162 100644 --- a/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs +++ b/InterfaceStubGenerator.Shared/InterfaceStubGenerator.cs @@ -77,6 +77,15 @@ public void GenerateInterfaceStubs( ImmutableArray candidateInterfaces ) { + if (compilation == null) + throw new ArgumentNullException(nameof(compilation)); + + if (reportDiagnostic == null) + throw new ArgumentNullException(nameof(reportDiagnostic)); + + if (addSource == null) + throw new ArgumentNullException(nameof(addSource)); + refitInternalNamespace = $"{refitInternalNamespace ?? string.Empty}RefitInternalGenerated"; @@ -131,7 +140,11 @@ ImmutableArray candidateInterfaces m => m.ContainingType, SymbolEqualityComparer.Default ) - .ToDictionary(g => g.Key, v => v.ToList()); + .ToDictionary, INamedTypeSymbol, List>( + g => g.Key, + v => [.. v], + SymbolEqualityComparer.Default + ); // Look through the candidate interfaces var interfaceSymbols = new List(); @@ -850,9 +863,9 @@ public void Initialize(GeneratorInitializationContext context) class SyntaxReceiver : ISyntaxReceiver { - public List CandidateMethods { get; } = new(); + public List CandidateMethods { get; } = []; - public List CandidateInterfaces { get; } = new(); + public List CandidateInterfaces { get; } = []; public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { diff --git a/Refit/ApiException.cs b/Refit/ApiException.cs index 7959e7df3..ccf432c95 100644 --- a/Refit/ApiException.cs +++ b/Refit/ApiException.cs @@ -9,7 +9,9 @@ namespace Refit /// Represents an error that occured while sending an API request. /// [Serializable] +#pragma warning disable CA1032 // Implement standard exception constructors public class ApiException : Exception +#pragma warning restore CA1032 // Implement standard exception constructors { /// /// HTTP response status code. @@ -162,7 +164,12 @@ public static Task Create( ) #pragma warning restore VSTHRD200 // Use "Async" suffix for async methods { - var exceptionMessage = CreateMessage(response.StatusCode, response.ReasonPhrase); + if (response?.IsSuccessStatusCode == true) + { + throw new ArgumentException("Response is successful, cannot create an ApiException.", nameof(response)); + } + + var exceptionMessage = CreateMessage(response!.StatusCode, response.ReasonPhrase); return Create( exceptionMessage, message, @@ -211,6 +218,7 @@ public static async Task Create( return exception; } +#pragma warning disable CA1031 // Do not catch general exception types try { exception.ContentHeaders = response.Content.Headers; @@ -235,6 +243,7 @@ public static async Task Create( // so we want to make sure we don't throw another one // that hides the real error. } +#pragma warning restore CA1031 // Do not catch general exception types return exception; } diff --git a/Refit/CamelCaseUrlParameterKeyFormatter.cs b/Refit/CamelCaseUrlParameterKeyFormatter.cs index 9396c91e1..c59410477 100644 --- a/Refit/CamelCaseUrlParameterKeyFormatter.cs +++ b/Refit/CamelCaseUrlParameterKeyFormatter.cs @@ -5,6 +5,11 @@ /// public class CamelCaseUrlParameterKeyFormatter : IUrlParameterKeyFormatter { + /// + /// Formats the specified key. + /// + /// The key. + /// public string Format(string key) { if (string.IsNullOrEmpty(key) || !char.IsUpper(key[0])) diff --git a/Refit/PushStreamContent.cs b/Refit/PushStreamContent.cs index e698df717..4fd4e2fb8 100644 --- a/Refit/PushStreamContent.cs +++ b/Refit/PushStreamContent.cs @@ -135,11 +135,11 @@ protected override async Task SerializeToStreamAsync( { var serializeToStreamTask = new TaskCompletionSource(); - Stream wrappedStream = new CompleteTaskOnCloseStream(stream, serializeToStreamTask); - await onStreamAvailable(wrappedStream, this, context); + using Stream wrappedStream = new CompleteTaskOnCloseStream(stream, serializeToStreamTask); + await onStreamAvailable(wrappedStream, this, context).ConfigureAwait(false); // wait for wrappedStream.Close/Dispose to get called. - await serializeToStreamTask.Task; + await serializeToStreamTask.Task.ConfigureAwait(false); } /// @@ -170,6 +170,7 @@ TaskCompletionSource serializeToStreamTask ?? throw new ArgumentNullException(nameof(serializeToStreamTask)); } + [SuppressMessage("Usage", "CA2215:Dispose methods should call base class dispose", Justification = "We don't dispose the underlying stream because we don't own it. Dispose in this case just signifies that the user's action is finished.")] protected override void Dispose(bool disposing) { // We don't dispose the underlying stream because we don't own it. Dispose in this case just signifies diff --git a/Refit/RestMethodInfo.cs b/Refit/RestMethodInfo.cs index 901dfc338..168f182b3 100644 --- a/Refit/RestMethodInfo.cs +++ b/Refit/RestMethodInfo.cs @@ -121,7 +121,7 @@ public RestMethodInfoInternal( if (attachmentName == null) continue; - attachmentDict ??= new Dictionary>(); + attachmentDict ??= []; attachmentDict[i] = Tuple.Create( attachmentName, GetUrlNameForParameter(ParameterInfoArray[i]) @@ -146,7 +146,7 @@ public RestMethodInfoInternal( continue; } - queryDict ??= new Dictionary(); + queryDict ??= []; queryDict.Add(i, GetUrlNameForParameter(ParameterInfoArray[i])); } @@ -558,12 +558,12 @@ HttpMethod method .DeclaringType.GetInterfaces() .SelectMany(i => i.GetTypeInfo().GetCustomAttributes(true)) .Reverse() - : Array.Empty(); + : []; var declaringTypeAttributes = methodInfo.DeclaringType != null ? methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true) - : Array.Empty(); + : []; // Headers set on the declaring type have to come first, // so headers set on the method can replace them. Switching @@ -581,7 +581,7 @@ HttpMethod method if (string.IsNullOrWhiteSpace(header)) continue; - ret ??= new Dictionary(); + ret ??= []; // NB: Silverlight doesn't have an overload for String.Split() // with a count parameter, but header values can contain @@ -609,7 +609,7 @@ static Dictionary BuildHeaderParameterMap(ParameterInfo[] parameter if (!string.IsNullOrWhiteSpace(header)) { - ret ??= new Dictionary(); + ret ??= []; ret[i] = header.Trim(); } } From ce31179c4601f7b6d8c2a3b2baa1c2b80cda86b5 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sun, 6 Oct 2024 22:15:35 +0100 Subject: [PATCH 2/2] Housekeeping Fix Code warnings --- Directory.Build.props | 1 + .../Refit.GeneratorTests.csproj | 13 +-- .../AuthenticatedClientHandlerTests.cs | 22 ++--- Refit.Xml/XmlContentSerializer.cs | 75 ++++++++++++++++- Refit/FormValueMultimap.cs | 5 +- Refit/RefitSettings.cs | 13 +++ Refit/RestMethodInfo.cs | 2 +- Refit/RestMethodParameterInfo.cs | 81 ++++++++++++++++++- Refit/RestService.cs | 3 + Refit/SystemTextJsonContentSerializer.cs | 52 +++++++++--- 10 files changed, 229 insertions(+), 38 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index ea3793a0b..1f6c482e5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,6 +24,7 @@ $(MSBuildThisFileDirectory)buildtask.snk true net462;netstandard2.0;net6.0;net8.0 + IDE0040;CA1054;CA1510 diff --git a/Refit.GeneratorTests/Refit.GeneratorTests.csproj b/Refit.GeneratorTests/Refit.GeneratorTests.csproj index 675e4f389..b8502a972 100644 --- a/Refit.GeneratorTests/Refit.GeneratorTests.csproj +++ b/Refit.GeneratorTests/Refit.GeneratorTests.csproj @@ -13,11 +13,12 @@ - - - - - + + + + + + @@ -37,7 +38,7 @@ %(RecursiveDir)\resources\%(Filename)%(Extension) Always - + diff --git a/Refit.Tests/AuthenticatedClientHandlerTests.cs b/Refit.Tests/AuthenticatedClientHandlerTests.cs index 98f02379e..185c0eebd 100644 --- a/Refit.Tests/AuthenticatedClientHandlerTests.cs +++ b/Refit.Tests/AuthenticatedClientHandlerTests.cs @@ -80,7 +80,7 @@ public void NullTokenGetterThrows() } [Fact] - public async void AuthenticatedHandlerIgnoresUnAuth() + public async Task AuthenticatedHandlerIgnoresUnAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() @@ -104,7 +104,7 @@ public async void AuthenticatedHandlerIgnoresUnAuth() } [Fact] - public async void AuthenticatedHandlerUsesAuth() + public async Task AuthenticatedHandlerUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() @@ -128,7 +128,7 @@ public async void AuthenticatedHandlerUsesAuth() } [Fact] - public async void AuthenticatedHandlerWithParamUsesAuth() + public async Task AuthenticatedHandlerWithParamUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() @@ -152,7 +152,7 @@ public async void AuthenticatedHandlerWithParamUsesAuth() } [Fact] - public async void AuthenticatedHandlerWithTokenInParameterUsesAuth() + public async Task AuthenticatedHandlerWithTokenInParameterUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; @@ -172,7 +172,7 @@ public async void AuthenticatedHandlerWithTokenInParameterUsesAuth() } [Fact] - public async void AuthenticatedHandlerWithTokenInHeaderCollectionUsesAuth() + public async Task AuthenticatedHandlerWithTokenInHeaderCollectionUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; @@ -198,7 +198,7 @@ public async void AuthenticatedHandlerWithTokenInHeaderCollectionUsesAuth() } [Fact] - public async void AuthenticatedHandlerWithAuthorizeAttributeAndHeaderCollectionUsesAuth() + public async Task AuthenticatedHandlerWithAuthorizeAttributeAndHeaderCollectionUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; @@ -234,7 +234,7 @@ public async void AuthenticatedHandlerWithAuthorizeAttributeAndHeaderCollectionU } [Fact] - public async void AuthenticatedHandlerWithDuplicatedAuthorizationHeaderUsesAuth() + public async Task AuthenticatedHandlerWithDuplicatedAuthorizationHeaderUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; @@ -271,7 +271,7 @@ public async void AuthenticatedHandlerWithDuplicatedAuthorizationHeaderUsesAuth( } [Fact] - public async void AuthenticatedHandlerPostTokenInHeaderCollectionUsesAuth() + public async Task AuthenticatedHandlerPostTokenInHeaderCollectionUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; @@ -304,7 +304,7 @@ public async void AuthenticatedHandlerPostTokenInHeaderCollectionUsesAuth() } [Fact] - public async void AuthentictedMethodFromBaseClassWithHeadersAttributeUsesAuth() + public async Task AuthentictedMethodFromBaseClassWithHeadersAttributeUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() @@ -331,7 +331,7 @@ public async void AuthentictedMethodFromBaseClassWithHeadersAttributeUsesAuth() } [Fact] - public async void AuthentictedMethodFromInheritedClassWithHeadersAttributeUsesAuth() + public async Task AuthentictedMethodFromInheritedClassWithHeadersAttributeUsesAuth() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() @@ -358,7 +358,7 @@ public async void AuthentictedMethodFromInheritedClassWithHeadersAttributeUsesAu } [Fact] - public async void AuthentictedMethodFromInheritedClassWithHeadersAttributeUsesAuth_WithCRLFCheck() + public async Task AuthentictedMethodFromInheritedClassWithHeadersAttributeUsesAuth_WithCRLFCheck() { var handler = new MockHttpMessageHandler(); var settings = new RefitSettings() diff --git a/Refit.Xml/XmlContentSerializer.cs b/Refit.Xml/XmlContentSerializer.cs index ad15ca6c2..3f3d4c3f2 100644 --- a/Refit.Xml/XmlContentSerializer.cs +++ b/Refit.Xml/XmlContentSerializer.cs @@ -20,9 +20,17 @@ public class XmlContentSerializer : IHttpContentSerializer readonly XmlContentSerializerSettings settings; readonly ConcurrentDictionary serializerCache = new(); + /// + /// Initializes a new instance of the class. + /// public XmlContentSerializer() : this(new XmlContentSerializerSettings()) { } + /// + /// Initializes a new instance of the class. + /// + /// The settings. + /// settings public XmlContentSerializer(XmlContentSerializerSettings settings) { this.settings = settings ?? throw new ArgumentNullException(nameof(settings)); @@ -76,7 +84,7 @@ public HttpContent ToHttpContent(T item) new XmlSerializer( t, settings.XmlAttributeOverrides, - Array.Empty(), + [], null, settings.XmlDefaultNamespace ) @@ -110,21 +118,40 @@ await content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false) } } + /// + /// XmlReaderWriterSettings. + /// public class XmlReaderWriterSettings { XmlReaderSettings readerSettings; XmlWriterSettings writerSettings; + /// + /// Initializes a new instance of the class. + /// public XmlReaderWriterSettings() : this(new XmlReaderSettings(), new XmlWriterSettings()) { } + /// + /// Initializes a new instance of the class. + /// + /// The reader settings. public XmlReaderWriterSettings(XmlReaderSettings readerSettings) : this(readerSettings, new XmlWriterSettings()) { } + /// + /// Initializes a new instance of the class. + /// + /// The writer settings. public XmlReaderWriterSettings(XmlWriterSettings writerSettings) : this(new XmlReaderSettings(), writerSettings) { } #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + /// + /// Initializes a new instance of the class. + /// + /// The reader settings. + /// The writer settings. public XmlReaderWriterSettings( XmlReaderSettings readerSettings, XmlWriterSettings writerSettings @@ -135,6 +162,13 @@ XmlWriterSettings writerSettings WriterSettings = writerSettings; } + /// + /// Gets or sets the reader settings. + /// + /// + /// The reader settings. + /// + /// value public XmlReaderSettings ReaderSettings { get @@ -145,6 +179,13 @@ public XmlReaderSettings ReaderSettings set => readerSettings = value ?? throw new ArgumentNullException(nameof(value)); } + /// + /// Gets or sets the writer settings. + /// + /// + /// The writer settings. + /// + /// value public XmlWriterSettings WriterSettings { get @@ -167,25 +208,55 @@ void ApplyOverrideSettings() } } + /// + /// XmlContentSerializerSettings. + /// public class XmlContentSerializerSettings { + /// + /// Initializes a new instance of the class. + /// public XmlContentSerializerSettings() { XmlDefaultNamespace = null; XmlReaderWriterSettings = new XmlReaderWriterSettings(); XmlNamespaces = new XmlSerializerNamespaces( - new[] { new XmlQualifiedName(string.Empty, string.Empty), } + [new XmlQualifiedName(string.Empty, string.Empty),] ); XmlAttributeOverrides = new XmlAttributeOverrides(); } + /// + /// Gets or sets the XML default namespace. + /// + /// + /// The XML default namespace. + /// public string? XmlDefaultNamespace { get; set; } + /// + /// Gets or sets the XML reader writer settings. + /// + /// + /// The XML reader writer settings. + /// public XmlReaderWriterSettings XmlReaderWriterSettings { get; set; } + /// + /// Gets or sets the XML namespaces. + /// + /// + /// The XML namespaces. + /// public XmlSerializerNamespaces XmlNamespaces { get; set; } + /// + /// Gets or sets the XML attribute overrides. + /// + /// + /// The XML attribute overrides. + /// public XmlAttributeOverrides XmlAttributeOverrides { get; set; } } } diff --git a/Refit/FormValueMultimap.cs b/Refit/FormValueMultimap.cs index 291fb3567..72092231c 100644 --- a/Refit/FormValueMultimap.cs +++ b/Refit/FormValueMultimap.cs @@ -11,10 +11,9 @@ namespace Refit /// same or different values. class FormValueMultimap : IEnumerable> { - static readonly Dictionary PropertyCache = new(); + static readonly Dictionary PropertyCache = []; - readonly IList> formEntries = - new List>(); + readonly IList> formEntries = []; readonly IHttpContentSerializer contentSerializer; diff --git a/Refit/RefitSettings.cs b/Refit/RefitSettings.cs index 8c3d90f46..38cdeda70 100644 --- a/Refit/RefitSettings.cs +++ b/Refit/RefitSettings.cs @@ -136,8 +136,21 @@ public Func< public Dictionary? HttpRequestMessageOptions { get; set; } #if NET6_0_OR_GREATER + + /// + /// Gets or sets the version. + /// + /// + /// The version. + /// public Version Version { get; set; } = HttpVersion.Version11; + /// + /// Gets or sets the version policy. + /// + /// + /// The version policy. + /// public System.Net.Http.HttpVersionPolicy VersionPolicy { get; set; } = HttpVersionPolicy.RequestVersionOrLower; #endif } diff --git a/Refit/RestMethodInfo.cs b/Refit/RestMethodInfo.cs index 168f182b3..4e8eb095a 100644 --- a/Refit/RestMethodInfo.cs +++ b/Refit/RestMethodInfo.cs @@ -261,7 +261,7 @@ static void VerifyUrlPathIsSane(string relativePath) ); // CRLF injection protection - if (relativePath.Contains("\r") || relativePath.Contains("\n")) + if (relativePath.Contains('\r') || relativePath.Contains('\n')) throw new ArgumentException( $"URL path {relativePath} must not contain CR or LF characters" ); diff --git a/Refit/RestMethodParameterInfo.cs b/Refit/RestMethodParameterInfo.cs index c5542bca4..dd748e85f 100644 --- a/Refit/RestMethodParameterInfo.cs +++ b/Refit/RestMethodParameterInfo.cs @@ -2,43 +2,120 @@ namespace Refit { + /// + /// RestMethodParameterInfo. + /// public class RestMethodParameterInfo { + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// The parameter information. public RestMethodParameterInfo(string name, ParameterInfo parameterInfo) { Name = name; ParameterInfo = parameterInfo; } + /// + /// Initializes a new instance of the class. + /// + /// if set to true [is object property parameter]. + /// The parameter information. public RestMethodParameterInfo(bool isObjectPropertyParameter, ParameterInfo parameterInfo) { IsObjectPropertyParameter = isObjectPropertyParameter; ParameterInfo = parameterInfo; } + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// public string? Name { get; set; } + + /// + /// Gets or sets the parameter information. + /// + /// + /// The parameter information. + /// public ParameterInfo ParameterInfo { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is object property parameter. + /// + /// + /// true if this instance is object property parameter; otherwise, false. + /// public bool IsObjectPropertyParameter { get; set; } - public List ParameterProperties { get; set; } = - new List(); + + /// + /// Gets or sets the parameter properties. + /// + /// + /// The parameter properties. + /// + public List ParameterProperties { get; set; } = []; + + /// + /// Gets or sets the type. + /// + /// + /// The type. + /// public ParameterType Type { get; set; } = ParameterType.Normal; } + /// + /// RestMethodParameterProperty. + /// public class RestMethodParameterProperty { + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// The property information. public RestMethodParameterProperty(string name, PropertyInfo propertyInfo) { Name = name; PropertyInfo = propertyInfo; } + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// public string Name { get; set; } + + /// + /// Gets or sets the property information. + /// + /// + /// The property information. + /// public PropertyInfo PropertyInfo { get; set; } } + /// + /// ParameterType. + /// public enum ParameterType { + /// + /// The normal + /// Normal, + + /// + /// The round tripping + /// RoundTripping } } diff --git a/Refit/RestService.cs b/Refit/RestService.cs index 0cf2571d8..c37c6ca05 100644 --- a/Refit/RestService.cs +++ b/Refit/RestService.cs @@ -3,6 +3,9 @@ namespace Refit { + /// + /// RestService. + /// public static class RestService { static readonly ConcurrentDictionary TypeMapping = new(); diff --git a/Refit/SystemTextJsonContentSerializer.cs b/Refit/SystemTextJsonContentSerializer.cs index b3f17a8b7..20e1f18c3 100644 --- a/Refit/SystemTextJsonContentSerializer.cs +++ b/Refit/SystemTextJsonContentSerializer.cs @@ -51,26 +51,34 @@ public HttpContent ToHttpContent(T item) return item; } - public string? GetFieldNameForProperty(PropertyInfo propertyInfo) + /// + /// Calculates what the field name should be for the given property. This may be affected by custom attributes the serializer understands + /// + /// A PropertyInfo object. + /// + /// The calculated field name. + /// + /// propertyInfo + public string? GetFieldNameForProperty(PropertyInfo propertyInfo) => propertyInfo switch { - if (propertyInfo is null) - throw new ArgumentNullException(nameof(propertyInfo)); - - return propertyInfo - .GetCustomAttributes(true) - .Select(a => a.Name) - .FirstOrDefault(); - } + null => throw new ArgumentNullException(nameof(propertyInfo)), + _ => propertyInfo + .GetCustomAttributes(true) + .Select(a => a.Name) + .FirstOrDefault() + }; /// /// Creates new and fills it with default parameters /// public static JsonSerializerOptions GetDefaultJsonSerializerOptions() { - var jsonSerializerOptions = new JsonSerializerOptions(); // Default to case insensitive property name matching as that's likely the behavior most users expect - jsonSerializerOptions.PropertyNameCaseInsensitive = true; - jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + var jsonSerializerOptions = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; jsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); jsonSerializerOptions.Converters.Add( new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) @@ -80,9 +88,21 @@ public static JsonSerializerOptions GetDefaultJsonSerializerOptions() } } - // From https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0#deserialize-inferred-types-to-object-properties + /// + /// ObjectToInferredTypesConverter. + /// From https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0#deserialize-inferred-types-to-object-properties + /// public class ObjectToInferredTypesConverter : JsonConverter { + /// + /// Reads and converts the JSON to type . + /// + /// The reader. + /// The type to convert. + /// An object that specifies serialization options to use. + /// + /// The converted value. + /// public override object? Read( ref Utf8JsonReader reader, Type typeToConvert, @@ -99,6 +119,12 @@ JsonTokenType.String when reader.TryGetDateTime(out var datetime) => datetime, _ => JsonDocument.ParseValue(ref reader).RootElement.Clone() }; + /// + /// Writes the specified writer. + /// + /// The writer. + /// The object to write. + /// The options. public override void Write( Utf8JsonWriter writer, object objectToWrite,