Skip to content

GH-516 parity for HTTP: Before middleware can replace an immutable request body - #3984

Open
danniewalden wants to merge 1 commit into
JasperFx:mainfrom
danniewalden:http-middleware-message-replacement
Open

GH-516 parity for HTTP: Before middleware can replace an immutable request body#3984
danniewalden wants to merge 1 commit into
JasperFx:mainfrom
danniewalden:http-middleware-message-replacement

Conversation

@danniewalden

@danniewalden danniewalden commented Aug 20, 2026

Copy link
Copy Markdown

Motivation

Handler chains have supported middleware replacing an immutable message since GH-516: a Before/BeforeAsync accepting the message type and returning it (optionally in a tuple) overwrites the message for the rest of the chain. HTTP chains lack the equivalent pass, so the same pattern on an endpoint class fails compilation with a colliding local (CS0841/CS0136):

public static Command Before(Command input, TimeProvider clock) =>
    input with { RejectedAt = clock.GetUtcNow() };

[WolverinePost("/reject")]
public static IResult Handle(Command command, State state) => ...;

Changes

Mirrors the HandlerChain.DetermineFrames GH-516 pass onto HttpChain.DetermineFrames (12 lines), with two HTTP-specific guards:

  • skip chains with no request body
  • skip the frame that reads the request body itself — the Newtonsoft reader is a MethodCall whose ReturnVariable is the request body variable; flipping it would delete the declaration

Sync, async, and tuple-returning Before methods behave identically to the handler side.

Out of scope

Registered middleware (Policies.AddMiddleware, [Middleware]) returning the request type is still blocked by the existing MiddlewarePolicy exception.

Tests

  • middleware_replacing_immutable_request: Bug_516-style chained sync/async/tuple fact + tuple IResult short-circuit
  • using_newtonsoft_for_serialization: regression for the body-reader skip
  • Docs section in docs/guide/http/middleware.md

Full net9.0-pinned wolverine.slnx build clean; Wolverine.Http.Tests and CoreTests suites green.

🤖 Generated with Claude Code

…fore middleware replace the request (JasperFxGH-516 parity)

Message handler chains have supported middleware replacing an immutable
message since JasperFxGH-516: a Before/BeforeAsync method that accepts the message
type and returns it (optionally in a tuple) overwrites the original for the
rest of the chain. HTTP chains never got the same codegen pass, so the same
pattern on an endpoint class generated a colliding local variable and
failed compilation (CS0841/CS0136).

This mirrors the HandlerChain.DetermineFrames pass onto
HttpChain.DetermineFrames, with two HTTP-specific guards: skip when the
chain has no request body, and skip the frame that reads the request body
itself (the Newtonsoft reader is a MethodCall whose ReturnVariable IS the
request body variable).

Scope is deliberately limited to Before methods declared on the endpoint
class; externally registered middleware returning the request type is still
guarded by the existing MiddlewarePolicy exception.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant