From c4f08463dae4051e85b4869b36d295936ce8b287 Mon Sep 17 00:00:00 2001 From: Xavier Date: Thu, 7 Dec 2023 18:04:29 -0800 Subject: [PATCH] Fixed ErrorObjectWriter --- .../Asp.Versioning.Http/ErrorObjectWriter.cs | 224 +++++++++--------- .../SourceGenerationContext.cs | 13 + 2 files changed, 123 insertions(+), 114 deletions(-) create mode 100644 src/AspNetCore/WebApi/src/Asp.Versioning.Http/SourceGenerationContext.cs diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Http/ErrorObjectWriter.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.Http/ErrorObjectWriter.cs index 81670721..6513f5c9 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Http/ErrorObjectWriter.cs +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Http/ErrorObjectWriter.cs @@ -39,8 +39,11 @@ public virtual ValueTask WriteAsync( ProblemDetailsContext context ) var obj = new ErrorObject( context.ProblemDetails ); OnBeforeWrite( context, ref obj ); - - return new( response.WriteAsJsonAsync( obj ) ); +#if NET8_0_OR_GREATER + return new( response.WriteAsJsonAsync( obj, SourceGenerationContext.Default.ErrorObject ) ); +#else + return new( response.WriteAsJsonAsync( obj); +#endif } /// @@ -52,140 +55,133 @@ public virtual ValueTask WriteAsync( ProblemDetailsContext context ) protected virtual void OnBeforeWrite( ProblemDetailsContext context, ref ErrorObject errorObject ) { } +} #pragma warning disable CA1815 // Override equals and operator equals on value types +/// +/// Represents an error object. +/// +public readonly struct ErrorObject +{ + internal ErrorObject( ProblemDetails problemDetails ) => + Error = new( problemDetails ); + /// - /// Represents an error object. + /// Gets the top-level error. /// - protected readonly struct ErrorObject + /// The top-level error. + [JsonPropertyName( "error" )] + public ErrorDetail Error { get; } +} + +/// +/// Represents the error detail. +/// +public readonly struct ErrorDetail +{ + private readonly ProblemDetails problemDetails; + private readonly InnerError? innerError; + private readonly Dictionary extensions = []; + + internal ErrorDetail( ProblemDetails problemDetails ) { - internal ErrorObject( ProblemDetails problemDetails ) => - Error = new( problemDetails ); - - /// - /// Gets the top-level error. - /// - /// The top-level error. - [JsonPropertyName( "error" )] - public ErrorDetail Error { get; } + this.problemDetails = problemDetails; + innerError = string.IsNullOrEmpty( problemDetails.Detail ) ? default : new InnerError( problemDetails ); } /// - /// Represents the error detail. + /// Gets or sets one of a server-defined set of error codes. /// - protected readonly struct ErrorDetail + /// A server-defined error code. + [JsonPropertyName( "code" )] + [JsonIgnore( Condition = WhenWritingNull )] + public string? Code { - private readonly ProblemDetails problemDetails; - private readonly InnerError? innerError; - private readonly Dictionary extensions = []; - - internal ErrorDetail( ProblemDetails problemDetails ) - { - this.problemDetails = problemDetails; - innerError = string.IsNullOrEmpty( problemDetails.Detail ) ? default : new InnerError( problemDetails ); - } - - /// - /// Gets or sets one of a server-defined set of error codes. - /// - /// A server-defined error code. - [JsonPropertyName( "code" )] - [JsonIgnore( Condition = WhenWritingNull )] - public string? Code + get => problemDetails.Extensions.TryGetValue( "code", out var value ) && + value is string code ? + code : + default; + set { - get => problemDetails.Extensions.TryGetValue( "code", out var value ) && - value is string code ? - code : - default; - set + if ( value is null ) { - if ( value is null ) - { - problemDetails.Extensions.Remove( "code" ); - } - else - { - problemDetails.Extensions["code"] = value; - } + problemDetails.Extensions.Remove( "code" ); + } + else + { + problemDetails.Extensions["code"] = value; } } - - /// - /// Gets or sets the error message. - /// - /// A human-readable representation of the error. - [JsonPropertyName( "message" )] - [JsonIgnore( Condition = WhenWritingNull )] - public string? Message - { - get => problemDetails.Title; - set => problemDetails.Title = value; - } - - /// - /// Gets or sets the target of the error. - /// - /// The error target of the error. - [JsonPropertyName( "target" )] - [JsonIgnore( Condition = WhenWritingNull )] - public string? Target - { - get => problemDetails.Title; - set => problemDetails.Title = value; - } - - /// - /// Gets an object containing more specific information than the current object about the error, if any. - /// - /// The inner error or null. - [JsonPropertyName( "innerError" )] - [JsonIgnore( Condition = WhenWritingNull )] - public InnerError? InnerError => innerError; - - /// - /// Gets a collection of extension key/value pair members. - /// - /// A collection of extension key/value pair members. - [JsonExtensionData] - public IDictionary Extensions => extensions; } /// - /// Represents an inner error. + /// Gets or sets the error message. /// - protected readonly struct InnerError + /// A human-readable representation of the error. + [JsonPropertyName( "message" )] + [JsonIgnore( Condition = WhenWritingNull )] + public string? Message { - private readonly ProblemDetails problemDetails; - private readonly Dictionary extensions = []; - - internal InnerError( ProblemDetails problemDetails ) => - this.problemDetails = problemDetails; - - /// - /// Gets or sets the inner error message. - /// - /// The inner error message. - [JsonPropertyName( "message" )] - [JsonIgnore( Condition = WhenWritingNull )] - public string? Message - { - get => problemDetails.Detail; - set => problemDetails.Detail = value; - } + get => problemDetails.Title; + set => problemDetails.Title = value; + } - /// - /// Gets a collection of extension key/value pair members. - /// - /// A collection of extension key/value pair members. - [JsonExtensionData] - public IDictionary Extensions => extensions; + /// + /// Gets or sets the target of the error. + /// + /// The error target of the error. + [JsonPropertyName( "target" )] + [JsonIgnore( Condition = WhenWritingNull )] + public string? Target + { + get => problemDetails.Title; + set => problemDetails.Title = value; } + + /// + /// Gets an object containing more specific information than the current object about the error, if any. + /// + /// The inner error or null. + [JsonPropertyName( "innerError" )] + [JsonIgnore( Condition = WhenWritingNull )] + public InnerError? InnerError => innerError; + + /// + /// Gets a collection of extension key/value pair members. + /// + /// A collection of extension key/value pair members. + [JsonExtensionData] + public IDictionary Extensions => extensions; } -#if NET8_0_OR_GREATER -[JsonSerializable( typeof( ErrorObjectWriter.ErrorObject ) )] -internal partial class SourceGenerationContext : JsonSerializerContext +/// +/// Represents an inner error. +/// +public struct InnerError { -} -#endif \ No newline at end of file + private readonly ProblemDetails problemDetails; + private readonly Dictionary extensions = []; + + internal InnerError( ProblemDetails problemDetails ) => + this.problemDetails = problemDetails; + + /// + /// Gets or sets the inner error message. + /// + /// The inner error message. + [JsonPropertyName( "message" )] + [JsonIgnore( Condition = WhenWritingNull )] + public string? Message + { + get => problemDetails.Detail; + set => problemDetails.Detail = value; + } + + /// + /// Gets a collection of extension key/value pair members. + /// + /// A collection of extension key/value pair members. + [JsonExtensionData] + public IDictionary Extensions => extensions; +} \ No newline at end of file diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Http/SourceGenerationContext.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.Http/SourceGenerationContext.cs new file mode 100644 index 00000000..19c06ca8 --- /dev/null +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Http/SourceGenerationContext.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. + +namespace Asp.Versioning; +using System.Text.Json.Serialization; +#if NET8_0_OR_GREATER +[JsonSerializable( typeof( ErrorObject ) )] +[JsonSerializable( typeof( ErrorDetail ) )] +[JsonSerializable( typeof( InnerError ) )] +internal sealed partial class SourceGenerationContext : JsonSerializerContext +{ +} + +#endif \ No newline at end of file