Skip to content

Header-bag key lookups are not naming-policy-aware (latent SessionId/#4054-class bugs) #4214

Description

@iancooper

Background

#4054 / #4205 fixed the ASB AzureServiceBusMessagePublisher, where a SessionId bag key was silently dropped after an Outbox round-trip. Root cause: the Outbox serializes the header Bag with JsonSerialisationOptions.Options, whose PropertyNamingPolicy (default JsonNamingPolicy.CamelCase) rewrites bag keys (see DictionaryStringObjectJsonConverter.Write). A key written as "SessionId" therefore comes back as "sessionId" — and the exact-match TryGetValue/Contains missed it.

The fix in the publisher now resolves keys via the active naming policy (ASBConstants.IsBagKey / IsReservedHeader), which is correct under any policy, including a user-overridden one (JsonSerialisationOptions.Options has a public setter).

This issue tracks the other sites with the same pattern. They were left out of the #4054 PR to keep its scope tight, and are categorised below by whether they reproduce today.

Reproducibly broken under the default (camelCase) policy

  • RocketMqMessageProducerBag.TryGetValue(HeaderNames.Keys, …) (RocketMqMessageProducer.cs:156) and HeaderNames.Tag (:172). The constants are "Brighter-RocketMQ-Keys" / "Brighter-RocketMQ-Tag"; camelCase lowercases the leading char (brighter-RocketMQ-Keys), so an exact-match lookup misses the key after an Outbox round-trip. Producer-side, app-supplied keys → genuinely affected.

Latent — correct only by accident under camelCase, would break under another policy (e.g. SnakeCaseLower)

  • AWS messageDeduplicationIdSnsMessagePublisher.cs:84, SqsMessageSender.cs:100 (plus the .V4 equivalents and AwsScheduler). The constant is already camelCase, so it survives the default policy — but ConvertName under snake_case yields message_deduplication_id and the exact match fails.
  • Core ProducerTopicOutboxProducerMediator.cs:946 reads Message.ProducerTopicHeaderName ("paramore.brighter.ProducerTopic"), set in WrapPipeline/WrapPipelineAsync before the Outbox store. Leading char is already lowercase, so it survives camelCase; would break under snake_case.

Same code smell but NOT reproducibly broken

  • AzureServiceBusSchedulerAzureServiceBusScheduler.cs:135 (ReservedHeaders.Contains(h.Key), no comparer) and :150 (TryGetValue(ASBConstants.SessionIdKey, …)). These look like the [Bug] Do Case insensitive check for ASB sessionID #4054 twin, but ConvertToServiceBusMessage runs against a freshly-constructed header whose Bag is empty (the original message is serialized into the body as a FireAzureScheduler payload, not the header bag). So the lookups never mismatch today. Worth hardening for consistency, but no live bug. Note the scheduler has its own duplicate ASBConstants (separate assembly), so it can't share the gateway's helper.

Suggested direction

Provide a shared, naming-policy-aware bag-key lookup (mirroring ASBConstants.IsBagKey) that reads JsonSerialisationOptions.Options.PropertyNamingPolicy at call time and matches raw-or-ConvertName, case-insensitive. Prime candidate for lifting into Paramore.Brighter core so every gateway/transform can reuse it rather than each re-implementing exact-match lookups.

Deeper question worth a design note: reserved/system bag keys (SessionId, etc.) arguably shouldn't be subject to a cosmetic naming policy during persistence at all — but changing the converter is a breaking wire-format change, so the read-side policy-aware lookup is the pragmatic fix.

Filed as follow-up to #4205.

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions