Skip to content

Commit

Permalink
Fixed ErrorObjectWriter
Browse files Browse the repository at this point in the history
  • Loading branch information
xavierjohn committed Dec 8, 2023
1 parent e662012 commit c4f0846
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 114 deletions.
224 changes: 110 additions & 114 deletions src/AspNetCore/WebApi/src/Asp.Versioning.Http/ErrorObjectWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

/// <summary>
Expand All @@ -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

/// <summary>
/// Represents an error object.
/// </summary>
public readonly struct ErrorObject
{
internal ErrorObject( ProblemDetails problemDetails ) =>
Error = new( problemDetails );

/// <summary>
/// Represents an error object.
/// Gets the top-level error.
/// </summary>
protected readonly struct ErrorObject
/// <value>The top-level error.</value>
[JsonPropertyName( "error" )]
public ErrorDetail Error { get; }
}

/// <summary>
/// Represents the error detail.
/// </summary>
public readonly struct ErrorDetail
{
private readonly ProblemDetails problemDetails;
private readonly InnerError? innerError;
private readonly Dictionary<string, object> extensions = [];

internal ErrorDetail( ProblemDetails problemDetails )
{
internal ErrorObject( ProblemDetails problemDetails ) =>
Error = new( problemDetails );

/// <summary>
/// Gets the top-level error.
/// </summary>
/// <value>The top-level error.</value>
[JsonPropertyName( "error" )]
public ErrorDetail Error { get; }
this.problemDetails = problemDetails;
innerError = string.IsNullOrEmpty( problemDetails.Detail ) ? default : new InnerError( problemDetails );
}

/// <summary>
/// Represents the error detail.
/// Gets or sets one of a server-defined set of error codes.
/// </summary>
protected readonly struct ErrorDetail
/// <value>A server-defined error code.</value>
[JsonPropertyName( "code" )]
[JsonIgnore( Condition = WhenWritingNull )]
public string? Code
{
private readonly ProblemDetails problemDetails;
private readonly InnerError? innerError;
private readonly Dictionary<string, object> extensions = [];

internal ErrorDetail( ProblemDetails problemDetails )
{
this.problemDetails = problemDetails;
innerError = string.IsNullOrEmpty( problemDetails.Detail ) ? default : new InnerError( problemDetails );
}

/// <summary>
/// Gets or sets one of a server-defined set of error codes.
/// </summary>
/// <value>A server-defined error code.</value>
[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;
}
}

/// <summary>
/// Gets or sets the error message.
/// </summary>
/// <value>A human-readable representation of the error.</value>
[JsonPropertyName( "message" )]
[JsonIgnore( Condition = WhenWritingNull )]
public string? Message
{
get => problemDetails.Title;
set => problemDetails.Title = value;
}

/// <summary>
/// Gets or sets the target of the error.
/// </summary>
/// <value>The error target of the error.</value>
[JsonPropertyName( "target" )]
[JsonIgnore( Condition = WhenWritingNull )]
public string? Target
{
get => problemDetails.Title;
set => problemDetails.Title = value;
}

/// <summary>
/// Gets an object containing more specific information than the current object about the error, if any.
/// </summary>
/// <value>The inner error or <c>null</c>.</value>
[JsonPropertyName( "innerError" )]
[JsonIgnore( Condition = WhenWritingNull )]
public InnerError? InnerError => innerError;

/// <summary>
/// Gets a collection of extension key/value pair members.
/// </summary>
/// <value>A collection of extension key/value pair members.</value>
[JsonExtensionData]
public IDictionary<string, object> Extensions => extensions;
}

/// <summary>
/// Represents an inner error.
/// Gets or sets the error message.
/// </summary>
protected readonly struct InnerError
/// <value>A human-readable representation of the error.</value>
[JsonPropertyName( "message" )]
[JsonIgnore( Condition = WhenWritingNull )]
public string? Message
{
private readonly ProblemDetails problemDetails;
private readonly Dictionary<string, object> extensions = [];

internal InnerError( ProblemDetails problemDetails ) =>
this.problemDetails = problemDetails;

/// <summary>
/// Gets or sets the inner error message.
/// </summary>
/// <value>The inner error message.</value>
[JsonPropertyName( "message" )]
[JsonIgnore( Condition = WhenWritingNull )]
public string? Message
{
get => problemDetails.Detail;
set => problemDetails.Detail = value;
}
get => problemDetails.Title;
set => problemDetails.Title = value;
}

/// <summary>
/// Gets a collection of extension key/value pair members.
/// </summary>
/// <value>A collection of extension key/value pair members.</value>
[JsonExtensionData]
public IDictionary<string, object> Extensions => extensions;
/// <summary>
/// Gets or sets the target of the error.
/// </summary>
/// <value>The error target of the error.</value>
[JsonPropertyName( "target" )]
[JsonIgnore( Condition = WhenWritingNull )]
public string? Target
{
get => problemDetails.Title;
set => problemDetails.Title = value;
}

/// <summary>
/// Gets an object containing more specific information than the current object about the error, if any.
/// </summary>
/// <value>The inner error or <c>null</c>.</value>
[JsonPropertyName( "innerError" )]
[JsonIgnore( Condition = WhenWritingNull )]
public InnerError? InnerError => innerError;

/// <summary>
/// Gets a collection of extension key/value pair members.
/// </summary>
/// <value>A collection of extension key/value pair members.</value>
[JsonExtensionData]
public IDictionary<string, object> Extensions => extensions;
}

#if NET8_0_OR_GREATER
[JsonSerializable( typeof( ErrorObjectWriter.ErrorObject ) )]
internal partial class SourceGenerationContext : JsonSerializerContext
/// <summary>
/// Represents an inner error.
/// </summary>
public struct InnerError
{
}
#endif
private readonly ProblemDetails problemDetails;
private readonly Dictionary<string, object> extensions = [];

internal InnerError( ProblemDetails problemDetails ) =>
this.problemDetails = problemDetails;

/// <summary>
/// Gets or sets the inner error message.
/// </summary>
/// <value>The inner error message.</value>
[JsonPropertyName( "message" )]
[JsonIgnore( Condition = WhenWritingNull )]
public string? Message
{
get => problemDetails.Detail;
set => problemDetails.Detail = value;
}

/// <summary>
/// Gets a collection of extension key/value pair members.
/// </summary>
/// <value>A collection of extension key/value pair members.</value>
[JsonExtensionData]
public IDictionary<string, object> Extensions => extensions;
}
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit c4f0846

Please sign in to comment.