API Reference ResultJsonConverter - ulfbou/Zentient.Results GitHub Wiki

API Reference: ResultJsonConverter

1. ResultJsonConverter

1.1. Overview

  • Namespace: Zentient.Results
  • Type: JsonConverterFactory
  • Summary: A custom System.Text.Json.JsonConverterFactory that enables seamless and robust JSON serialization and deserialization of Result and Result<T> types. It ensures that these result objects are correctly represented in JSON payloads, exposing relevant properties while handling internal state.

1.2. Design Philosophy / Rationale

The Result and Result<T> structs have internal constructor logic and private fields (_errors, _messages) that standard System.Text.Json serialization might not handle optimally by default. ResultJsonConverter was created to provide explicit control over this process. Its design ensures:

  • Consistent Output: Predictable JSON structure for Result types, regardless of success or failure.
  • Completeness: All key public properties (IsSuccess, IsFailure, Status, Messages, Errors, Value) are correctly serialized.
  • Robust Deserialization: Handles various incoming JSON structures gracefully, providing fallbacks and error reporting if critical data (like Status) is missing.
  • Type Safety: Dynamically creates appropriate generic or non-generic converters based on the type being serialized/deserialized.

1.3. Inheritance / Implementation

  • Inherits from: System.Text.Json.Serialization.JsonConverterFactory

2. Methods

2.1. CanConvert(Type typeToConvert)

  • Signature: public override bool CanConvert(Type typeToConvert)
  • Summary: Determines whether this converter can convert the specified object type.
  • Parameters:
    • typeToConvert (Type): The type of the object to check.
  • Return Value: (bool): true if the converter can handle the typeToConvert (i.e., it's IResult, Result, IResult<T>, or Result<T>); otherwise, false.
  • Behavior: This method is used by System.Text.Json to identify if ResultJsonConverter is suitable for a given type during serialization or deserialization. It supports both the interface types (IResult, IResult<T>) and their concrete struct implementations (Result, Result<T>).

2.2. CreateConverter(Type typeToConvert, JsonSerializerOptions options)

  • Signature: public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
  • Summary: Creates a JsonConverter for the specified type.
  • Parameters:
    • typeToConvert (Type): The type of the object to convert.
    • options (JsonSerializerOptions): The serializer options being used.
  • Return Value: (JsonConverter?): A new JsonConverter instance appropriate for the typeToConvert, or null if the type cannot be converted.
  • Behavior: This factory method inspects typeToConvert. If it's a generic Result<T> or IResult<T>, it dynamically creates and returns an instance of ResultGenericJsonConverter<TValue>. If it's a non-generic Result or IResult, it returns an instance of ResultNonGenericJsonConverter. This ensures the correct, type-specific logic is applied.

3. Internal Converter Classes

The ResultJsonConverter factory manages two internal, private converter implementations:

3.1. ResultNonGenericJsonConverter

  • Role: Handles serialization and deserialization for Result (non-generic) and IResult.
  • Serialization (Write method): Explicitly writes IsSuccess, IsFailure, Status, Messages (if not empty), and Errors (if not empty) to the JSON output.
  • Deserialization (Read method): Reads the JSON object, attempting to parse status, messages, and errors. If status cannot be determined, it defaults to ResultStatuses.Error and generates a DeserializationError ErrorInfo. It then constructs a new Result instance using its internal constructor.

3.2. ResultGenericJsonConverter<TValue>

  • Role: Handles serialization and deserialization for Result<TValue> and IResult<TValue>.
  • Serialization (Write method): Explicitly writes IsSuccess, IsFailure, Status, Messages (if not empty), Errors (if not empty), and crucially, the Value property to the JSON output.
  • Deserialization (Read method): Reads the JSON object, attempting to parse value, status, messages, and errors. Similar to the non-generic converter, it handles missing status by defaulting to ResultStatuses.Error and adding a DeserializationError ErrorInfo. It then constructs a new Result<TValue> instance using its internal constructor.

7. Remarks / Additional Notes

  • Automatic Registration: To use this converter, you typically register it with your JsonSerializerOptions:

    var options = new JsonSerializerOptions
    {
        WriteIndented = true,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    };
    options.Converters.Add(new ResultJsonConverter());
    
    // Then use JsonSerializer.Serialize/Deserialize with these options
  • Circular Reference Prevention: The internal converters create new JsonSerializerOptions instances that remove themselves from the converters list (_options.Converters.Remove(this)). This is a standard pattern to prevent infinite recursion when a converter needs to call the default serializer for its own properties (e.g., when serializing ErrorInfo objects within the Errors collection).

  • RFC 9457 Alignment: The enhanced serialization logic, particularly for ErrorInfo's Detail and Extensions, aids in generating JSON payloads that are more compliant with RFC 9457 (Problem Details for HTTP APIs) when Result types are used for API responses.


Last Updated: 2025-06-07 Version: 0.3.0

⚠️ **GitHub.com Fallback** ⚠️