### Install Nerdbank.MessagePack via NuGet Source: https://context7.com/aarnott/nerdbank.messagepack/llms.txt Install the core library or integration packages for SignalR and ASP.NET Core MVC using NuGet. Ensure C# language version 14 is set for optimal experience. ```xml ``` ```xml 14 ``` -------------------------------- ### SignalR Hub Implementation Example Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/signalr.md Example implementation of a SignalR Hub. Hubs function identically regardless of the underlying protocol (JSON or MessagePack). ```csharp public class ChatHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } } ``` -------------------------------- ### Custom BinaryData Converter Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/custom-converters.md This example demonstrates a fully defined converter for System.BinaryData. It serializes BinaryData by writing its underlying byte array. ```csharp using System; using System.Buffers; using Nerdbank.MessagePack; public class BinaryDataConverter : IMessagePackConverter { public void Serialize(ref MessagePackWriter writer, BinaryData value, MessagePackSerializerOptions options) { // Write the underlying byte array of BinaryData writer.Write(value.ToArray()); } public BinaryData Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { // Read the byte array and construct BinaryData return BinaryData. fromBytes(reader.ReadBytes().ToArray()); } } ``` -------------------------------- ### Example Violation of UseComparerAttribute Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack072.md This code demonstrates a violation where the UseComparerAttribute is not specifying a compatible comparer. This will be flagged by the analyzer. ```csharp using System.Collections.Generic; using Nerdbank.MessagePack; public class Defective { [UseComparer(typeof(int))] // Error: int does not implement IComparer or IEqualityComparer public List Strings { get; set; } } ``` -------------------------------- ### Example violation: Missing GetJsonSchema Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack032.md This converter for MyType serializes to a single integer but does not document this schema. ```csharp public class MyTypeConverter : MessagePackConverter { public override MyType Read(ref MessagePackReader reader, SerializationContext context) { int a = reader.ReadInt32(); return new MyType(a); } public override void Write(ref MessagePackWriter writer, in MyType value, SerializationContext context) { writer.Write(value.A); } } ``` -------------------------------- ### Complete Sample with TypeShapeAttribute Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/surrogate-types.md This C# code demonstrates the complete setup, including the original type, its surrogate, the marshaler, and the `TypeShapeAttribute` applied to the original type to reference the marshaler. ```csharp [TypeShape(Marshaler = typeof(OriginalTypeMarshaler))] public class OriginalType { private int _privateField; private string _anotherPrivateField; public OriginalType(int privateField, string anotherPrivateField) { _privateField = privateField; _anotherPrivateField = anotherPrivateField; } // Public properties for demonstration, but fields are private public int PublicFieldForDemo { get => _privateField; } public string PublicStringForDemo { get => _anotherPrivateField; } } public record struct OriginalTypeSurrogate(int PrivateField, string AnotherPrivateField); public class OriginalTypeMarshaler : IMarshaler { public OriginalTypeSurrogate? Marshal(OriginalType? value) { if (value == null) { return null; } // Accessing private fields via nested class return new OriginalTypeSurrogate(value._privateField, value._anotherPrivateField); } public OriginalType Unmarshal(OriginalTypeSurrogate? value) { if (value == null) { // This case should ideally not happen if OriginalType is not nullable // and the marshaler is correctly used. throw new InvalidOperationException("Cannot unmarshal null surrogate to a non-nullable OriginalType."); } // Creating a new instance of OriginalType using its constructor return new OriginalType(value.Value.PrivateField, value.Value.AnotherPrivateField); } } ``` -------------------------------- ### Defective Async Converter Implementation Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack035.md This example shows a defective implementation where a MessagePackStreamingReader is created and then switched to a MessagePackReader, but neither reader is returned, leading to a bug. ```csharp public override async ValueTask ReadAsync(MessagePackReader reader, CancellationToken cancellationToken) { var streamingReader = MessagePackAsyncReader.CreateStreamingReader(reader); var bufferedReader = MessagePackAsyncReader.CreateBufferedReader(reader); // Bug: Neither reader is returned. return default; } ``` -------------------------------- ### Serialize with Key and Gaps Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/customizing-serialization.md Demonstrates serializing an object with a large gap between assigned indexes, illustrating how MessagePack handles sparse data. This example assumes SerializeDefaultValues is set to Never. ```csharp public class WithKeyAndGaps { public string OneProperty { get; set; } = "value1"; public string AnotherProperty { get; set; } = null; } ``` -------------------------------- ### Corrected Async Converter Implementation Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack034.md This corrected example shows the proper way to handle MessagePackWriter. All statements using the writer must occur before it is returned. If the writer is needed after an await, create a new one. ```csharp public override async ValueTask WriteAsync(TBufferWriter writer, T value, CancellationToken cancellationToken) where TBufferWriter : IBufferWriter { await base.WriteAsync(writer, value, cancellationToken); // Fix: All statements using the writer occur before returning it. MessagePackAsyncWriter.ReturnWriter(writer); // If the sync writer must be used after the await expression as well, you may create a new sync writer after the await statement. // writer.Write(123); } ``` -------------------------------- ### Resolution: Return Reader After Use Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack036.md This example shows the correct way to handle MessagePack readers. The MessagePackAsyncReader.ReturnReader call is moved to a point after the reader is no longer needed, preventing reuse issues. ```csharp internal class Fix : IMessagePackSerializationActivator { public async ValueTask ActivateAsync(MessagePackSerializerOptions options, Type type, CancellationToken cancellationToken) { await using var reader = options.ReaderPool.Rent(cancellationToken); await reader.ReadAsync(cancellationToken); var result = await reader.ReadAsync(cancellationToken); // Use reader before returning options.ReaderPool.ReturnReader(reader); return result; } } ``` -------------------------------- ### Defective Async Converter Implementation Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack034.md This example demonstrates a violation where MessagePackWriter is reused after being returned. Ensure all writer operations complete before returning the writer. ```csharp public override async ValueTask WriteAsync(TBufferWriter writer, T value, CancellationToken cancellationToken) where TBufferWriter : IBufferWriter { await base.WriteAsync(writer, value, cancellationToken); // Defect: Reusing writer after returning it. MessagePackAsyncWriter.ReturnWriter(writer); writer.Write(123); } ``` -------------------------------- ### Stateful Converter with SerializationContext Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/custom-converters.md This C# example shows how a custom converter can access state from the SerializationContext instead of using fields, enabling concurrent use with different state values and avoiding serializer instantiation costs. ```csharp public sealed class StatefulConverter : MessagePackConverter { public override void Write(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options) { // Retrieve state from the context var connectionId = options.Context.Items.GetValueOrDefault("connectionId"); // ... use connectionId for serialization logic ... MessagePackSerializer.Default.Serialize(ref writer, value, options); } public override T Read(ref MessagePackReader reader, MessagePackSerializerOptions options) { // Retrieve state from the context var connectionId = options.Context.Items.GetValueOrDefault("connectionId"); // ... use connectionId for deserialization logic ... return MessagePackSerializer.Default.Deserialize(ref reader, options); } } ``` -------------------------------- ### Duck Typing for Unions Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/unions.md Example demonstrating duck typing for unions, where types are identified by their shape (members) rather than explicit type headers. This is useful for protocol compatibility. ```csharp public abstract class Animal { public string Name { get; set; } } [DerivedTypeDuckTyping] public class Dog : Animal { public int BarkVolume { get; set; } } [DerivedTypeDuckTyping] public class Cat : Animal { public int MeowPitch { get; set; } } ``` -------------------------------- ### Example Violation: Async Converter Missing PreferAsyncSerialization Override Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack037.md This converter overrides async methods but fails to set `PreferAsyncSerialization` to `true`. This can lead to the serializer using slower synchronous methods. ```csharp public class DefectiveConverter : MessagePackConverter { public override T Read(ref MessagePackReader reader, MessagePackSerializerOptions options) { throw new System.NotImplementedException(); } public override async ValueTask ReadAsync(ref MessagePackReader reader, MessagePackSerializerOptions options, CancellationToken cancellationToken = default) { await Task.Delay(1, cancellationToken); return default; } public override void Write(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options) { throw new System.NotImplementedException(); } public override async ValueTask WriteAsync(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options, CancellationToken cancellationToken = default) { await Task.Delay(1, cancellationToken); } } ``` -------------------------------- ### Implement Stateful MessagePack Converter using SerializationContext Source: https://context7.com/aarnott/nerdbank.messagepack/llms.txt Utilize SerializationContext to store per-call state, enabling a single serializer instance to handle multiple configurations. This avoids recreating the converter pipeline for different states. The example demonstrates reading and writing values with a dynamic multiplier. ```csharp using Nerdbank.MessagePack; using PolyType; [GenerateShape] [MessagePackConverter(typeof(StatefulConverter))] public partial record struct SpecialType(int Value); public class StatefulConverter : MessagePackConverter { public override SpecialType Read(ref MessagePackReader reader, SerializationContext context) { int multiplier = (int)context["ValueMultiplier"]!; return new SpecialType(reader.ReadInt32() / multiplier); } public override void Write(ref MessagePackWriter writer, in SpecialType value, SerializationContext context) { int multiplier = (int)context["ValueMultiplier"]!; writer.Write(value.Value * multiplier); } } MessagePackSerializer serializer = new() { StartingContext = new SerializationContext { ["ValueMultiplier"] = 3 }, }; byte[] msgpack = serializer.Serialize(new SpecialType(5)); Console.WriteLine(serializer.ConvertToJson(msgpack)); // 15 (5 * 3) SpecialType back = serializer.Deserialize(msgpack); Console.WriteLine(back.Value); // 5 (15 / 3) ``` -------------------------------- ### Resolution: Private UnusedDataPacket property Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack062.md This example demonstrates the correct way to declare an UnusedDataPacket property as private. Remember to add a PropertyShapeAttribute to avoid introducing NBMsgPack060 issues. ```cs public class Person { public required string Name { get; set; } [PropertyShape] private UnusedDataPacket Extension { get; set; } } ``` -------------------------------- ### Violation: Public UnusedDataPacket property Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack062.md This example shows a violation where the UnusedDataPacket property is declared as public. This can lead to issues with message packing. ```cs public class Person { public required string Name { get; set; } public UnusedDataPacket Extension { get; set; } // NBMsgPack062 } ``` -------------------------------- ### Example Violation of UseComparerAttribute Rule Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack073.md This snippet demonstrates a violation where UseComparerAttribute is applied with an abstract type without a static member. This will trigger the NBMsgPack073 analyzer. ```csharp using Nerdbank.MessagePack; public abstract class AbstractComparer { } public class MyClass { [UseComparer(typeof(AbstractComparer))] public string MyProperty { get; set; } } ``` -------------------------------- ### Violation: Custom converter calls MessagePackSerializer Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack030.md This example demonstrates an incorrect implementation where a custom converter instantiates a new MessagePackSerializer and uses it to serialize a property. This violates the recommended practice for custom converters. ```csharp public class MyTypeConverter : MessagePackConverter { public override MyType? Read(ref MessagePackReader reader, SerializationContext context) => throw new System.NotImplementedException(); public override void Write(ref MessagePackWriter writer, in MyType? value, SerializationContext context) { var serializer = new MessagePackSerializer(); // NBMsgPack030 serializer.Serialize(value.SomeProperty); // NBMsgPack030 } } public class MyType { public SomeOtherType? SomeProperty { get; set; } } [GenerateShape] public partial class SomeOtherType {} ``` -------------------------------- ### Example Violation: Missing ref modifier Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack050.md This code demonstrates a method declared with a ref struct parameter without the `ref` modifier, which can cause issues with buffer and position tracking. ```csharp public void DefectiveMethod(MessagePackReader reader) { // This method will operate on a copy of the reader, not the original. // Any changes to reader.Position or its internal buffers will be lost. } ``` -------------------------------- ### Use Surrogate Types with IMarshaler for Non-Serializable Objects Source: https://context7.com/aarnott/nerdbank.messagepack/llms.txt Make non-serializable types serializable by pairing them with a simple, serializable surrogate record and an IMarshaler implementation. This approach is simpler than writing a full custom converter. The example shows how to marshal an 'OriginalType' to a 'MarshaledType' and back. ```csharp using Nerdbank.MessagePack; using PolyType; [GenerateShape] [TypeShape(Marshaler = typeof(MyTypeMarshaler))] public partial class OriginalType { private int a; private int b; public OriginalType(int a, int b) { this.a = a; this.b = b; } public int Sum => this.a + this.b; // Surrogate — simple serializable struct internal record struct MarshaledType(int A, int B); // Marshaler — converts between OriginalType and MarshaledType internal class MyTypeMarshaler : IMarshaler { public MarshaledType? Marshal(OriginalType? value) => value is null ? null : new(value.a, value.b); public OriginalType? Unmarshal(MarshaledType? surrogate) => surrogate.HasValue ? new(surrogate.Value.A, surrogate.Value.B) : null; } } MessagePackSerializer serializer = new(); var original = new OriginalType(3, 4); byte[] msgpack = serializer.Serialize(original); OriginalType? restored = serializer.Deserialize(msgpack); Console.WriteLine(restored!.Sum); // 7 ``` -------------------------------- ### Avoid Assembly Loads with ITypeShape Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/performance.md Use serialization overloads that accept ITypeShape to prevent unnecessary assembly loads. This example demonstrates how to serialize a type without loading the assembly for BigInteger. ```csharp using Nerdbank.MessagePack; using System.Numerics; // Assume MyType is defined elsewhere and does not directly depend on System.Numerics // Assume MyType implements ITypeShape var serializer = new MessagePackSerializer(); // This call will load the System.Numerics assembly if BigInteger is referenced by any witness type // var data = serializer.Serialize(new MyType()); // Instead, use the TypeShape provider directly to avoid loading unrelated assemblies: var serializer2 = new MessagePackSerializer(TypeShape.Of()); var data2 = serializer2.Serialize(new MyType()); ``` -------------------------------- ### Implement Custom MessagePack Converter for a Record Source: https://context7.com/aarnott/nerdbank.messagepack/llms.txt Subclass MessagePackConverter to define custom serialization logic for types like 'Point'. Ensure to call context.DepthStep() before reading or writing structures to prevent stack overflows. This example shows how to handle nulls, map headers, and unknown fields for forward compatibility. ```csharp using Nerdbank.MessagePack; using PolyType; public record Point(int X, int Y); public class PointConverter : MessagePackConverter { public override Point? Read(ref MessagePackReader reader, SerializationContext context) { if (reader.TryReadNil()) return null; context.DepthStep(); int count = reader.ReadMapHeader(); int x = 0, y = 0; for (int i = 0; i < count; i++) { switch (reader.ReadString()) { case "x": x = reader.ReadInt32(); break; case "y": y = reader.ReadInt32(); break; default: reader.Skip(context); break; // forward-compat: skip unknowns } } return new Point(x, y); } public override void Write(ref MessagePackWriter writer, in Point? value, SerializationContext context) { if (value is null) { writer.WriteNil(); return; } context.DepthStep(); writer.WriteMapHeader(2); writer.Write("x"); writer.Write(value.X); writer.Write("y"); writer.Write(value.Y); } } // Register at the type level via attribute [MessagePackConverter(typeof(PointConverter))] [GenerateShape] public partial class AnnotatedPoint { public int X; public int Y; } // Or register at runtime MessagePackSerializer serializer = new(); serializer = serializer with { Converters = [.. serializer.Converters, new PointConverter()], }; byte[] msgpack = serializer.Serialize(new Point(3, 4)); Console.WriteLine(serializer.ConvertToJson(msgpack)); // {"x":3,"y":4} ``` -------------------------------- ### Serve Documentation Locally with DocFX Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/CONTRIBUTING.md Run this command in the 'docfx/' directory to host the documentation site locally. Rebuild the docs by running `dotnet docfx` again after making changes. ```powershell dotnet docfx --serve ``` -------------------------------- ### Example Violation of DerivedTypeShapeAttribute Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack010.md Illustrates a scenario where DerivedType does not derive from BaseType, violating the assignability requirement of DerivedTypeShapeAttribute. ```cs [DerivedTypeShape(typeof(DerivedType), Tag = 1)] // DerivedType is not in fact derived from BaseType class BaseType { } [GenerateShape] class DerivedType { } ``` -------------------------------- ### Example Violation of NBMsgPack060 Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack060.md This C# code demonstrates a violation where a private member of type UnusedDataPacket is not configured with a PropertyShapeAttribute. ```csharp public class Person { public required string Name { get; set; } private UnusedDataPacket Extension { get; set; } // NBMsgPack060 } ``` -------------------------------- ### Serialize and Deserialize a Record Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/getting-started.md Demonstrates the roundtrip serialization and deserialization of a `SimpleRecord` object using Nerdbank.MessagePack. This involves creating an instance, serializing it to a byte array, and then deserializing it back. ```csharp // Create an instance of the record. var original = new SimpleRecord { Name = "Example", Value = 42 }; // Serialize the object to MessagePack format. var buffer = MessagePackSerializer.Serialize(original); // Deserialize the MessagePack data back into an object. var roundtrip = MessagePackSerializer.Deserialize(buffer); // Verify the roundtrip. Assert.Equal(original.Name, roundtrip.Name); Assert.Equal(original.Value, roundtrip.Value); ``` -------------------------------- ### Violation: Reusing Reader After Return Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack036.md This example demonstrates a violation where a MessagePackStreamingReader is returned before the method has finished using it. This can cause issues with subsequent read operations. ```csharp internal class Defective : IMessagePackSerializationActivator { public async ValueTask ActivateAsync(MessagePackSerializerOptions options, Type type, CancellationToken cancellationToken) { await using var reader = options.ReaderPool.Rent(cancellationToken); await reader.ReadAsync(cancellationToken); options.ReaderPool.ReturnReader(reader); await reader.ReadAsync(cancellationToken); // Violation: reader is already returned return null; } } ``` -------------------------------- ### Original Type with Non-Serializable Fields Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/surrogate-types.md This C# code defines a type with private fields that are not serialized by default. It serves as an example of a type that requires a surrogate for serialization. ```csharp public class OriginalType { private int _privateField; private string _anotherPrivateField; public OriginalType(int privateField, string anotherPrivateField) { _privateField = privateField; _anotherPrivateField = anotherPrivateField; } // Public properties for demonstration, but fields are private public int PublicFieldForDemo { get => _privateField; } public string PublicStringForDemo { get => _anotherPrivateField; } } ``` -------------------------------- ### Set C# Language Version Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/getting-started.md Configure your project to use C# 14 for enhanced features. This is typically done in your .csproj or Directory.Build.props file. ```xml 14 ``` -------------------------------- ### Resolution: Multi-Targeting Project Fix Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack051.md In multi-targeting projects, use the preferred API only where it is available. This avoids breaking builds for older target frameworks and reduces the need for extensive `#if` sections. ```csharp #if NET6_0_OR_GREATER unionTypeMapping.Map(Shape.Instance); #else unionTypeMapping.Map(); #endif ``` -------------------------------- ### Violation: MessagePackConverter with Non-Public Constructor Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack021.md This example demonstrates the violation where a custom MessagePackConverter type has an explicit, non-public constructor. Ensure your converter type has a public default constructor. ```cs [MessagePackConverter(typeof(MyTypeConverter))] public class MyType { } public class MyTypeConverter : MessagePackConverter { private MyTypeConverter() { } public override MyType Read(ref MessagePackReader reader, SerializationContext context) => throw new System.NotImplementedException(); public override void Write(ref MessagePackWriter writer, in MyType value, SerializationContext context) => throw new System.NotImplementedException(); } ``` -------------------------------- ### Array-Based Serialization with [Key] Attribute Source: https://context7.com/aarnott/nerdbank.messagepack/llms.txt Use the [Key(n)] attribute to serialize properties as compact msgpack arrays instead of string-keyed maps. Do not reuse key indexes after deployment to maintain backward compatibility. ```csharp using Nerdbank.MessagePack; using PolyType; [GenerateShape] public partial class Product { [Key(0)] public string? Name { get; set; } [Key(1)] public decimal Price { get; set; } [Key(2)] public int Stock { get; set; } } // Serializes as: ["Widget",9.99,100] (array, not name=value map) MessagePackSerializer serializer = new(); byte[] msgpack = serializer.Serialize(new Product { Name = "Widget", Price = 9.99m, Stock = 100 }); Console.WriteLine(serializer.ConvertToJson(msgpack)); // ["Widget",9.99,100] ``` -------------------------------- ### Serialize objects with indexes for keys in C# Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/customizing-serialization.md Apply @Nerdbank.MessagePack.KeyAttribute to properties and fields to opt into serializing with indexes instead of property names. This results in more compact MessagePack data. ```csharp public class MyPoco { [Key(0)] public string OneProperty { get; set; } [Key(1)] public string AnotherProperty { get; set; } } ``` -------------------------------- ### Runtime Derived Type Registration (.NET) Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/unions.md Shows how to register derived types for a union at runtime in .NET, useful when static attribute registration is not possible. ```csharp var builder = new MessagePackSerializerOptions.Builder { Security = { RecursiveDepth = 100 } }; builder.WithDerivedTypes(new DerivedType[] { new DerivedType(typeof(Dog), "dog"), new DerivedType(typeof(Cat), "cat"), new DerivedType(typeof(FarmAnimal), "animal"), }); var serializer = new MessagePackSerializer(builder.Build()); ``` -------------------------------- ### Resolution: Implementing GetJsonSchema Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack032.md This converter for MyType correctly implements GetJsonSchema to document that it serializes as an integer. ```csharp public class MyTypeConverter : MessagePackConverter { public override MyType Read(ref MessagePackReader reader, SerializationContext context) { int a = reader.ReadInt32(); return new MyType(a); } public override void Write(ref MessagePackWriter writer, in MyType value, SerializationContext context) { writer.Write(value.A); } public override JsonObject GetJsonSchema(JsonSchemaContext context, ITypeShape typeShape) { return new JsonObject { ["type"] = "integer", }; } } ``` -------------------------------- ### DerivedTypeShape Alias Resolution Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack011.md This example shows the correct way to define DerivedTypeShape attributes by assigning unique aliases (Tags) to each derived type. This resolves the violation shown previously. ```csharp [DerivedTypeShape(typeof(DerivedType1), Tag = 1)] [DerivedTypeShape(typeof(DerivedType2), Tag = 2)] class BaseType { } class DerivedType1 : BaseType { } class DerivedType2 : BaseType { } ``` -------------------------------- ### Resolution: Unique DerivedTypeShape Alias Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack012.md This example demonstrates the correct usage where each derived type is assigned a unique tag, resolving the violation. This ensures proper functioning of subtype unions. ```cs [DerivedTypeShape(typeof(DerivedType), Tag = 1)] class BaseType { } class DerivedType : BaseType { } ``` -------------------------------- ### Add Nerdbank.MessagePack Namespace Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/unity.md Include this using statement at the top of your code files to make the serializer's extension methods available. This is particularly useful for projects targeting non-.NET platforms. ```csharp using Nerdbank.MessagePack; ``` -------------------------------- ### Violation: Duplicate DerivedTypeShape Alias Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack012.md This example shows a violation where the `DerivedType` is assigned two different tags within the same `BaseType` scope. This can cause issues with subtype union resolution. ```cs [DerivedTypeShape(typeof(DerivedType), Tag = 1)] [DerivedTypeShape(typeof(DerivedType), Tag = 2)] // assigned second alias to a subtype class BaseType { } class DerivedType : BaseType { } ``` -------------------------------- ### Configure SignalR Server with Witness Class Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/signalr.md Configure the SignalR server to use MessagePack protocol, utilizing a witness class for type shape provision. This is a preferred approach for type safety with the PolyType source generator. ```csharp var builder = WebApplication.CreateBuilder(); builder.Services.AddSignalR() .AddMessagePackProtocol(); var app = builder.Build(); app.MapHub("/chat"); app.Run(); ``` -------------------------------- ### Resolution: Use SerializationContext to get converter Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack030.md This corrected implementation shows how to properly delegate the serialization of a sub-property. It retrieves the appropriate converter for the sub-type from the SerializationContext and uses it to write the value. ```csharp public override void Write(ref MessagePackWriter writer, in MyType? value, SerializationContext context) { SomeOtherType? someProperty = value.SomeProperty; context.GetConverter().Write(ref writer, ref someProperty, context); } ``` -------------------------------- ### Configure SignalR Client with MessagePack Protocol Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/signalr.md Configure a .NET SignalR client to use the MessagePack protocol by adding it to the connection builder. Ensure both server and client use the same protocol. ```csharp var connection = new HubConnectionBuilder() .WithUrl("/chat") .AddMessagePackProtocol() .Build(); ``` -------------------------------- ### Enable MessagePack Output for Controller Actions Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/aspnetmvc.md Apply the [Produces("application/x-msgpack")] attribute to controller actions or the entire controller to indicate that it will return data in the MessagePack format. This ensures clients can request and receive MessagePack-encoded data. ```csharp [Produces("application/x-msgpack")] public class PersonController : Controller { public IActionResult GetPerson(int id) { // ... return a Person object return Ok(new Person { Id = id, Name = "John Doe" }); } } ``` -------------------------------- ### Using MessagePackString for Property Names Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/custom-converters.md This C# code demonstrates how to use the MessagePackString class to avoid repeated encoding and allocation of string property names, reducing GC pressure and improving performance. ```csharp public sealed class User { public int Age { get; set; } public string Name { get; set; } } public sealed class UserConverter : MessagePackConverter { private static readonly MessagePackString AgeKey = new MessagePackString("age"); private static readonly MessagePackString NameKey = new MessagePackString("name"); public override void Write(ref MessagePackWriter writer, User value, MessagePackSerializerOptions options) { writer.WriteObjectHeader(2); writer.Write(AgeKey); writer.Write(value.Age); writer.Write(NameKey); writer.Write(value.Name); } public override User Read(ref MessagePackReader reader, MessagePackSerializerOptions options) { var count = reader.ReadObjectHeader(); var user = new User(); for (var i = 0; i < count; i++) { var key = reader.ReadString(); if (key.Equals(AgeKey.AsSpan())) { user.Age = reader.ReadInt32(); } else if (key.Equals(NameKey.AsSpan())) { user.Name = reader.ReadString(); } else { reader.Skip(); } } return user; } } ``` -------------------------------- ### DerivedTypeShape Alias Violation Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack011.md This example demonstrates a violation where the same alias (Tag = 1) is reused for two different derived types within the same base type. Ensure aliases are unique to avoid this. ```csharp [DerivedTypeShape(typeof(DerivedType1), Tag = 1)] [DerivedTypeShape(typeof(DerivedType2), Tag = 1)] // Reused an alias class BaseType { } class DerivedType1 : BaseType { } class DerivedType2 : BaseType { } ``` -------------------------------- ### Example Violation of MessagePackConverter Type Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack020.md This code demonstrates an incorrect usage of the MessagePackConverter attribute where the specified converter type does not derive from the required base class. This will cause a compilation or runtime error. ```cs [MessagePackConverter(typeof(MyTypeConverter))] // MyTypeConverter does not derive from the correct base type public class MyType { } public class MyTypeConverter { public MyType Read(ref MessagePackReader reader, SerializationContext context) => throw new System.NotImplementedException(); public void Write(ref MessagePackWriter writer, ref MyType value, SerializationContext context) => throw new System.NotImplementedException(); } ``` -------------------------------- ### Enable System.Text.Json Converters Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/built-in-converters.md Use this code to create a msgpack serializer that can convert System.Text.Json DOM types. This enables support for JsonNode, JsonElement, and JsonDocument. ```csharp var serializer = new MessagePackSerializerOptions .Standard .WithSystemTextJsonConverters() .ToSerializerOptions(); var msgpack = new MessagePackSerializer(serializer); ``` -------------------------------- ### Simple Targeted Deserialization Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/targeted-deserialization.md Deserialize a specific property from a msgpack object using a LINQ expression to define the path. This reduces the cost of deserialization by only processing the necessary data. ```csharp var data = new byte[] { ... }; // msgpack encoded data var name = MessagePackSerializer.DeserializePath(data, "person.name"); ``` -------------------------------- ### Read Whole Array for Version Compatibility Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/custom-converters.md Ensure version compatibility by reading all elements of an array, even if fewer are expected. This prevents errors when deserializing data serialized by different converter versions. ```csharp public override MyType Read(ref MessagePackReader reader, MessagePackSerializerOptions options) { // ... other cases ... case 1: // Read and skip value at index 1 reader.Skip(); break; // ... other cases ... default: // Skip any unknown array index reader.Skip(); break; } return new MyType(/* ... */); } ``` -------------------------------- ### DerivedTypeShape Aliases Across Different Types Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack011.md This example illustrates that DerivedTypeShape aliases do not need to be unique across different base types. The same alias (Tag = 1) can be used for derived types of distinct base classes. ```csharp [DerivedTypeShape(typeof(DerivedFromBaseType), Tag = 1)] class BaseType { } [DerivedTypeShape(typeof(DerivedFromAnotherType), Tag = 1)] class AnotherType { } ``` -------------------------------- ### Resolution: MessagePackConverter with Public Constructor Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack021.md This example shows the corrected version where the custom MessagePackConverter type declares a public default constructor. Alternatively, remove the explicit constructor to allow the C# compiler to generate one. ```cs [MessagePackConverter(typeof(MyTypeConverter))] public class MyType { } public class MyTypeConverter : MessagePackConverter { public override MyType Read(ref MessagePackReader reader, SerializationContext context) => throw new System.NotImplementedException(); public override void Write(ref MessagePackWriter writer, in MyType value, SerializationContext context) => throw new System.NotImplementedException(); } ``` -------------------------------- ### Resolution: Flexible deserialization with default values Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack031.md This converter demonstrates flexible deserialization by reading any number of elements from an array header and providing default values if fewer than two are encountered. It also correctly skips unknown elements. ```cs public override MyType Read(ref MessagePackReader reader, SerializationContext context) { int count = reader.ReadArrayHeader(); // Initialize default values in case the array has fewer than 2 elements. int property1 = 0; short property2 = 0; for (int i = 0; i < count; i++) { switch (i) { case 0: property1 = reader.ReadInt32(); break; case 1: property2 = reader.ReadInt16(); break; default: // Very important that we read elements in the array belonging to this object even if we don't know what to do with them. // Calling Skip() is a way to read and drop the element without knowing what kind it is. reader.Skip(); break; } } return new MyType(property1, property2); } ``` -------------------------------- ### Implement a Converter Factory Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/custom-converters.md Define a converter factory by implementing IMessagePackConverterFactory to apply a converter to many types. Register the factory using the MessagePackSerializer.ConverterFactories property. The factory is consulted for any data type requiring a converter. ```csharp using Nerdbank.MessagePack; var serializer = new MessagePackSerializer(new MessagePackSerializerOptions { ConverterFactories = { new MyConverterFactory() } }); public class MyConverterFactory : IMessagePackConverterFactory { public IMessagePackConverter? GetConverter(Type typeToConvert, MessagePackSerializerOptions options) { // Logic to determine if a converter should be returned for the given type. // Example: return new MyCustomConverter(); if typeToConvert has a specific attribute. return null; // Or return a specific converter instance } } ``` -------------------------------- ### Example Violation: Union Type Mapping Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack051.md This code constructs a union type mapping using a method that may fail at runtime if type arguments are not attributed with GenerateShapeAttribute. This is acceptable for .NET Standard or .NET Framework targets but emits a warning for .NET targets. ```csharp unionTypeMapping.Map(); ``` -------------------------------- ### Define and Serialize/Deserialize C# Record with Nerdbank.MessagePack Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/README.md Use the `[GenerateShape]` attribute on your top-level record for performance and safety. This attribute recursively generates source for all referenced types, ensuring full object graph serialization. ```cs [GenerateShape] public partial record ARecord(string AString, bool ABoolean, float AFloat, double ADouble); ``` ```cs // Construct a value. var value = new ARecord("hello", true, 1.0f, 2.0); // Create a serializer instance. MessagePackSerializer serializer = new(); // Serialize the value to the buffer. byte[] msgpack = serializer.Serialize(value); // Deserialize it back. var deserialized = serializer.Deserialize(msgpack); ``` -------------------------------- ### Basic Round-Trip Serialization with MessagePackSerializer Source: https://context7.com/aarnott/nerdbank.messagepack/llms.txt Use MessagePackSerializer for basic serialization and deserialization. Apply [GenerateShape] to the root type for source-generated, NativeAOT-safe serialization. Reuse serializer instances for performance as they cache converter models and are thread-safe. ```csharp using Nerdbank.MessagePack; using PolyType; // Only the top-level type needs [GenerateShape] and partial. [GenerateShape] public partial record Person(string Name, int Age, bool IsAdult); // Create one serializer instance and reuse it. MessagePackSerializer serializer = new(); var person = new Person("Alice", 30, true); // Serialize to byte[] byte[] msgpack = serializer.Serialize(person); // Deserialize back Person? deserialized = serializer.Deserialize(msgpack); Console.WriteLine(deserialized); // Person { Name = Alice, Age = 30, IsAdult = True } // Inspect the binary as JSON for debugging (not for production use) string json = serializer.ConvertToJson(msgpack); Console.WriteLine(json); // {"Name":"Alice","Age":30,"IsAdult":true} ``` -------------------------------- ### Runtime Derived Type Registration with DerivedShapeMapping Source: https://context7.com/aarnott/nerdbank.messagepack/llms.txt Register derived types at runtime using `DerivedShapeMapping` when attribute-based registration is not possible, such as for third-party types or plugin systems. This allows for polymorphic serialization without compile-time attribute decoration. ```csharp using Nerdbank.MessagePack; using PolyType; record Animal(string Name); [GenerateShape] partial record Horse(string Name) : Animal(Name); [GenerateShape] partial record Cow(string Name) : Animal(Name); // Build the mapping imperatively DerivedShapeMapping mapping = new(); mapping.Add(tag: 1); mapping.Add(tag: 2); MessagePackSerializer serializer = new() { DerivedTypeUnions = [mapping], }; byte[] msgpack = serializer.Serialize(new Horse("Flicka")); Animal back = serializer.Deserialize(msgpack)!; // returns Horse ``` -------------------------------- ### Resolution: Concrete Type with UseComparerAttribute Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack070.md This code shows the correct usage of the UseComparerAttribute by specifying a concrete type, resolving the NBMsgPack070 analyzer violation. ```csharp using Nerdbank.MessagePack; public class MyClass { [UseComparer(typeof(MyComparer))] public T Value { get; set; } } public class MyComparer : IComparer { public int Compare(T x, T y) => 0; } ``` -------------------------------- ### Union Types with Integer Identifiers Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/unions.md Shows how to use integer identifiers for union cases, which can improve performance and reduce payload size. ```csharp [Union(0, 1)] public abstract record Animal { [Union(1, 2)] public abstract record Horse : Animal; [Union(2, 3)] public record QuarterHorse : Horse; [Union(3, 4)] public record Thoroughbred : Horse; [Union(4, 5)] public record Dog : Animal; [Union(5, 6)] public record Cat : Animal; } ``` -------------------------------- ### MessagePackSerializer Configuration Properties Source: https://context7.com/aarnott/nerdbank.messagepack/llms.txt Configure MessagePackSerializer via object initializer or 'with' expressions. The instance is immutable and thread-safe. Options include property naming policy, skipping default values, serializing enums by name, performance optimization, max nesting depth, and preserving object references. ```csharp using Nerdbank.MessagePack; // Apply camelCase naming to all properties var serializer = new MessagePackSerializer { PropertyNamingPolicy = MessagePackNamingPolicy.CamelCase, }; // Skip default-valued properties to reduce payload size serializer = serializer with { SerializeDefaultValues = SerializeDefaultValuesPolicy.Never, }; // Serialize enum values as their string names instead of ordinals serializer = serializer with { SerializeEnumValuesByName = true, }; // Boost performance when backward compat with older serialized data is not needed serializer = serializer with { PerfOverSchemaStability = true, }; // Set max nesting depth for security (default is conservative) serializer = new MessagePackSerializer { StartingContext = new SerializationContext { MaxDepth = 100 }, }; // Preserve object reference equality across serialize/deserialize serializer = serializer with { PreserveReferences = true }; ``` -------------------------------- ### Configure SignalR with MessagePack Protocol Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/signalr.md Add the MessagePack protocol to your SignalR hub configuration by calling AddMessagePackProtocol. This should be done in your builder class. ```csharp builder.Services.AddSignalR().AddMessagePackProtocol(); ``` -------------------------------- ### Configure SignalR Client with Custom Serializer Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/docs/signalr.md Configure a .NET SignalR client to use MessagePack protocol with a custom serializer. This allows for specific MessagePack options, such as compression, to be applied on the client side. ```csharp var connection = new HubConnectionBuilder() .WithUrl("/chat") .AddMessagePackProtocol(options => { options.SerializerOptions = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4Block); }) .Build(); ``` -------------------------------- ### Violation: Open Generic Type with UseComparerAttribute Source: https://github.com/aarnott/nerdbank.messagepack/blob/main/docfx/analyzers/NBMsgPack070.md This code demonstrates the incorrect usage of the UseComparerAttribute with an open generic type, which will trigger the NBMsgPack070 analyzer. ```csharp using Nerdbank.MessagePack; public class MyClass { [UseComparer(typeof(MyComparer<>))] public T Value { get; set; } } public class MyComparer : IComparer { public int Compare(T x, T y) => 0; } ```