autofac / Autofac.Extras.DynamicProxy

Interceptor and decorator support for Autofac IoC via Castle DynamicProxy
MIT License
106 stars 33 forks source link

Cannot interface-proxy `internal` interface #2

Closed BrunoJuchli closed 9 years ago

BrunoJuchli commented 9 years ago

Cannot interface-propxy internal interface even though assembly is marked with

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

as stated in the Documentation

Container Configuration

builder.RegisterType<TrackCurrentSingleCallInterceptor>().AsSelf();

builder.RegisterType<SingleCall>()
    .As<ISingleCallWithUpdate>()
    .EnableInterfaceInterceptors()
    .InterceptedBy(typeof(TrackCurrentSingleCallInterceptor));

Exception

System.InvalidOperationExceptionThe component Activator = SingleCall (ReflectionActivator), Services = [Pmr.TetrapolRadio.SingleCommunication.ISingleCallWithUpdate], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope cannot use interface interception as it provides services that are not publicly visible interfaces. Check your registration of the component to ensure you're not enabling interception and registering it as an internal/private interface type. at Autofac.Extras.DynamicProxy2.RegistrationExtensions.EnsureInterfaceInterceptionApplies(IComponentRegistration componentRegistration) at Autofac.Extras.DynamicProxy2.RegistrationExtensions.<>cDisplayClassc`3.b9(Object sender, ActivatingEventArgs1 e) at System.EventHandler1.Invoke(Object sender, TEventArgs e) at Autofac.Core.Registration.ComponentRegistration.RaiseActivating(IComponentContext context, IEnumerable1 parameters, ref Object instance) at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable1 parameters) at Autofac.Core.Resolving.InstanceLookup.Execute() at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable1 parameters) at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable1 parameters)

(Hint: Moq-ing internal interfaces from the same assembly works (=> in a different test assembly), so the attribute is set correctly).

Issue-Analysis

RegistrationExtensions.EnsureInterfaceInterceptionApplies contains a check

if (((Type) swt.ServiceType).IsInterface)
          return !((Type) swt.ServiceType).IsVisible;

This check is not in line with documentation, because IsVisible only returns true if the type is public, not when it's internal combined with InternalsVisibleToAttribute.

I don't think that there's a possiblity to check for whether some Type is visible to another Assembly due to InternalsVisibleToAttribute, so i suggest just getting rid of the IsVisible check.

Comment: As the exception is occuring during resolving (not when building the container), the failure-case will still be detected at the exact same time. Only potential downside is, that Castle DynamicProxy's exception message might not be as verbose. In one part it's more verbose, however, because it states that you can fix it by adding an InternalsVisibleToAttribute...

alexmg commented 9 years ago

I've pushed a 3.0.6 package to NuGet that supports internal interfaces if the InternalsVisibleToAttribute has been set to DynamicProxyGenAssembly2.

If your assembly is strong named the attribute must include the PublicKey:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
BrunoJuchli commented 9 years ago

that was fast. Thanks! :)