Universal.Common.Json 1.7.0

dotnet add package Universal.Common.Json --version 1.7.0
                    
NuGet\Install-Package Universal.Common.Json -Version 1.7.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Universal.Common.Json" Version="1.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Universal.Common.Json" Version="1.7.0" />
                    
Directory.Packages.props
<PackageReference Include="Universal.Common.Json" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Universal.Common.Json --version 1.7.0
                    
#r "nuget: Universal.Common.Json, 1.7.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Universal.Common.Json@1.7.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Universal.Common.Json&version=1.7.0
                    
Install as a Cake Addin
#tool nuget:?package=Universal.Common.Json&version=1.7.0
                    
Install as a Cake Tool

Universal.Common.Json

This package provides JSON Schema functionality according to the Draft 2020-12 specification, offering two distinct implementations for schema generation: JsonSchemaConverter and SelfReferencingJsonSchemaConverter. It includes functionality for direct schema manipulation, automatic schema generation from .NET types, and JSON validation against schemas.

Features

  • Full support for JSON Schema Draft 2020-12
  • Two schema converter implementations for different use cases
  • Serialization and deserialization using both Newtonsoft.Json and System.Text.Json
  • Extension data support for custom keywords
  • Automatic schema generation from .NET types
  • Best-guess schema inference from sample JSON data (no .NET type required)
  • Support for data annotation attributes
  • Comprehensive JSON validation against schemas
  • JSON token extraction based on schema matching

Schema Converters

JsonSchemaConverter

The standard converter is optimized for simple to moderately complex types. It's ideal when:

  • Your types don't have circular references
  • You need straightforward, flat schema generation
  • Performance is a priority
  • You're working with DTOs or simple data models
var converter = new JsonSchemaConverter();
JsonSchema schema = converter.Convert<Person>();

SelfReferencingJsonSchemaConverter

This specialized converter handles complex object graphs and self-referencing types. Use it when:

  • Your types contain circular references
  • You need to handle inheritance properly
  • You want schemas with shared definitions
  • You're working with complex domain models
var converter = new SelfReferencingJsonSchemaConverter();
JsonSchema schema = converter.Convert<ComplexType>();

Key differences:

  • Creates $ref references for complex types
  • Maintains a definitions section for reused types
  • Handles circular dependencies gracefully
  • May produce larger schemas due to type definitions

Schema Inference from Data

JsonSchemaInferrer produces a best-guess JsonSchema from sample JSON values rather than a .NET type. Reach for it when the shape is only known at runtime — heterogeneous data files, dynamic payloads, or anything not backed by a compile-time type. A common use case is feeding the inferred schema to a structured-output LLM API, where the schema constrains the model's response.

var inferrer = new JsonSchemaInferrer();

// From a JSON string...
JsonSchema schema = inferrer.Infer("[{ \"id\": 1, \"name\": \"fire\" }, { \"id\": 2, \"name\": \"ice\" }]");

// ...or from an already-parsed Newtonsoft JToken.
JsonSchema schemaFromToken = inferrer.Infer(JToken.Parse(json));

Inference is sample-driven — it can only describe what it sees. Pass as many representative samples as you have (e.g. a whole array/batch, not a single object) so optional fields, mixed types, and nullability are all observed. Across the supplied samples the inferrer:

  • Unions object properties and recurses into nested objects and arrays.
  • Merges every array element into a single items schema.
  • Maps leaves to string / integer / number / boolean, collapsing integer + number on the same field to number.
  • Represents a field seen as more than one type (or as null) using anyOf, e.g. a sometimes-null string becomes anyOf: [ { "type": "string" }, { "type": "null" } ].
  • Falls back to a default leaf type (string) for fields that are always null and for the items of always-empty arrays.

By default the output is ready for schema-constrained APIs that require closed objects: every object schema is emitted with additionalProperties: false and lists all observed keys as required.

Options

var inferrer = new JsonSchemaInferrer(new JsonSchemaInferrer.Options
{
    // Emit objects without `additionalProperties: false` (allows extra properties). Default: false.
    AdditionalProperties = false,

    // Require every observed key. When false, only keys present in ALL object samples
    // are required. Default: true.
    RequireAllProperties = true,

    // Type assigned to leaves whose type could not be inferred (always null, or empty arrays).
    // Default: "string".
    DefaultLeafType = "string",

    // When set, emitted as the root schema's `$schema` keyword. Default: null (omitted).
    SchemaVersion = "https://json-schema.org/draft/2020-12/schema",
});

Options propagate to nested schemas at any depth. Infer(string) throws ArgumentException for input that is null, empty, whitespace, or not well-formed JSON; for malformed JSON the underlying parser error is preserved on InnerException.

Usage Examples

Basic Type Conversion

// Using standard converter
var standardConverter = new JsonSchemaConverter();
var personSchema = standardConverter.Convert<Person>();

// Using self-referencing converter
var complexConverter = new SelfReferencingJsonSchemaConverter();
var orderSchema = complexConverter.Convert<Order>();

Handling Self-References

public class Employee
{
    [Required]
    public string Name { get; set; }

    [Required]
    public Employee Manager { get; set; }  // Self-reference

    public List<Employee> DirectReports { get; set; }
}

// Use SelfReferencingJsonSchemaConverter for this case
var converter = new SelfReferencingJsonSchemaConverter();
JsonSchema schema = converter.Convert<Employee>();

The resulting schema will include definitions to handle the self-reference:

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "manager": { "$ref": "#/definitions/Employee" },
    "directReports": {
      "type": "array",
      "items": { "$ref": "#/definitions/Employee" }
    }
  },
  "required": ["name", "manager"],
  "definitions": {
    "Employee": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "manager": { "$ref": "#/definitions/Employee" },
        "directReports": {
          "type": "array",
          "items": { "$ref": "#/definitions/Employee" }
        }
      },
      "required": ["name", "manager"]
    }
  }
}

Complex Inheritance Example

public abstract class Vehicle
{
    [Required]
    public string VIN { get; set; }

    public decimal Price { get; set; }
}

public class Car : Vehicle
{
    public int Doors { get; set; }
    public List<string> Features { get; set; }
}

public class Fleet
{
    public List<Vehicle> Vehicles { get; set; }
    public Car PrimaryCar { get; set; }
}

// Use SelfReferencingJsonSchemaConverter for inheritance
var converter = new SelfReferencingJsonSchemaConverter();
JsonSchema schema = converter.Convert<Fleet>();

Validation

Both schema types can be used with the validator:

var validator = new JsonSchemaValidator(schema);
var result = validator.Validate(jsonData);
if (!result.IsValid)
{
    foreach (string error in result.Errors)
    {
        Console.WriteLine($"Validation error: {error}");
    }
}

Supported Validation Attributes

Both converters support the following validation attributes:

  • [Required] - Marks properties as required in the schema
  • [StringLength] - Sets minimum and maximum string length
  • [MinLength], [MaxLength] - Sets collection size constraints
  • [Range] - Sets minimum and maximum numeric values
  • [RegularExpression] - Sets string patterns
  • [JsonPropertyName] - Customizes property names in the schema
  • [Description] - Adds property descriptions to the schema

Best Practices

  1. Choose the right converter:

    • Use JsonSchemaConverter for simple types and better performance
    • Use SelfReferencingJsonSchemaConverter for complex object graphs
  2. Consider schema size:

    • SelfReferencingJsonSchemaConverter produces larger schemas due to definitions
    • Use it only when necessary to handle circular references or complex inheritance
  3. Performance considerations:

    • JsonSchemaConverter is more performant for simple types
    • SelfReferencingJsonSchemaConverter has additional overhead for tracking references
  4. Type organization:

    • Group related types to make schemas more maintainable
    • Use inheritance thoughtfully to avoid overly complex schemas
  5. Validation attributes:

    • Apply validation attributes consistently across your models
    • Consider using custom attributes for special cases

Known Limitations

  • JsonSchemaConverter doesn't handle circular references
  • SelfReferencingJsonSchemaConverter may produce larger schemas
  • Both converters have limited support for dynamic types
  • Custom serialization attributes may not be fully supported
  • JsonSchemaInferrer only describes what the samples contain; shapes, fields, or value types absent from the data are not represented
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Universal.Common.Json:

Package Downloads
Universal.Anthropic.Client

Class library for interacting with the Anthropic REST API.

Universal.OpenAI.Client

Class library for interacting with OpenAI APIs.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.7.0 175 7/6/2026
1.6.0 407 6/19/2026
1.5.1 832 4/3/2026
1.5.0 2,659 11/13/2024
1.4.0 213 11/11/2024
1.3.0 195 11/6/2024
1.2.0 191 11/6/2024
1.1.0 180 10/30/2024
1.0.2 426 9/4/2024
1.0.1 237 9/4/2024

Fixed Guid/byte/sbyte/uint/ulong/ushort/DateTimeOffset/TimeSpan/Uri type mapping in both schema converters and added "format" annotations for them. Type/format mapping is now overridable via protected virtual members on a shared JsonSchemaConverterBase.