BrighterCommand / BrighterCommand/Brighter

Newtonsoft.Json compatibility broken on MessageHeader and Observability.Baggage

Open
#4,149 0 comments 0 reactions 1 assignee Claimed by @DevJonny View on GitHub
.NET 0 - Backlog Bug V10.X
Dominant language
C#
Stars
2.5k
Forks
296
Avg merge
1d 11h
Merged PRs (30d)
21

Description

### Describe the bug

Several Brighter types cannot be (de)serialised by `Newtonsoft.Json`. This breaks the otherwise-supported combination of Brighter + a Newtonsoft-based persistence stack (e.g. an app using the Cosmos SDK's `CosmosJsonNetSerializer` for the inbox/outbox).

Two distinct symptoms with the same root cause — Brighter only ships System.Text.Json infrastructure for shapes that need a custom converter:

**1. `MessageHeader` properties carry `[Newtonsoft.Json.JsonConverter]` attributes pointing at STJ converters**

`MessageHeader.Topic`, `MessageHeader.ReplyTo`, `MessageHeader.TraceParent`, and `MessageHeader.TraceState` are decorated with `[Newtonsoft.Json.JsonConverter(typeof(X))]` where the referenced converter type `X` inherits from `System.Text.Json.Serialization.JsonConverter`, not `Newtonsoft.Json.JsonConverter`. Newtonsoft tries to instantiate it as one of its own converters and throws `InvalidCastException`.

**2. `Paramore.Brighter.Observability.Baggage` has no Newtonsoft converter**

`Baggage` implements `IEnumerable>` but exposes `Add(string, string)` only — there is no `Add(KeyValuePair)`. Newtonsoft sees the `IEnumerable>` implementation, infers a list-shaped target, and fails to populate it because no matching `Add` overload exists. The same shape of problem affects `System.Net.Mime.ContentType` (its `Parameters` collection isn't Newtonsoft-friendly) wherever it appears on a Newtonsoft-traversed type.

### To Reproduce

**Symptom 1:**

```csharp
var json = JsonConvert.SerializeObject(new MessageHeader(
messageId: Id.Random(),
topic: new RoutingKey("test"),
messageType: MessageType.MT_EVENT));

// Throws InvalidCastException: Unable to cast object of type
// 'Paramore.Brighter.JsonConverters.' to type 'Newtonsoft.Json.JsonConverter'.
var roundtripped = JsonConvert.DeserializeObject(json);
```

Equivalent failure occurs whenever Newtonsoft walks the type — e.g. Cosmos SDK reading a `MessageHeader` out of an outbox/inbox document with `CosmosJsonNetSerializer`.

**Symptom 2:**

```csharp
var baggage = new Baggage();
baggage.Add("k", "v");

var json = JsonConvert.SerializeObject(baggage);
var roundtripped = JsonConvert.DeserializeObject(json);
// Fails — no matching Add overload for KeyValuePair
```

### Exceptions

Symptom 1:
```
System.InvalidCastException: Unable to cast object of type
'Paramore.Brighter.JsonConverters.' to type 'Newtonsoft.Json.JsonConverter'.
at Newtonsoft.Json.Serialization.JsonTypeReflector.CreateJsonConverterInstance(...)
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateProperty(...)
```

### Suggested fix

For the `MessageHeader` attributes — either:

1. Drop the `[Newtonsoft.Json.JsonConverter(...)]` attributes (STJ-only annotation is fine; Newtonsoft consumers can configure their own converters globally), **or**
2. Ship a real `Newtonsoft.Json.JsonConverter` sibling for each affected property and reference it from the attribute.

For `Baggage` (and any sibling types with the same problem) — either:

1. Ship a `Newtonsoft.Json.JsonConverter` sibling alongside the STJ converter, matching the same wire shape (`[{"Key":"...","Value":"..."}]`), **or**
2. Expose a public mutable dictionary-shaped API on `Baggage` that general-purpose serialisers can populate without a custom converter.

Workaround currently in use downstream: a Newtonsoft `IContractResolver` that detects the misattributed properties and ignores them, plus hand-rolled `Newtonsoft.Json.JsonConverter` and `Newtonsoft.Json.JsonConverter` siblings.

### Further technical details

- Brighter version: **10.4.1**
- `dotnet --info`:
```
.NET SDK 10.0.108 (commit 94ea82652c, MSBuild 18.0.11+94ea82652)
Host 10.0.8 (x64)
RID: win-x64
```
- OS: Windows 11 (build 10.0.26200)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.