Repository navigation
Add real-world middleware examples and document the Type overloads - #201
Merged
Merged
Conversation
Fixes #160. The pipeline page explained the API thoroughly but its only example was a "Hello World" that wrote to the console, which leaves the reader knowing how to add middleware and not what to add it for. Four examples now cover the shapes that actually come up: timing an activation, substituting resolve parameters, short-circuiting to return a cached instance, and applying one behavior across many services at once. That last one is the case from autofac/Autofac#1337 - wanting an aspect applied to every registration without calling an extension method on each one - which is what motivated the RegisterServiceMiddleware overloads added in 8.2.0. Those overloads were themselves undocumented: the Type-based ones for when the service isn't known at compile time, the descriptor that names the middleware in resolve traces instead of leaving it "anonymous", and StartOfPhase insertion. The short-circuit example carries a warning, because the sharp edge isn't obvious. DisposalTrackingMiddleware runs in the registration pipeline, so an instance supplied from the service pipeline's Sharing phase is never tracked for disposal and its lifetime events never fire.
tillig
force-pushed
the
feature/middleware-examples
branch
from
September 1, 2026 18:04
010ae9a to
d13a88f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #160.
Why
The pipeline page explains the API thoroughly, but its only example was a "Hello World" that writes to the console. That leaves a reader knowing how to add middleware and not what to add it for — which is exactly what #160 asked for.
#160 also pointed at autofac/Autofac#1337 as a case solved with middleware where the solution "wasn't an obvious solution". Following that thread, the ask was an aspect applied to every registration without calling an extension method on each one — and that's the scenario that motivated the
RegisterServiceMiddlewareoverloads added in 8.2.0. Those overloads turned out to be undocumented too, so this covers both.What's added
Four examples, each a shape that comes up in practice rather than a demo:
NewInstanceActivatedto avoid recording timings when a shared instance was handed back and nothing was actually constructed.ParameterSelectionis documented in the phase table as "the recommended point at which the resolve parameters should be replaced" but had no example. ShowsChangeParametersand appends to the existing set so an explicitly-passed parameter still wins.Instance, don't callnext. The phase table says to useSharing"to choose your own shared instance"; this is what that looks like.Plus the three undocumented pieces of the 8.2.0 API: the
Type-based overloads for when the service type isn't known at compile time, thedescriptorthat names your middleware in resolve traces instead of leaving itanonymous, andMiddlewareInsertionMode.StartOfPhase.The sharp edge, called out
The short-circuit example carries a warning, because the trap isn't visible from the API.
DisposalTrackingMiddlewareruns in the registration pipeline (Phase => PipelinePhase.Activation, added toComponentRegistration._lateBuildPipeline). An instance supplied from the service pipeline'sSharingphase never reaches it, so it isn't tracked for disposal and its lifetime events never fire. Easy to ship a leak on.Verification
Every API in the new examples was checked against source rather than assumed:
IResolvePipelineBuilder.Useoverloads confirmed inPipelineBuilderExtensions.cs, including the(phase, insertionMode, callback)form the timing example uses.ChangeParameters,Instance,NewInstanceActivated,Serviceconfirmed onResolveRequestContext.RegisterServiceMiddlewareoverloads confirmed inServiceMiddlewareRegistrationExtensions.cs; theTypeanddescriptorforms are exercised byRegistrationOnlyIfTests.ConfigurePipeline, since the docs note that crossing them is an error.sphinx -b html -W --keep-goinganddoc8clean. I also checked the rendered heading tree: the four examples nest correctly ash3under a newExamplesh2, which confirms the hierarchy repair from #197 is holding.