Skip to content

fix: case-insensitive SessionId and reserved-header handling for ASB (#4054)#4205

Open
iancooper wants to merge 1 commit into
masterfrom
bug/4054
Open

fix: case-insensitive SessionId and reserved-header handling for ASB (#4054)#4205
iancooper wants to merge 1 commit into
masterfrom
bug/4054

Conversation

@iancooper

Copy link
Copy Markdown
Member

What

Fixes #4054 — the ASB SessionId set from a Brighter outbox was silently dropped.

Root cause

Brighter's JSON serialization uses JsonNamingPolicy.CamelCase (see JsonSerialisationOptions), so a header bag key written as "SessionId" returns as "sessionId" after a serialization round-trip — e.g. when a message is stored in and read back from an Outbox.

In AzureServiceBusMessagePublisher:

  • Bag.TryGetValue("SessionId", …) is an exact match, so it missed the camelCased "sessionId" key and the session was never set on the outgoing message.
  • The reserved-header filter ReservedHeaders.Contains(h.Key) is also case-sensitive, so the camelCased reserved keys (sessionId, messageType, handledCount, replyTo) leaked into ApplicationProperties.

Fix

Both lookups now use OrdinalIgnoreCase:

  • SessionId is resolved case-insensitively.
  • Reserved headers are stripped case-insensitively.

Tests

Added When_Converting_A_Message_With_A_Session_Id.cs — a [Theory] proving both "SessionId" and "sessionId" set ServiceBusMessage.SessionId and are kept out of ApplicationProperties.

Notes

The diagnosis was confirmed by tracing the camelCase serialization policy before fixing (the original suggested fix only partially addressed the reserved-header leak). That "confirm the theory first" step is the basis of the lightweight bug workflow proposed in #4204.

🤖 Generated with Claude Code

…4054)

Brighter's JSON serialization camelCases header bag keys, so a "SessionId"
key returns as "sessionId" after an Outbox round-trip. The publisher's
exact-match lookup missed it (session never set) and the case-sensitive
reserved-header filter let it leak into ApplicationProperties. Both lookups
are now OrdinalIgnoreCase.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@codescene-delta-analysis codescene-delta-analysis Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our agent can fix these. Install it.

Gates Passed
4 Quality Gates Passed

Quality Gate Profile: Clean Code Collective
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

@iancooper iancooper self-assigned this Jun 25, 2026
@iancooper iancooper added 3 - Done .NET Pull requests that update .net code V10.X labels Jun 25, 2026
@iancooper

Copy link
Copy Markdown
Member Author

@Jonny-Freemarket Any thoughts?

@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Code Review — PR #4205: case-insensitive SessionId & reserved-header handling (ASB)

Reviewed the diff against the surrounding code and traced the serialization path. Overall: correct, well-scoped fix with an accurate root-cause diagnosis. I verified the claim independently — DictionaryStringObjectJsonConverter.Write (line 57) applies options.PropertyNamingPolicy.ConvertName to every bag key, and JsonSerialisationOptions sets CamelCase, so a bag key written as SessionId does round-trip back as sessionId. The JsonSerialisationOptions XML doc even calls this out explicitly. Good detective work, and the in-code comments make the non-obvious behavior discoverable for the next maintainer.

Correctness ✅

  • FirstOrDefault(...).Value on the Dictionary<string,object> returns default(KeyValuePair<…>) = (null, null) when no match, so the is not null guard is safe — no KeyNotFoundException/NRE risk.
  • Stripping reserved headers case-insensitively and then re-adding MessageType/HandledCount/ReplyTo from the canonical header properties is the right ordering: the camelCased duplicates are removed and the authoritative values re-added.

Suggestions (non-blocking)

  1. Test coverage gap vs. the stated fix scope. The PR body says messageType, handledCount, and replyTo also leaked into ApplicationProperties when camelCased, and the reserved-header filter change addresses that — but the new test only exercises SessionId/sessionId. Since the reserved-header leak is half the fix, consider a [Theory] (or extra cases) asserting that camelCased messageType/handledCount/replyTo bag keys do not appear in ApplicationProperties. Otherwise a future regression to the ReservedHeaders.Contains comparer would slip through untested.

  2. Behavior change worth noting. Reserved-header stripping is now case-insensitive across the board, so a user-supplied custom property whose key differs from a reserved name only by case (e.g. sessionid, Replyto) will now be stripped where it previously passed through. This is consistent with the fix's intent and almost certainly desirable, but it is a (minor) observable change for that edge case.

  3. Minor: ambiguous-casing edge case. A Dictionary<string,object> can legitimately hold both SessionId and sessionId simultaneously. FirstOrDefault then resolves to whichever the dictionary enumerates first, which isn't a guaranteed order. Extremely unlikely in practice (a round-trip produces only the camelCased form), so not worth code — just flagging.

  4. Micro-perf (negligible). The lookup moved from an O(1) TryGetValue to an O(n) FirstOrDefault scan, and the bag is now iterated twice. The header bag is tiny, so this is irrelevant — mentioning only for completeness.

Conventions ✅

  • New test follows repo naming (When_Converting_… file, AzureServiceBusMessagePublisher…Tests class, [Trait("Category","ASB")]), matching siblings like When_Converting_A_Message_With_Local_Headers.cs.
  • A test was added with the fix, consistent with the repo's TDD guidance.

Nice fix — the one thing I'd genuinely push on before merge is adding the reserved-header-leak assertions (suggestion #1) so the second half of the change is actually covered by a test.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3 - Done Bug .NET Pull requests that update .net code V10.X

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Do Case insensitive check for ASB sessionID

1 participant