Skip to content

Commit

Permalink
Improved performance of class based dynamic proxies by caching attrib…
Browse files Browse the repository at this point in the history
…ute defined interceptor services in registration metadata.
  • Loading branch information
alexmg committed Feb 17, 2017
1 parent 75360d3 commit d612783
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 39 deletions.
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 4.2.0.{build}
version: 4.2.1.{build}

configuration: Release

Expand Down
92 changes: 55 additions & 37 deletions src/Autofac.Extras.DynamicProxy/RegistrationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public static class RegistrationExtensions
{
private const string InterceptorsPropertyName = "Autofac.Extras.DynamicProxy.RegistrationExtensions.InterceptorsPropertyName";

private const string AttributeInterceptorsPropertyName = "Autofac.Extras.DynamicProxy.RegistrationExtensions.AttributeInterceptorsPropertyName";

private static readonly IEnumerable<Service> EmptyServices = new Service[0];

private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator();
Expand Down Expand Up @@ -132,10 +134,13 @@ public static IRegistrationBuilder<TLimit, TConcreteReflectionActivatorData, TRe
}

registration.ActivatorData.ImplementationType =
ProxyGenerator.ProxyBuilder.CreateClassProxyType(
registration.ActivatorData.ImplementationType,
additionalInterfaces ?? new Type[0],
options);
ProxyGenerator.ProxyBuilder.CreateClassProxyType(
registration.ActivatorData.ImplementationType,
additionalInterfaces ?? new Type[0],
options);

var interceptorServices = GetInterceptorServicesFromAttributes(registration.ActivatorData.ImplementationType);
AddInterceptorServicesToMetadata(registration, interceptorServices, AttributeInterceptorsPropertyName);

registration.OnPreparing(e =>
{
Expand Down Expand Up @@ -203,8 +208,7 @@ public static IRegistrationBuilder<TLimit, TActivatorData, TSingleRegistrationSt
{
EnsureInterfaceInterceptionApplies(e.Component);

var proxiedInterfaces =
e.Instance
var proxiedInterfaces = e.Instance
.GetType()
.GetInterfaces()
.Where(i =>
Expand All @@ -223,13 +227,13 @@ public static IRegistrationBuilder<TLimit, TActivatorData, TSingleRegistrationSt
var interfaces = proxiedInterfaces.Skip(1).ToArray();

var interceptors = GetInterceptorServices(e.Component, e.Instance.GetType())
.Select(s => e.Context.ResolveService(s))
.Cast<IInterceptor>()
.ToArray();
.Select(s => e.Context.ResolveService(s))
.Cast<IInterceptor>()
.ToArray();

e.Instance = options == null
? ProxyGenerator.CreateInterfaceProxyWithTarget(theInterface, interfaces, e.Instance, interceptors)
: ProxyGenerator.CreateInterfaceProxyWithTarget(theInterface, interfaces, e.Instance, options, interceptors);
? ProxyGenerator.CreateInterfaceProxyWithTarget(theInterface, interfaces, e.Instance, interceptors)
: ProxyGenerator.CreateInterfaceProxyWithTarget(theInterface, interfaces, e.Instance, options, interceptors);
});

return registration;
Expand Down Expand Up @@ -259,16 +263,7 @@ public static IRegistrationBuilder<TLimit, TActivatorData, TStyle> InterceptedBy
throw new ArgumentNullException(nameof(interceptorServices));
}

object existing;
if (builder.RegistrationData.Metadata.TryGetValue(InterceptorsPropertyName, out existing))
{
builder.RegistrationData.Metadata[InterceptorsPropertyName] =
((IEnumerable<Service>)existing).Concat(interceptorServices).Distinct();
}
else
{
builder.RegistrationData.Metadata.Add(InterceptorsPropertyName, interceptorServices);
}
AddInterceptorServicesToMetadata(builder, interceptorServices, InterceptorsPropertyName);

return builder;
}
Expand Down Expand Up @@ -403,9 +398,9 @@ public static IRegistrationBuilder<TLimit, TActivatorData, TSingleRegistrationSt
private static void EnsureInterfaceInterceptionApplies(IComponentRegistration componentRegistration)
{
if (componentRegistration.Services
.OfType<IServiceWithType>()
.Select(s => s.ServiceType.GetTypeInfo())
.Any(s => !s.IsInterface || (!s.Assembly.IsInternalToDynamicProxy() && !s.IsVisible)))
.OfType<IServiceWithType>()
.Select(s => s.ServiceType.GetTypeInfo())
.Any(s => !s.IsInterface || (!s.Assembly.IsInternalToDynamicProxy() && !s.IsVisible)))
{
throw new InvalidOperationException(
string.Format(
Expand All @@ -415,6 +410,23 @@ private static void EnsureInterfaceInterceptionApplies(IComponentRegistration co
}
}

private static void AddInterceptorServicesToMetadata<TLimit, TActivatorData, TStyle>(
IRegistrationBuilder<TLimit, TActivatorData, TStyle> builder,
IEnumerable<Service> interceptorServices,
string metadataKey)
{
object existing;
if (builder.RegistrationData.Metadata.TryGetValue(metadataKey, out existing))
{
builder.RegistrationData.Metadata[metadataKey] =
((IEnumerable<Service>)existing).Concat(interceptorServices).Distinct();
}
else
{
builder.RegistrationData.Metadata.Add(metadataKey, interceptorServices);
}
}

private static IEnumerable<Service> GetInterceptorServices(IComponentRegistration registration, Type implType)
{
if (registration == null)
Expand All @@ -435,22 +447,28 @@ private static IEnumerable<Service> GetInterceptorServices(IComponentRegistratio
result = result.Concat((IEnumerable<Service>)services);
}

return registration.Metadata.TryGetValue(AttributeInterceptorsPropertyName, out services)
? result.Concat((IEnumerable<Service>)services)
: result.Concat(GetInterceptorServicesFromAttributes(implType));
}

private static IEnumerable<Service> GetInterceptorServicesFromAttributes(Type implType)
{
var implTypeInfo = implType.GetTypeInfo();
if (implTypeInfo.IsClass)
{
result = result.Concat(implTypeInfo
.GetCustomAttributes(typeof(InterceptAttribute), true)
.Cast<InterceptAttribute>()
.Select(att => att.InterceptorService));
if (!implTypeInfo.IsClass) return Enumerable.Empty<Service>();

result = result.Concat(implType
.GetInterfaces()
.SelectMany(i => i.GetTypeInfo().GetCustomAttributes(typeof(InterceptAttribute), true))
.Cast<InterceptAttribute>()
.Select(att => att.InterceptorService));
}
var classAttributeServices = implTypeInfo
.GetCustomAttributes(typeof(InterceptAttribute), true)
.Cast<InterceptAttribute>()
.Select(att => att.InterceptorService);

var interfaceAttributeServices = implType
.GetInterfaces()
.SelectMany(i => i.GetTypeInfo().GetCustomAttributes(typeof(InterceptAttribute), true))
.Cast<InterceptAttribute>()
.Select(att => att.InterceptorService);

return result.ToArray();
return classAttributeServices.Concat(interfaceAttributeServices);
}
}
}
2 changes: 1 addition & 1 deletion src/Autofac.Extras.DynamicProxy/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@
"dependencyinjection"
]
},
"version": "4.2.0-*"
"version": "4.2.1-*"
}

0 comments on commit d612783

Please sign in to comment.