dotnetcore / AspectCore-Framework

AspectCore is an AOP-based cross platform framework for .NET Standard.
MIT License
1.68k stars 319 forks source link

使用aspectCore做SqlSugar的事务拦截器,发现获取ISqlSugarClient对象变了 #303

Open my6521 opened 1 year ago

my6521 commented 1 year ago

问题描述: 使用aspectCore做SqlSugar的事务拦截器,发现获取ISqlSugarClient对象变了。 使用FromServiceContext或者 context.ServiceProvider.GetService()获取ISqlSugarClient的对象发生变化; SqlSugarClient是AsyncLocal共享存储,发生线程变化就会重新对象,一般Task.Run开启线程才会发生变化呀

注入方式:

services.AddSingleton<ISqlSugarClient>()
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class TransactionAopAttribute : AbstractInterceptorAttribute
{
    [FromServiceContext]
    public ILogger<TransactionAopAttribute> Logger { get; set; }

    [FromServiceContext]
    public ISqlSugarClient SqlSugarClient { get; set; }

    public string Name { get; set; }
    public IsolationLevel Level { get; set; } = IsolationLevel.Unspecified;

    public override async Task Invoke(AspectContext context, AspectDelegate next)
    {
        // var sqlSugarClient = context.ServiceProvider.GetService<ISqlSugarClient>();

        Console.WriteLine($"{Name}:{SqlSugarClient.ContextID}");

        var notTran = SqlSugarClient.Ado.IsNoTran();
        if (!notTran)
        {
            await next.Invoke(context);
            return;
        }

        try
        {
            await SqlSugarClient.Ado.BeginTranAsync(Level);
            await next(context);
            await SqlSugarClient.Ado.CommitTranAsync();
        }
        catch
        {
            await SqlSugarClient.Ado.RollbackTranAsync();

            throw;
        }
    }
}
    public interface ITestService
    {
        Task Say();
    }

    public class TestService : ITestService, IScopedDependency
    {
        private readonly ISqlSugarClient _sqlSugarClient;

        public TestService(ISqlSugarClient sqlSugarClient)
        {
            _sqlSugarClient = sqlSugarClient;
        }

        [TransactionAop(Name = "TestService=>AOP")]
        public virtual Task Say()
        {
            Console.WriteLine($"TestService=>Say:{_sqlSugarClient.ContextID}");

            return Task.CompletedTask;
        }
    }
  private readonly ITestService _testService;

    public DelayRefundJob(ITestService testService)
    {
        _testService = testService;
    }

    //[TransactionAop(Name = "Execute")]
    public virtual async Task Execute()
    {
        await _testService.Say();

        await Task.Delay(1000);

        Console.WriteLine("========================");

        await _testService.Say();
}

两次调用 _testService.Say() ContextId居然不一致。如果把AOP特性去掉,ContextID是一致的

liuhaoyang commented 1 year ago

拦截器本身是异步的。ISqlSugarClient 建议使用单例或者scoped吧

my6521 commented 1 year ago

用了拦截器相当于就开了新的异步,对于每个await内部相当于是独立线程了