Skip to content

Releases: ch-robinson/dotnet-avro

9.2.0

15 Sep 13:53
Compare
Choose a tag to compare

This minor release addresses a compatibility issue and fixes a serialization bug on Apple Silicon:

  • Chr.Avro.Confluent now targets Confluent.Kafka and Confluent.SchemaRegistry 1.9.3 to address an unexpected API change (#229, #230).

  • In previous versions, attempting to serialize negative Durations would silently write zero instead of throwing OverflowException when running on M1 processors (and possibly other ARM targets).

9.1.1

12 Aug 17:17
Compare
Choose a tag to compare

This patch release fixes a CLI issue introduced in 8.0.0:

9.1.0

11 Jul 20:53
Compare
Choose a tag to compare

This minor release adds support for an additional System.ComponentModel attribute:

  • When generating record schemas, Chr.Avro uses the [Description] attribute (if present) to derive descriptions for records and fields (#219, h/t @thomasbrueggemann). For example, given the following class:

    [Description("Represents an object in the graph.")]
    public class Node
    {
        [Description("The unique identifier of the node.")]
        public Guid Id { get; set; }
    }

    The schema builder would generate:

    {
        "name": "Node",
        "type": "record",
        "description": "Represents an object in the graph.",
        "fields": [{
            "name": "Id",
            "type": {
                "type": "string",
                "logicalType": "uuid"
            },
            "description": "The unique identifier of the node."
        }]
    }

9.0.0

27 Jun 19:43
Compare
Choose a tag to compare

This major release includes improvements to component model and data contract attribute usage.

Breaking changes

  • When generating schemas for decimal, Chr.Avro attempts to use the [Range] attribute to infer decimal precision and scale (#216). For example, given the following class:

    public class SensorReading
    {
        [Range(typeof(decimal), "0.000", "1.000", ConvertValueInInvariantCulture = true)]
        public decimal Value { get; set; }
    }

    The schema builder would generate:

    {
        "name": "SensorReading",
        "type": "record",
        "fields": [{
            "name": "Value",
            "type": {
                "type": "bytes",
                "logicalType": "decimal"
                "precision": 4,
                "scale": 3
            }
        }]
    }

    If precision and scale cannot be inferred, Chr.Avro will fall back to the defaults (29 and 14, respectively).

  • When serializing enum types to "string" schemas, Chr.Avro uses the [EnumMember] attribute value if one is set (#217). This matches the behavior of the schema builder for enum types when behavior is set to Symbolic (the default).

8.2.0

16 Jun 17:08
Compare
Choose a tag to compare

This minor release updates dependency versions:

  • Chr.Avro.Confluent targets Confluent.Kafka and Confluent.SchemaRegistry 1.9.x.

8.1.1

04 Mar 03:11
Compare
Choose a tag to compare

This patch release fixes an issue with data contract attribute handling:

  • Serdes for fields with [DataMember] and [EnumMember] attributes failed when the name or value was not set explicitly.

8.1.0

02 Mar 15:36
Compare
Choose a tag to compare

This minor release fixes a regression introduced in 8.0.0:

  • Support for [DataContract] and [NonSerialized] attributes was unintentionally removed when the type resolution framework was refactored away (#207). 8.1.0 reintroduces support to the schema and serde builders.

8.0.2

23 Feb 15:01
Compare
Choose a tag to compare

This patch release fixes an issue with default value representation:

  • Default values specified with the [DefaultValue] attribute or directly with ObjectDefaultValue<TValue> were unable to be written by the JSON schema writer (#199, #200, h/t @nicodeslandes).

8.0.1

21 Feb 15:06
Compare
Choose a tag to compare

This patch release fixes a regression that was introduced in 8.0.0:

  • Reading an array, map, or union schema containing a string schema with the "uuid" logical type caused the schema reader to throw (#195, h/t @woodlee).

8.0.0

15 Feb 19:05
Compare
Choose a tag to compare

8.0.0 is a major release that includes a number of breaking changes and significant new features. Some of these have been in the works for over a year, and we’re excited to finally make them available.

Breaking changes

  • The type resolution framework has been removed, and the schema builder and the serializer builders now reflect on .NET types directly.

    Before:

    var typeResolver = new ReflectionResolver(
        memberVisibility: BindingFlags.Public | BindingFlags.Instance,
        resolveReferenceTypesAsNullable: false,
        resolveUnderlyingEnumTypes: false);
    
    var schemaBuilder = new SchemaBuilder(
        temporalBehavior: TemporalBehavior.Iso8601,
        typeResolver: typeResolver);
    
    var serializerBuilder = new BinarySerializerBuilder(
        typeResolver: typeResolver);

    After:

    var schemaBuilder = new SchemaBuilder(
        memberVisibility: BindingFlags.Public | BindingFlags.Instance,
        nullableReferenceTypeBehavior: NullableReferenceTypeBehavior.None,
        enumBehavior: EnumBehavior.Symbolic,
        temporalBehavior: TemporalBehavior.Iso8601);
    
    var serializerBuilder = new BinarySerializerBuilder(
        memberVisibility: BindingFlags.Public | BindingFlags.Instance);

    As demonstrated above, the resolveReferenceTypesAsNullable parameter on the resolver has been replaced by the nullableReferenceTypeBehavior on the schema builder, which allows for more granular options. In the same vein, resolveUnderlyingEnumTypes on the resolver has been replaced by enumBehavior on the schema builder.

  • The schema builder now uses nullable reference type annotations to infer whether nullable schemas should be generated. In previous releases, reference type handing was all-or-nothing.

    Before:

    var typeResolver = new ReflectionResolver(
        resolveReferenceTypesAsNullable: false); // 😞
    
    var schemaBuilder = new SchemaBuilder(
        typeResolver: typeResolver);

    After:

    var schemaBuilder = new SchemaBuilder(
        nullableReferenceTypeBehavior: NullableReferenceTypeBehavior.Annotated); // 🤠

    Annotated becomes the default behavior in this release, so this is a breaking change. Applications may still use None or All to keep the behavior of previous versions. --nullable-references options on the CLI have been updated to match:

    # Create a schema from a type with nullable reference type analysis enabled (the default behavior):
    dotnet avro create --assembly bin/Debug/netstandard2.0/Example.dll --type Example.Type --nullable-references annotated
    
    # Generate a C# class with nullable reference type annotations enabled (not the default behavior):
    dotnet avro generate --registry-url http://registry.example --subject example-topic-value --nullable-references
  • An enum schema may be mapped to string (#161). Deserialization will always succeed; serialization will throw if the provided value does not exactly match a symbol on the schema. Similarly, Enum types may now be mapped to a "string" schema (#188). Serialization will always succeed; deserialization will throw if the serialized value does not exactly match an enumerator.

    With these changes, the --enums-as-ints option on the CLI has been replaced with --enum-behavior:

    # Create an "enum" schema (the default behavior):
    dotnet avro create --type System.DateTimeKind --enum-behavior symbolic
    
    # Create an "int" or "long" schema (the behavior for flag enums):
    dotnet avro create --type System.DateTimeKind --enum-behavior integral
    
    # Create a "string" schema (new):
    dotnet avro create --type System.DateTimeKind --enum-behavior nominal
  • Chr.Avro.Confluent now correctly implements the entirety of the Confluent wire format (#6). Previously, the serdes did not provide any special handling for top-level "bytes" schemas even though the wire format provides that only the data (no length information) should be serialized in that case. As this changes serialization behavior, applications that use "bytes" as a Kafka key or value schema should be upgraded carefully.

  • Binary serializers will now throw if a value provided for an "int" schema overflows a 32-bit signed integer (#120). Previously, 64-bit signed integers could be written.

  • The IBinaryCodec abstraction has been replaced by new BinaryReader and BinaryWriter objects that complement the System.Text.Json reader/writer:

    Before:

    var codec = new BinaryCodec();
    var input = Expression.Parameter(typeof(Stream));
    var readInteger = Expression
        .Lambda<Func<Stream, long>>(codec.ReadInteger(input), new[] { input })
        .Compile();
    var result = readInteger(stream);

    After:

    var reader = new BinaryReader(stream);
    var result = reader.ReadInteger();

    Most applications should be unaffected by this change.

New features

  • JSON encoding has been implemented (#2).

  • Default record field values are now supported (#7), enabling classes/structs to be serialized as records even if fields with defaults have no matching member.

  • Mapping IntPtr and UIntPtr to "int" and "long" schemas is now supported to enable serializing nint and nuint (#140).

  • All concrete collection types from System.Collections.ObjectModel are now supported (#97, #189).

Bug fixes

  • The schema builder will no longer fail to generate schemas for generic types (#128, #187). Previously, the backtick in a generic type name would cause an invalid record name to be generated.

With this release, we’ve enabled Source Link to improve the debugging experience. We’ve also aligned the codebase to the latest StyleCop analysis rules and C#/.NET versions to make it easier to contribute.