Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

当调用未被代理的方法且类的访问级别不是 public 时出错 #274

Open
devenliu opened this issue Oct 22, 2021 · 3 comments
Open

Comments

@devenliu
Copy link

devenliu commented Oct 22, 2021

代码

/*********************
* 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:

  1. 通过构造函数获取 ICustomService 的实例
  2. 调用 ICustomService.Todo1()
  3. 结果:正确运行

用例2(导致了错误):

  1. 通过构造函数获取 ICustomService 的实例
  2. 调用 ICustomService.Todo2()
  3. 结果:无法访问方法,报错 System.MethodAccessException

问题

  1. 这是一个 bug 吗?
  2. 是我的用法不对吗?
@devenliu devenliu changed the title 当 interface 的实现类访问级别不是 public 时出错 当调用未被代理的方法且类的访问级别不是 public 时出错 Oct 22, 2021
@devenliu
Copy link
Author

当访问被代理的方法时,正确运行;
当访问未被代理的方法时,抛出错误,但如果我将实现类设置为 public,它又正确运行了。

@devenliu
Copy link
Author

目前我的方案:

// 为以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)); ;
    }
}

@liuhaoyang
Copy link
Member

从外部程序集调用internal 函数是会报System.MethodAccessException异常的。。打了拦截器不会报异常的原因是这个地方会生成一个public的代理函数...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants