AspectCore-Framework
AspectCore-Framework copied to clipboard
当调用未被代理的方法且类的访问级别不是 public 时出错
代码
/*********************
* MyWeb.csproj
**********************/
using AspectCore.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace MyWeb
{
// 启动类
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new DynamicProxyServiceProviderFactory()) // 替换 DI 工厂
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.ConfigureDynamicProxy(config =>
{
// 注册全局拦截器(只拦截被打了标记的方法)
config.Interceptors.AddTyped<TransactionalInterceptorAttribute>((MethodInfo method) => method.GetCustomAttribute<TransactionFlagAttribute>() != null);
})
}
}
}
/*********************
* MyLib.csproj
**********************/
// 定义标记
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class TransactionFlagAttribute: Attribute
{
}
// 定义拦截器
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class TransactionInterceptorAttribute : AbstractInterceptorAttribute
{
public override async Task Invoke(AspectContext context, AspectDelegate next)
{
// 启用事务...
await next(context);
// 提交事务...
}
}
// 定义服务
public interface ICustomService
{
// 给需要被代理的方法打上标记
[TransactionFlag]
void Todo1();
// 这是不需要被代理的方法
void Todo2();
}
// 服务的实现类,访问级别“程序集内部可见”
internal class MyInternalCustomService: ICustomService
{
// 实现服务方法1
public void Todo1()
{
//.....
}
// 实现服务方法2
public void Todo1()
{
//.....
}
}
重现
用例1:
- 通过构造函数获取
ICustomService
的实例 - 调用
ICustomService.Todo1()
- 结果:正确运行
用例2(导致了错误):
- 通过构造函数获取
ICustomService
的实例 - 调用
ICustomService.Todo2()
- 结果:无法访问方法,报错
System.MethodAccessException
问题
- 这是一个 bug 吗?
- 是我的用法不对吗?
当访问被代理的方法时,正确运行; 当访问未被代理的方法时,抛出错误,但如果我将实现类设置为 public,它又正确运行了。
目前我的方案:
// 为以Service结尾的服务启用拦截器
config.Interceptors.AddTyped<TransactionalInterceptorAttribute>(Predicates.ForService("*Service"));
// 修改拦截器逻辑
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class TransactionInterceptorAttribute : AbstractInterceptorAttribute
{
public override async Task Invoke(AspectContext context, AspectDelegate next)
{
// 增加条件
if (!CanApply(context))
{
await next.Invoke(context);
return;
}
// 启用事务...
await next(context);
// 提交事务...
}
private bool CanApply(AspectContext context)
{
return context.ProxyMethod.CustomAttributes.Any(x => x.AttributeType == typeof(TransactionalAttribute)); ;
}
}
从外部程序集调用internal 函数是会报System.MethodAccessException异常的。。打了拦截器不会报异常的原因是这个地方会生成一个public的代理函数...