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
{{ message }}
Repository navigation
EnableClassInterceptors does not take into account enum KeyFilter parameters in the constructor #56
When using EnableClassInterceptors() and registering a class with WithAttributeFiltering(), parameters decorated with KeyFilter will not have their filter taken into account when trying to intercept the class
I just wanted to jump in and say that your issue here has been seen but it may be a bit before someone can jump in and do anything about it. We're dreadfully short on PRs coming in and there are only a couple of active maintainers, both of whom are doing this in their shrinking spare time. If you want this solved faster, we'd very much welcome a PR that includes the fix and a test to validate the fix.
My initial guess is that when the proxy is generated for the interceptor that we're not copying the attributes from the original class constructor parameters over to the interceptor constructor parameters. Is that right? Is there something else? I don't know without diving in and just solving the problem, which I don't have time for at this exact moment. But if you were going to try for a PR, that'd be a good place to start looking.
I understand this is a side project and time is tight. I will try to check what you are pointing me too and see if I can fix it and get a PR, but as of right now I feel it is above my knowledge of c#.
for each PositionalParameter it is trying to resolve the service without taking into account if it's keyed. Tell me if you believe this is indeed the problem to pursue it further.
After digging into this, the root cause is a bug in Castle DynamicProxy, not in this library or in Autofac core.
When EnableClassInterceptors generates the proxy subclass, Castle replicates the constructor parameter attributes onto the proxy's constructor. KeyFilterAttribute's constructor parameter is typed object (KeyFilterAttribute(object key)), so an enum key gets boxed — and Castle reproduces that boxed enum argument as its underlying integer rather than the original enum type.
The attribute is still present on the proxy constructor, but KeyFilterAttribute.Key ends up as boxed (int)0 instead of TestEnum.STRING_ONE. Core's WithAttributeFiltering then looks up new KeyedService((int)0, typeof(string)), which doesn't match the registered KeyedService(TestEnum.STRING_ONE, typeof(string)) — so the filter silently misses (picking an unkeyed fallback if one exists, or failing to bind the constructor if not).
Key points:
This only affects non-string keys (enums, etc.). String keys round-trip fine, because a string boxes into object losslessly.
It only affects EnableClassInterceptors. EnableInterfaceInterceptors doesn't rewrite the constructor, so the original attribute is read intact.
We're on the latest released Castle.Core (5.2.1); this is not fixed on their unreleased 6.0.0 branch either.
I've filed an upstream issue with a minimal (Autofac-free) repro: castleproject/Core#748.
Workarounds until Castle fixes it:
Use a string key with [KeyFilter], or
Use EnableInterfaceInterceptors instead of EnableClassInterceptors.
We'll track the upstream issue and revisit once Castle ships a fix.
changed the title [-]EnableClassInterceptors does not take into account KeyFilter-ed parameters in the constructor[/-][+]EnableClassInterceptors does not take into account enum KeyFilter parameters in the constructor[/+]on Jun 24, 2026
Activity
tillig commentedon Nov 14, 2024
I just wanted to jump in and say that your issue here has been seen but it may be a bit before someone can jump in and do anything about it. We're dreadfully short on PRs coming in and there are only a couple of active maintainers, both of whom are doing this in their shrinking spare time. If you want this solved faster, we'd very much welcome a PR that includes the fix and a test to validate the fix.
My initial guess is that when the proxy is generated for the interceptor that we're not copying the attributes from the original class constructor parameters over to the interceptor constructor parameters. Is that right? Is there something else? I don't know without diving in and just solving the problem, which I don't have time for at this exact moment. But if you were going to try for a PR, that'd be a good place to start looking.
elgatov commentedon Nov 14, 2024
Hi tillig,
I understand this is a side project and time is tight. I will try to check what you are pointing me too and see if I can fix it and get a PR, but as of right now I feel it is above my knowledge of c#.
Thanks for the help
elgatov commentedon Nov 18, 2024
I believe the error is exactly in
Autofac.Extras.DynamicProxy/src/Autofac.Extras.DynamicProxy/RegistrationExtensions.cs
Line 130 in 2115f37
for each
PositionalParameterit is trying to resolve the service without taking into account if it's keyed. Tell me if you believe this is indeed the problem to pursue it further.Thank you.
tillig commentedon Nov 18, 2024
I think that's a reasonable place to start, for sure.
tillig commentedon Jun 24, 2026
After digging into this, the root cause is a bug in Castle DynamicProxy, not in this library or in Autofac core.
When
EnableClassInterceptorsgenerates the proxy subclass, Castle replicates the constructor parameter attributes onto the proxy's constructor.KeyFilterAttribute's constructor parameter is typedobject(KeyFilterAttribute(object key)), so an enum key gets boxed — and Castle reproduces that boxed enum argument as its underlying integer rather than the original enum type.The attribute is still present on the proxy constructor, but
KeyFilterAttribute.Keyends up as boxed(int)0instead ofTestEnum.STRING_ONE. Core'sWithAttributeFilteringthen looks upnew KeyedService((int)0, typeof(string)), which doesn't match the registeredKeyedService(TestEnum.STRING_ONE, typeof(string))— so the filter silently misses (picking an unkeyed fallback if one exists, or failing to bind the constructor if not).Key points:
objectlosslessly.EnableClassInterceptors.EnableInterfaceInterceptorsdoesn't rewrite the constructor, so the original attribute is read intact.I've filed an upstream issue with a minimal (Autofac-free) repro: castleproject/Core#748.
Workarounds until Castle fixes it:
[KeyFilter], orEnableInterfaceInterceptorsinstead ofEnableClassInterceptors.We'll track the upstream issue and revisit once Castle ships a fix.
[-]EnableClassInterceptors does not take into account KeyFilter-ed parameters in the constructor[/-][+]EnableClassInterceptors does not take into account enum KeyFilter parameters in the constructor[/+]Merge pull request #65 from autofac/feature/issue-56