Skip to content

Commit

Permalink
add interceptor and dynamicProxy support for LightInject (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
月光双刀 authored and liuhaoyang committed Feb 2, 2019
1 parent f6b67cf commit 5138fe4
Show file tree
Hide file tree
Showing 10 changed files with 624 additions and 2 deletions.
18 changes: 16 additions & 2 deletions extras/AspectCore.Extras.sln
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspectCore.Extensions.DataA
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspectCore.Extensions.DependencyInjection.ConsoleSample", "sample\AspectCore.Extensions.DependencyInjection.ConsoleSample\AspectCore.Extensions.DependencyInjection.ConsoleSample.csproj", "{EBCFF74A-4787-4A3E-A83D-0DC0329CFD2E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspectCore.Extensions.Hosting", "src\AspectCore.Extensions.Hosting\AspectCore.Extensions.Hosting.csproj", "{96DC1BED-E5E0-4E68-AF04-05115BE39B7A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspectCore.Extensions.Hosting", "src\AspectCore.Extensions.Hosting\AspectCore.Extensions.Hosting.csproj", "{96DC1BED-E5E0-4E68-AF04-05115BE39B7A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspectCore.Extensions.Hosting.Tests", "test\AspectCore.Extensions.Hosting.Tests\AspectCore.Extensions.Hosting.Tests.csproj", "{9547A839-70F0-4FAA-B574-9A61082FE567}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspectCore.Extensions.Hosting.Tests", "test\AspectCore.Extensions.Hosting.Tests\AspectCore.Extensions.Hosting.Tests.csproj", "{9547A839-70F0-4FAA-B574-9A61082FE567}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspectCore.Extensions.LightInject", "src\AspectCore.Extensions.LightInject\AspectCore.Extensions.LightInject.csproj", "{E3973799-7370-4D17-882F-D48CFB8C10F3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspectCore.Extensions.LightInject.Test", "test\AspectCore.Extensions.LightInject.Test\AspectCore.Extensions.LightInject.Test.csproj", "{8E8A9BBB-0168-4A90-9477-FF2C325ECDCB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -125,6 +129,14 @@ Global
{9547A839-70F0-4FAA-B574-9A61082FE567}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9547A839-70F0-4FAA-B574-9A61082FE567}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9547A839-70F0-4FAA-B574-9A61082FE567}.Release|Any CPU.Build.0 = Release|Any CPU
{E3973799-7370-4D17-882F-D48CFB8C10F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E3973799-7370-4D17-882F-D48CFB8C10F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3973799-7370-4D17-882F-D48CFB8C10F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3973799-7370-4D17-882F-D48CFB8C10F3}.Release|Any CPU.Build.0 = Release|Any CPU
{8E8A9BBB-0168-4A90-9477-FF2C325ECDCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E8A9BBB-0168-4A90-9477-FF2C325ECDCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E8A9BBB-0168-4A90-9477-FF2C325ECDCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E8A9BBB-0168-4A90-9477-FF2C325ECDCB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -148,6 +160,8 @@ Global
{EBCFF74A-4787-4A3E-A83D-0DC0329CFD2E} = {E933A059-A6AC-46AC-928D-33656D7FE93A}
{96DC1BED-E5E0-4E68-AF04-05115BE39B7A} = {EF35FB72-D934-45A8-9856-E60EA2623135}
{9547A839-70F0-4FAA-B574-9A61082FE567} = {BA3DCC4B-D8B9-4761-AAD9-4B1363140049}
{E3973799-7370-4D17-882F-D48CFB8C10F3} = {EF35FB72-D934-45A8-9856-E60EA2623135}
{8E8A9BBB-0168-4A90-9477-FF2C325ECDCB} = {BA3DCC4B-D8B9-4761-AAD9-4B1363140049}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B7A2B7A3-2AF0-4769-8E22-4FAA41E80591}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\..\..\build\common.props" />

<PropertyGroup>
<Description>Interceptor and dynamicProxy support for LightInject via AspectCore Framework.</Description>
<PackageTags>DynamicProxy;Aop;LightInject;AspectCore</PackageTags>
<PackageReleaseNotes>Interceptor and dynamicProxy support for LightInject via AspectCore Framework.</PackageReleaseNotes>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LightInject" Version="5.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\core\src\AspectCore.Core\AspectCore.Core.csproj" />
</ItemGroup>
</Project>

Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using AspectCore.Configuration;
using AspectCore.DynamicProxy;
using AspectCore.DynamicProxy.Parameters;
using AspectCore.Injector;
using LightInject;
using IServiceContainer = LightInject.IServiceContainer;

namespace AspectCore.Extensions.LightInject
{
public enum RegistryType
{
ByType,
ByInstance,
ByFactory
}

public static class ContainerBuilderExtensions
{
private static readonly string[] _nonAspect =
{
"LightInject.*",
"LightInject"
};

private static readonly string[] _excepts = new[]
{
"Microsoft.Extensions.Logging",
"Microsoft.Extensions.Options",
"System",
"System.*",
"IHttpContextAccessor",
"ITelemetryInitializer",
"IHostingEnvironment",
}.Concat(_nonAspect).ToArray();

public static IServiceContainer RegisterDynamicProxy(this IServiceContainer container,
IAspectConfiguration aspectConfig = null,
Action<IAspectConfiguration> configure = null)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
aspectConfig = aspectConfig ?? new AspectConfiguration();

foreach (var m in _nonAspect)
{
aspectConfig.NonAspectPredicates.AddNamespace(m);
}

configure?.Invoke(aspectConfig);

container.RegisterInstance<IAspectConfiguration>(aspectConfig)
.Register(typeof(IManyEnumerable<>), typeof(ManyEnumerable<>))
.RegisterInstance<IServiceContainer>(container)
.Register<IServiceProvider, LightInjectServiceResolver>()
.Register<IServiceResolver, LightInjectServiceResolver>()
.Register<IAspectContextFactory, AspectContextFactory>()
.Register<IAspectActivatorFactory, AspectActivatorFactory>()
.Register<IProxyGenerator, ProxyGenerator>()
.Register<IParameterInterceptorSelector, ParameterInterceptorSelector>()
.Register<IPropertyInjectorFactory, PropertyInjectorFactory>()
.Register<IInterceptorCollector, InterceptorCollector>()
.Register<IInterceptorSelector, ConfigureInterceptorSelector>()
.Register<IInterceptorSelector, AttributeInterceptorSelector>()
.Register<IAdditionalInterceptorSelector, AttributeAdditionalInterceptorSelector>()
.Register<IAspectValidatorBuilder, AspectValidatorBuilder>()
.Register<IAspectBuilderFactory, AspectBuilderFactory>()
.Register<IProxyTypeGenerator, ProxyTypeGenerator>()
.Register<IAspectCachingProvider, AspectCachingProvider>()
.Register<IAspectExceptionWrapper, AspectExceptionWrapper>();

container.Decorate(aspectConfig.CreateDecorator());

return container;
}

private static RegistryType GetRegistryType(this ServiceRegistration registration)
{
if (registration.FactoryExpression != null) return RegistryType.ByFactory;
else if (registration.Value != null) return RegistryType.ByInstance;
else return RegistryType.ByType;
}

private static Type GetImplType(this ServiceRegistration registration)
{
switch (registration.GetRegistryType())
{
case RegistryType.ByType: return registration.ImplementingType;
case RegistryType.ByInstance: return registration.Value.GetType();
case RegistryType.ByFactory: return registration.FactoryExpression.Method.ReturnType;
default: throw new ArgumentOutOfRangeException();
}
}

private static DecoratorRegistration CreateDecorator(this IAspectConfiguration aspectConfiguration)
{
var reg = new DecoratorRegistration()
{
CanDecorate = s => CanDecorate(s, aspectConfiguration),
ImplementingTypeFactory = CreateProxyType
};
return reg;
}

private static Type CreateProxyType(IServiceFactory factory, ServiceRegistration registration)
{
var serviceType = registration.ServiceType.GetTypeInfo();
var implType = registration.GetImplType();
var proxyTypeGenerator = factory.GetInstance<IProxyTypeGenerator>();

if (serviceType.IsClass)
{
return proxyTypeGenerator.CreateClassProxyType(serviceType, implType);
}
else if (serviceType.IsGenericTypeDefinition)
{
return proxyTypeGenerator.CreateClassProxyType(implType, implType);
}
else
{
return proxyTypeGenerator.CreateInterfaceProxyType(serviceType, implType);
}
}

private static bool CanDecorate(ServiceRegistration registration, IAspectConfiguration aspectConfiguration)
{
var serviceType = registration.ServiceType.GetTypeInfo();
var implType = registration.GetImplType().GetTypeInfo();

if (implType.IsProxy() || !implType.CanInherited())
{
return false;
}
if (_excepts.Any(x => implType.Name.Matches(x)) || _excepts.Any(x => implType.Namespace.Matches(x)))
{
return false;
}
if (!serviceType.CanInherited() || serviceType.IsNonAspect())
{
return false;
}

var aspectValidator = new AspectValidatorBuilder(aspectConfiguration).Build();
if (!aspectValidator.Validate(serviceType, true) && !aspectValidator.Validate(implType, false))
{
return false;
}
return true;
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
using AspectCore.DynamicProxy;
using AspectCore.Injector;
using LightInject;
using IServiceContainer = LightInject.IServiceContainer;

namespace AspectCore.Extensions.LightInject
{
[NonAspect]
internal class LightInjectServiceResolver : IServiceResolver
{
private readonly IServiceContainer _container;

public LightInjectServiceResolver(IServiceContainer container)
{
_container = container;
}

public object GetService(Type serviceType)
{
return _container.TryGetInstance(serviceType);
}

public void Dispose()
{
_container.Dispose();
}

public object Resolve(Type serviceType)
{
return _container.TryGetInstance(serviceType);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<DebugType>portable</DebugType>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\AspectCore.Extensions.LightInject\AspectCore.Extensions.LightInject.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Threading.Tasks;
using AspectCore.DynamicProxy;

namespace AspectCoreTest.LightInject
{
[AttributeUsage(AttributeTargets.Method)]
public class AsyncIncreamentAttribute : AbstractInterceptorAttribute
{
public override async Task Invoke(AspectContext context, AspectDelegate next)
{
await context.Invoke(next);
await Task.Delay(100); // 此处模拟一个真.异步方法,用于测试线程上下文切换

if (context.ReturnValue is Task<int> task)
{
var result = await task;
context.ReturnValue = Task.FromResult(result + 1);
}
else if (context.ReturnValue is ValueTask<int> valueTask)
{
var result = await valueTask;
context.ReturnValue = new ValueTask<int>(result + 1);
}
else if (context.ReturnValue is int result)
{
context.ReturnValue = result + 1;
}
}
}
}
Loading

0 comments on commit 5138fe4

Please sign in to comment.