You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Allow a decorator registration to be intercepted using the same fluent syntax we already use for normal registrations:
builder.RegisterType<StringMethodInterceptor>();// The decorator gets intercepted, using familiar chained syntax.builder.RegisterDecorator<Decorator,IService>().EnableInterfaceInterceptors().InterceptedBy(typeof(StringMethodInterceptor));// The decorated type can be intercepted independently (existing syntax).builder.RegisterType<Implementation>().EnableInterfaceInterceptors().InterceptedBy(typeof(SomeOtherInterceptor)).As<IService>();
Background / motivation
Since Autofac v5, the resolve pipeline changed such that an interceptor attached to a service registration wraps the innermost (decorated) instance, not the outermost decorator. This is discussed at length in autofac/Autofac#1416. We are not proposing to change that order-of-operations behavior. Instead we want to let people attach interception directly to the decorator registration, so the interception point is explicit and reads naturally ("the decorator is intercepted by X") rather than relying on interceptors "magically" moving during decoration.
PR #55 attempted this with a standalone builder.EnableInterfaceInterceptors<TService>() call disconnected from the decorator registration. That syntax was rejected in review as confusing/inconsistent — it isn't clear what is intercepting what, or how it relates to RegisterType interception.
Why this works mechanically
Tracing the core resolve pipeline: when DecoratorMiddleware resolves the decorator, it does so via a new ResolveRequest that preserves the decorator's own registration, and RegistrationPipelineInvokeMiddleware invokes context.Registration.ResolvePipeline. Interface interception attaches its middleware at the Activation phase on the registration pipeline. So if interception middleware is present on the decorator registration's pipeline, it executes and wraps the (outermost) decorator instance. No core runtime change is needed — only a way to configure that pipeline.
The blocker (requires a core Autofac change)
The modern RegisterDecorator<TDecorator, TService>() returns void and builds + snapshots the decorator registration internally (CreateRegistration() clones the pipeline). There is no IRegistrationBuilder to chain .EnableInterfaceInterceptors() onto, and the pipeline is frozen by the time the method returns.
This needs a core change so decorator registration returns a configurable builder. The plan for that is captured in autofac/Autofac#1416. Once core exposes a decorator builder with ConfigurePipeline (and metadata for InterceptedBy), the work in this repo is small, since EnableInterfaceInterceptors/InterceptedBy are already extension methods.
Scope & open questions for the implementation
Closed-type decorators first. Open-generic decorators (RegisterGenericDecorator) build the closed decorator registration lazily at resolve time (OpenGenericDecoratorMiddlewareSource), so there's no registration-time builder to configure. Recommend deferring open-generic support to a follow-up.
[Intercept] attribute selection on the decorator type
A different interceptor for the decorator vs. the decorated type (good acceptance test)
Sensible behavior for class-vs-interface interception combinations
Reusable cleanup regardless of this feature: extract the duplicated proxy-application logic out of RegistrationExtensions into a shared ProxyHelpers (as PR Add intercept on decorator #55 did). This can land independently.
Process note: new tests should use NSubstitute, not Moq.
Dependencies
Blocked on the core Autofac change tracked in autofac/Autofac#1416, which is a breaking change and must ship in a major core release. This issue tracks the downstream feature; PR #55 is the original prototype.
Summary
Allow a decorator registration to be intercepted using the same fluent syntax we already use for normal registrations:
Background / motivation
Since Autofac v5, the resolve pipeline changed such that an interceptor attached to a service registration wraps the innermost (decorated) instance, not the outermost decorator. This is discussed at length in autofac/Autofac#1416. We are not proposing to change that order-of-operations behavior. Instead we want to let people attach interception directly to the decorator registration, so the interception point is explicit and reads naturally ("the decorator is intercepted by X") rather than relying on interceptors "magically" moving during decoration.
PR #55 attempted this with a standalone
builder.EnableInterfaceInterceptors<TService>()call disconnected from the decorator registration. That syntax was rejected in review as confusing/inconsistent — it isn't clear what is intercepting what, or how it relates toRegisterTypeinterception.Why this works mechanically
Tracing the core resolve pipeline: when
DecoratorMiddlewareresolves the decorator, it does so via a newResolveRequestthat preserves the decorator's own registration, andRegistrationPipelineInvokeMiddlewareinvokescontext.Registration.ResolvePipeline. Interface interception attaches its middleware at theActivationphase on the registration pipeline. So if interception middleware is present on the decorator registration's pipeline, it executes and wraps the (outermost) decorator instance. No core runtime change is needed — only a way to configure that pipeline.The blocker (requires a core Autofac change)
The modern
RegisterDecorator<TDecorator, TService>()returnsvoidand builds + snapshots the decorator registration internally (CreateRegistration()clones the pipeline). There is noIRegistrationBuilderto chain.EnableInterfaceInterceptors()onto, and the pipeline is frozen by the time the method returns.This needs a core change so decorator registration returns a configurable builder. The plan for that is captured in autofac/Autofac#1416. Once core exposes a decorator builder with
ConfigurePipeline(and metadata forInterceptedBy), the work in this repo is small, sinceEnableInterfaceInterceptors/InterceptedByare already extension methods.Scope & open questions for the implementation
RegisterGenericDecorator) build the closed decorator registration lazily at resolve time (OpenGenericDecoratorMiddlewareSource), so there's no registration-time builder to configure. Recommend deferring open-generic support to a follow-up.ProxyGenerationOptionssupport on the decorator[Intercept]attribute selection on the decorator typeRegistrationExtensionsinto a sharedProxyHelpers(as PR Add intercept on decorator #55 did). This can land independently.Dependencies
Blocked on the core Autofac change tracked in autofac/Autofac#1416, which is a breaking change and must ship in a major core release. This issue tracks the downstream feature; PR #55 is the original prototype.