Browse Source

Implemented interception for interface proxies.

pull/81/head
Halil İbrahim Kalkan 10 years ago
parent
commit
f939c1da77
  1. 7
      Volo.Abp.sln
  2. 2
      src/AbpDesk/AbpDesk.ConsoleDemo/AbpDesk/ConsoleDemo/Program.cs
  3. 24
      src/AbpDesk/AbpDesk.ConsoleDemo/AbpDesk/ConsoleDemo/TicketLister.cs
  4. 1
      src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj
  5. 95
      src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpAutofacServiceProviderFactory.cs
  6. 23
      src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj
  7. 20
      src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs
  8. 36
      src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs
  9. 13
      src/Volo.Abp/Microsoft/Extensions/DependencyInjection/IOnServiceRegistredArgs.cs
  10. 21
      src/Volo.Abp/Microsoft/Extensions/DependencyInjection/OnServiceRegistredArgs.cs
  11. 2
      src/Volo.Abp/Microsoft/Extensions/DependencyInjection/ServiceCollectionConventionalRegistrationExtensions.cs
  12. 30
      src/Volo.Abp/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs
  13. 17
      src/Volo.Abp/Volo/Abp/AbpKernelModule.cs
  14. 4
      src/Volo.Abp/Volo/Abp/DynamicProxy/IAbpMethodInvocation.cs
  15. 13
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInterceptor.cs
  16. 12
      src/Volo.Abp/Volo/DependencyInjection/AutoRegistrationHelper.cs
  17. 11
      src/Volo.Abp/Volo/DependencyInjection/ServiceRegistrationActionList.cs

7
Volo.Abp.sln

@ -108,6 +108,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Identity.HttpApi.C
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Autofac", "src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj", "{CECE1288-B5A1-4A6B-BEE0-331861F94983}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Autofac", "src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj", "{CECE1288-B5A1-4A6B-BEE0-331861F94983}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Castle.Core", "src\Volo.Abp.Castle.Core\Volo.Abp.Castle.Core.csproj", "{053F7446-0545-482E-9F29-9C96B926966C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -258,6 +260,10 @@ Global
{CECE1288-B5A1-4A6B-BEE0-331861F94983}.Debug|Any CPU.Build.0 = Debug|Any CPU {CECE1288-B5A1-4A6B-BEE0-331861F94983}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CECE1288-B5A1-4A6B-BEE0-331861F94983}.Release|Any CPU.ActiveCfg = Release|Any CPU {CECE1288-B5A1-4A6B-BEE0-331861F94983}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CECE1288-B5A1-4A6B-BEE0-331861F94983}.Release|Any CPU.Build.0 = Release|Any CPU {CECE1288-B5A1-4A6B-BEE0-331861F94983}.Release|Any CPU.Build.0 = Release|Any CPU
{053F7446-0545-482E-9F29-9C96B926966C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{053F7446-0545-482E-9F29-9C96B926966C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{053F7446-0545-482E-9F29-9C96B926966C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{053F7446-0545-482E-9F29-9C96B926966C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -308,5 +314,6 @@ Global
{17B14A48-5248-4F4C-A8E6-6926AA94EB7C} = {1895A5C9-50D4-4568-9A3A-14657E615A5E} {17B14A48-5248-4F4C-A8E6-6926AA94EB7C} = {1895A5C9-50D4-4568-9A3A-14657E615A5E}
{00B240B6-EC44-461A-9578-EF4F1BE9C688} = {1895A5C9-50D4-4568-9A3A-14657E615A5E} {00B240B6-EC44-461A-9578-EF4F1BE9C688} = {1895A5C9-50D4-4568-9A3A-14657E615A5E}
{CECE1288-B5A1-4A6B-BEE0-331861F94983} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8} {CECE1288-B5A1-4A6B-BEE0-331861F94983} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
{053F7446-0545-482E-9F29-9C96B926966C} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

2
src/AbpDesk/AbpDesk.ConsoleDemo/AbpDesk/ConsoleDemo/Program.cs

@ -48,7 +48,7 @@ namespace AbpDesk.ConsoleDemo
{ {
application application
.ServiceProvider .ServiceProvider
.GetRequiredService<TicketLister>() .GetRequiredService<TicketLister2>()
.List(); .List();
application application

24
src/AbpDesk/AbpDesk.ConsoleDemo/AbpDesk/ConsoleDemo/TicketLister.cs

@ -28,4 +28,28 @@ namespace AbpDesk.ConsoleDemo
} }
} }
} }
//Uses TicketAppService instead of ITicketAppService.
public class TicketLister2 : ITransientDependency
{
private readonly TicketAppService _ticketAppService;
public TicketLister2(TicketAppService ticketAppService)
{
_ticketAppService = ticketAppService;
}
public void List()
{
Console.WriteLine();
Console.WriteLine("List of tickets:");
var result = AsyncHelper.RunSync(() => _ticketAppService.GetAll(new GetAllTicketsInput()));
foreach (var ticket in result.Items)
{
Console.WriteLine(ticket);
}
}
}
} }

1
src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj

@ -18,6 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Volo.Abp.Castle.Core\Volo.Abp.Castle.Core.csproj" />
<ProjectReference Include="..\Volo.Abp\Volo.Abp.csproj" /> <ProjectReference Include="..\Volo.Abp\Volo.Abp.csproj" />
</ItemGroup> </ItemGroup>

95
src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpAutofacServiceProviderFactory.cs

@ -1,7 +1,13 @@
using System; using System;
using System.Linq;
using System.Reflection;
using Autofac; using Autofac;
using Autofac.Core;
using Autofac.Extensions.DependencyInjection; using Autofac.Extensions.DependencyInjection;
using Castle.DynamicProxy;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.DynamicProxy;
namespace Volo.Abp.Autofac namespace Volo.Abp.Autofac
{ {
@ -11,6 +17,7 @@ namespace Volo.Abp.Autofac
public class AbpAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder> public class AbpAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{ {
private readonly ContainerBuilder _builder; private readonly ContainerBuilder _builder;
private IServiceCollection _services;
public AbpAutofacServiceProviderFactory(ContainerBuilder builder) public AbpAutofacServiceProviderFactory(ContainerBuilder builder)
{ {
@ -24,7 +31,9 @@ namespace Volo.Abp.Autofac
/// <returns>A container builder that can be used to create an <see cref="T:System.IServiceProvider" />.</returns> /// <returns>A container builder that can be used to create an <see cref="T:System.IServiceProvider" />.</returns>
public ContainerBuilder CreateBuilder(IServiceCollection services) public ContainerBuilder CreateBuilder(IServiceCollection services)
{ {
AutofacRegistration.Populate(_builder, services); _services = services;
_builder.Populate(services);
return _builder; return _builder;
} }
@ -33,7 +42,91 @@ namespace Volo.Abp.Autofac
{ {
Check.NotNull(containerBuilder, nameof(containerBuilder)); Check.NotNull(containerBuilder, nameof(containerBuilder));
HandleRegistrationActions(containerBuilder);
return new AutofacServiceProvider(containerBuilder.Build()); return new AutofacServiceProvider(containerBuilder.Build());
} }
private static readonly ProxyGenerator _proxyGenerator = new ProxyGenerator();
private void HandleRegistrationActions(ContainerBuilder containerBuilder)
{
var registrationActions = _services.GetServiceRegistrationActionList();
containerBuilder.RegisterCallback(registry =>
{
foreach (var registration in registry.Registrations)
{
var registredArgs = new OnServiceRegistredArgs(registration.Activator.LimitType);
foreach (var registrationAction in registrationActions)
{
registrationAction(registredArgs);
}
registration.Preparing += (sender, args) =>
{
};
registration.Activating += (sender, args) =>
{
if (args.Component.Services.OfType<IServiceWithType>().Any(swt => !swt.ServiceType.GetTypeInfo().IsVisible) || args.Instance.GetType().Namespace.StartsWith("Castle.Proxies"))
{
return;
}
if (registredArgs.Interceptors.Any())
{
ApplyInterceptors(args, registredArgs);
}
};
}
});
}
private static void ApplyInterceptors(ActivatingEventArgs<object> args, OnServiceRegistredArgs registredArgs)
{
var mainService = args.Component.Services.OfType<IServiceWithType>().FirstOrDefault()?.ServiceType;
if (mainService == null)
{
return;
}
var interceptorInstances = registredArgs.Interceptors
.Select(i => (IInterceptor)new CastleAbpInterceptorAdapter((IAbpInterceptor)args.Context.Resolve(i)))
.ToArray();
if (mainService.GetTypeInfo().IsInterface)
{
args.ReplaceInstance(
_proxyGenerator
.CreateInterfaceProxyWithTargetInterface(
mainService,
args.Instance,
interceptorInstances
)
);
}
else
{
//var proxied = _proxyGenerator
// .CreateClassProxyWithTarget(
// mainService,
// args.Instance,
// interceptorInstances
// );
//args.ReplaceInstance(proxied);
//args.ReplaceInstance(
// _proxyGenerator
// .CreateClassProxyWithTarget(
// mainService,
// args.Instance,
// interceptorInstances
// )
//);
}
}
} }
} }

23
src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.6</TargetFramework>
<AssemblyName>Volo.Abp.Castle.Core</AssemblyName>
<PackageId>Volo.Abp.Castle.Core</PackageId>
<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50</PackageTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Castle.Core" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp\Volo.Abp.csproj" />
</ItemGroup>
</Project>

20
src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs

@ -0,0 +1,20 @@
using Castle.DynamicProxy;
using Volo.Abp.DynamicProxy;
namespace Volo.Abp.Castle.DynamicProxy
{
public class CastleAbpInterceptorAdapter : IInterceptor
{
private readonly IAbpInterceptor _abpInterceptor;
public CastleAbpInterceptorAdapter(IAbpInterceptor abpInterceptor)
{
_abpInterceptor = abpInterceptor;
}
public void Intercept(IInvocation invocation)
{
_abpInterceptor.Intercept(new CastleAbpMethodInvocationAdapter(invocation));
}
}
}

36
src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs

@ -0,0 +1,36 @@
using System;
using System.Reflection;
using Castle.DynamicProxy;
using Volo.Abp.DynamicProxy;
namespace Volo.Abp.Castle.DynamicProxy
{
public class CastleAbpMethodInvocationAdapter : IAbpMethodInvocation
{
public object[] Arguments => _invocation.Arguments;
public Type[] GenericArguments => _invocation.GenericArguments;
public object TargetObject => _invocation.InvocationTarget;
public MethodInfo Method => _invocation.MethodInvocationTarget;
public object ReturnValue
{
get => _invocation.ReturnValue;
set => _invocation.ReturnValue = value;
}
private readonly IInvocation _invocation;
public CastleAbpMethodInvocationAdapter(IInvocation invocation)
{
_invocation = invocation;
}
public void Proceed()
{
_invocation.Proceed();
}
}
}

13
src/Volo.Abp/Microsoft/Extensions/DependencyInjection/IOnServiceRegistredArgs.cs

@ -0,0 +1,13 @@
using System;
using Volo.Abp.Collections;
using Volo.Abp.DynamicProxy;
namespace Microsoft.Extensions.DependencyInjection
{
public interface IOnServiceRegistredArgs
{
ITypeList<IAbpInterceptor> Interceptors { get; }
Type ImplementationType { get; }
}
}

21
src/Volo.Abp/Microsoft/Extensions/DependencyInjection/OnServiceRegistredArgs.cs

@ -0,0 +1,21 @@
using System;
using Volo;
using Volo.Abp.Collections;
using Volo.Abp.DynamicProxy;
namespace Microsoft.Extensions.DependencyInjection
{
public class OnServiceRegistredArgs : IOnServiceRegistredArgs
{
public virtual ITypeList<IAbpInterceptor> Interceptors { get; }
public virtual Type ImplementationType { get; }
public OnServiceRegistredArgs(Type implementationType)
{
ImplementationType = Check.NotNull(implementationType, nameof(implementationType));
Interceptors = new TypeList<IAbpInterceptor>();
}
}
}

2
src/Volo.Abp/Microsoft/Extensions/DependencyInjection/ServiceCollectionConventionalRegistrationExtensions.cs

@ -18,7 +18,7 @@ namespace Microsoft.Extensions.DependencyInjection
return GetOrCreateRegistrarList(services); return GetOrCreateRegistrarList(services);
} }
private static List<IConventionalRegistrar> GetOrCreateRegistrarList(IServiceCollection services) private static ConventionalRegistrarList GetOrCreateRegistrarList(IServiceCollection services)
{ {
var conventionalRegistrars = services.GetSingletonInstanceOrNull<IObjectAccessor<ConventionalRegistrarList>>()?.Value; var conventionalRegistrars = services.GetSingletonInstanceOrNull<IObjectAccessor<ConventionalRegistrarList>>()?.Value;
if (conventionalRegistrars == null) if (conventionalRegistrars == null)

30
src/Volo.Abp/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs

@ -0,0 +1,30 @@
using System;
using Volo.DependencyInjection;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionRegistrationActionExtensions
{
public static void OnServiceRegistred(this IServiceCollection services, Action<IOnServiceRegistredArgs> registrationAction)
{
GetOrCreateServiceActionList(services).Add(registrationAction);
}
public static ServiceRegistrationActionList GetServiceRegistrationActionList(this IServiceCollection services)
{
return GetOrCreateServiceActionList(services);
}
private static ServiceRegistrationActionList GetOrCreateServiceActionList(IServiceCollection services)
{
var registrationActionList = services.GetSingletonInstanceOrNull<IObjectAccessor<ServiceRegistrationActionList>>()?.Value;
if (registrationActionList == null)
{
registrationActionList = new ServiceRegistrationActionList();
services.AddObjectAccessor(registrationActionList);
}
return registrationActionList;
}
}
}

17
src/Volo.Abp/Volo/Abp/AbpKernelModule.cs

@ -1,12 +1,21 @@
using System; using System;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Uow;
using Volo.DependencyInjection; using Volo.DependencyInjection;
namespace Volo.Abp namespace Volo.Abp
{ {
public class AbpKernelModule : AbpModule public class AbpKernelModule : AbpModule
{ {
public override void PreConfigureServices(IServiceCollection services)
{
services.OnServiceRegistred(registration => { RegisterUnitOfWorkInterceptor(registration); });
}
public override void ConfigureServices(IServiceCollection services) public override void ConfigureServices(IServiceCollection services)
{ {
services.AddOptions(); services.AddOptions();
@ -21,5 +30,13 @@ namespace Volo.Abp
{ {
context.ServiceProvider.GetRequiredService<ObjectAccessor<IServiceProvider>>().Value = context.ServiceProvider; context.ServiceProvider.GetRequiredService<ObjectAccessor<IServiceProvider>>().Value = context.ServiceProvider;
} }
private static void RegisterUnitOfWorkInterceptor(IOnServiceRegistredArgs registration)
{
if (typeof(IApplicationService).GetTypeInfo().IsAssignableFrom(registration.ImplementationType))
{
registration.Interceptors.Add<UnitOfWorkInterceptor>();
}
}
} }
} }

4
src/Volo.Abp/Volo/Abp/DynamicProxy/IAbpMethodInvocation.cs

@ -9,9 +9,9 @@ namespace Volo.Abp.DynamicProxy
Type[] GenericArguments { get; } Type[] GenericArguments { get; }
object InvocationTarget { get; } object TargetObject { get; }
MethodInfo MethodInvocationTarget { get; } MethodInfo Method { get; }
object ReturnValue { get; set; } object ReturnValue { get; set; }

13
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInterceptor.cs

@ -0,0 +1,13 @@
using Volo.Abp.DynamicProxy;
using Volo.DependencyInjection;
namespace Volo.Abp.Uow
{
public class UnitOfWorkInterceptor : IAbpInterceptor, ITransientDependency
{
public void Intercept(IAbpMethodInvocation invocation)
{
invocation.Proceed();
}
}
}

12
src/Volo.Abp/Volo/DependencyInjection/AutoRegistrationHelper.cs

@ -26,15 +26,19 @@ namespace Volo.DependencyInjection
return GetDefaultExposedServices(type); return GetDefaultExposedServices(type);
} }
public static IEnumerable<Type> GetDefaultExposedServices(Type type) public static IEnumerable<Type> GetDefaultExposedServices(Type type, bool includeSelf = true)
{ {
var typeInfo = type.GetTypeInfo(); var serviceTypes = new List<Type>();
var serviceTypes = new List<Type> { type }; if (includeSelf)
{
serviceTypes.Add(type);
}
foreach (var interfaceType in typeInfo.GetInterfaces()) foreach (var interfaceType in type.GetTypeInfo().GetInterfaces())
{ {
var interfaceName = interfaceType.Name; var interfaceName = interfaceType.Name;
if (interfaceName.StartsWith("I")) if (interfaceName.StartsWith("I"))
{ {
interfaceName = interfaceName.Right(interfaceName.Length - 1); interfaceName = interfaceName.Right(interfaceName.Length - 1);

11
src/Volo.Abp/Volo/DependencyInjection/ServiceRegistrationActionList.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.DependencyInjection
{
public class ServiceRegistrationActionList : List<Action<IOnServiceRegistredArgs>>
{
}
}
Loading…
Cancel
Save