Skip to content

Pin the my/routes manifest to one wire shape across instances#5573

Merged
WilliamBZA merged 2 commits into
authfrom
fix-my-routes-manifest-casing
Jul 3, 2026
Merged

Pin the my/routes manifest to one wire shape across instances#5573
WilliamBZA merged 2 commits into
authfrom
fix-my-routes-manifest-casing

Conversation

@dvdstelt

@dvdstelt dvdstelt commented Jul 2, 2026

Copy link
Copy Markdown
Member

Problem

The my/routes manifest is served by a single shared controller (MyRoutesController) hosted on the Primary, Audit, and Monitoring instances. Each instance serializes JSON with its own global naming policy: Primary snake_case, Monitoring camelCase. So the same contract emitted url_template from Primary and urlTemplate from Monitoring. ServicePulse merges both manifests and keys on url_template, so every Monitoring entry was silently dropped, denying Monitoring-gated actions regardless of the user's actual permissions.

Fix

Pin the field names on RouteManifestEntry with [JsonPropertyName], which overrides each host's naming policy, so every instance emits an identical { method, url_template }. Added a serialization test asserting snake_case is emitted even under a camelCase policy (the existing acceptance test deserializes into the record and is casing-agnostic, so it could not catch a regression).

MyRoutesController is the only controller shared across instances, so RouteManifestEntry is the only DTO affected. The my/routes endpoint is unreleased, so there is no backward-compatibility impact.

ServicePulse coordination

This supersedes the client-side dual-casing workaround in Particular/ServicePulse#3053, which can be closed. The one useful part of that PR, discovering the my/routes URL from the root document, has been folded into the main ServicePulse feature PR (Particular/ServicePulse#3035). With this fix the ServicePulse client reads snake_case only, so we can ship the two together.

dvdstelt added 2 commits July 2, 2026 13:15
The Primary instance serializes JSON snake_case while the Monitoring instance
serializes camelCase, so the same my/routes contract emitted url_template on one
and urlTemplate on the other. A client merging both manifests would silently
drop every entry from the differently-cased instance.

Pin the field names on RouteManifestEntry with [JsonPropertyName] so every host
emits an identical { method, url_template } shape regardless of its global JSON
naming policy.
The acceptance test deserializes the response into the C# record, which is
casing-agnostic, so it would not catch a regression of the emitted field names.
Add a serialization test asserting RouteManifestEntry emits snake_case even under
a camelCase policy (as the Monitoring instance uses), pinning the contract that
[JsonPropertyName] enforces.
@WilliamBZA WilliamBZA merged commit e98efda into auth Jul 3, 2026
33 checks passed
@WilliamBZA WilliamBZA deleted the fix-my-routes-manifest-casing branch July 3, 2026 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants