0
0
Эх сурвалжийг харах

修复事务不能使用嵌套异步方法的问题。

zhontai 4 жил өмнө
parent
commit
c57820ba47

+ 1 - 0
Admin.Core/Admin.Core.csproj

@@ -49,6 +49,7 @@
     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" />
     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" />
     <PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.0" />
     <PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.0" />
     <PackageReference Include="Caching.CSRedis" Version="3.6.60" />
     <PackageReference Include="Caching.CSRedis" Version="3.6.60" />
+    <PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.0.0" />
     <PackageReference Include="FluentValidation.AspNetCore" Version="9.5.2" />
     <PackageReference Include="FluentValidation.AspNetCore" Version="9.5.2" />
     <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
     <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.4" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.4" />

+ 13 - 0
Admin.Core/Admin.Core.xml

@@ -4,6 +4,19 @@
         <name>Admin.Core</name>
         <name>Admin.Core</name>
     </assembly>
     </assembly>
     <members>
     <members>
+        <member name="M:Admin.Core.Aop.TransactionAsyncInterceptor.InterceptSynchronous(Castle.DynamicProxy.IInvocation)">
+            <summary>
+            拦截同步执行的方法
+            </summary>
+            <param name="invocation"></param>
+        </member>
+        <member name="M:Admin.Core.Aop.TransactionAsyncInterceptor.InterceptAsynchronous(Castle.DynamicProxy.IInvocation)">
+            <summary>
+            拦截返回结果为Task的方法
+            </summary>
+            <param name="invocation"></param>
+        </member>
+        <!-- Badly formed XML comment ignored for member "M:Admin.Core.Aop.TransactionAsyncInterceptor.InterceptAsynchronous``1(Castle.DynamicProxy.IInvocation)" -->
         <member name="T:Admin.Core.Attributes.LoginAttribute">
         <member name="T:Admin.Core.Attributes.LoginAttribute">
             <summary>
             <summary>
             启用登录
             启用登录

+ 154 - 0
Admin.Core/Aop/TransactionAsyncInterceptor.cs

@@ -0,0 +1,154 @@
+using System.Threading.Tasks;
+using Castle.DynamicProxy;
+using FreeSql;
+using Admin.Core.Common.Extensions;
+using Admin.Core.Common.Output;
+using Admin.Core.Common.Attributes;
+using Admin.Core.Repository;
+using System.Linq;
+
+namespace Admin.Core.Aop
+{
+    public class TransactionAsyncInterceptor : IAsyncInterceptor
+    {
+        IUnitOfWork _unitOfWork;
+        private readonly MyUnitOfWorkManager _unitOfWorkManager;
+
+        public TransactionAsyncInterceptor(MyUnitOfWorkManager unitOfWorkManager)
+        {
+            _unitOfWorkManager = unitOfWorkManager;
+        }
+
+        private bool TryBegin(IInvocation invocation)
+        {
+            var method = invocation.MethodInvocationTarget ?? invocation.Method;
+            var attribute = method.GetCustomAttributes(typeof(TransactionAttribute), false).FirstOrDefault();
+            if (attribute is TransactionAttribute transaction)
+            {
+                _unitOfWork = _unitOfWorkManager.Begin(transaction.Propagation, transaction.IsolationLevel);
+                return true;
+            }
+
+            return false;
+        }
+
+        private async Task InternalInterceptAsynchronous(IInvocation invocation)
+        {
+            //string methodName =
+            //    $"{invocation.MethodInvocationTarget.DeclaringType?.FullName}.{invocation.Method.Name}()";
+            //int? hashCode = _unitOfWork.GetHashCode();
+
+            invocation.Proceed();
+
+            try
+            {
+                //处理Task返回一个null值的情况会导致空指针
+                if (invocation.ReturnValue != null)
+                {
+                    await (Task)invocation.ReturnValue;
+                }
+                _unitOfWork.Commit();
+            }
+            catch (System.Exception)
+            {
+                _unitOfWork.Rollback();
+                throw;
+            }
+            finally
+            {
+                _unitOfWork.Dispose();
+            }
+        }
+
+        private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation)
+        {
+            TResult result;
+            if (TryBegin(invocation))
+            {
+                try
+                {
+                    invocation.Proceed();
+                    result = await (Task<TResult>)invocation.ReturnValue;
+                    if (result is IResponseOutput res && !res.Success)
+                    {
+                        _unitOfWork.Rollback();
+                    }
+                    else
+                    {
+                        _unitOfWork.Commit();
+                    }
+                }
+                catch (System.Exception)
+                {
+                    _unitOfWork.Rollback();
+                    throw;
+                }
+                finally
+                {
+                    _unitOfWork.Dispose();
+                }
+            }
+            else
+            {
+                invocation.Proceed();
+                result = await (Task<TResult>)invocation.ReturnValue;
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 拦截同步执行的方法
+        /// </summary>
+        /// <param name="invocation"></param>
+        public void InterceptSynchronous(IInvocation invocation)
+        {
+            if (TryBegin(invocation))
+            {
+                try
+                {
+                    invocation.Proceed();
+                    _unitOfWork.Commit();
+                }
+                catch
+                {
+                    _unitOfWork.Rollback();
+                    throw;
+                }
+                finally
+                {
+                    _unitOfWork.Dispose();
+                }
+            }
+            else
+            {
+                invocation.Proceed();
+            }
+        }
+
+        /// <summary>
+        /// 拦截返回结果为Task的方法
+        /// </summary>
+        /// <param name="invocation"></param>
+        public void InterceptAsynchronous(IInvocation invocation)
+        {
+            if (TryBegin(invocation))
+            {
+                invocation.ReturnValue = InternalInterceptAsynchronous(invocation);
+            }
+            else
+            {
+                invocation.Proceed();
+            }
+        }
+
+        /// <summary>
+        /// 拦截返回结果为Task<TResult>的方法
+        /// </summary>
+        /// <typeparam name="TResult"></typeparam>
+        /// <param name="invocation"></param>
+        public void InterceptAsynchronous<TResult>(IInvocation invocation)
+        {
+            invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation);
+        }
+    }
+}

+ 6 - 56
Admin.Core/Aop/TransactionInterceptor.cs

@@ -1,69 +1,19 @@
-using System.Reflection;
-using System.Threading.Tasks;
-using Castle.DynamicProxy;
-using FreeSql;
-using Admin.Core.Common.Extensions;
-using Admin.Core.Common.Output;
-using Admin.Core.Common.Attributes;
-using Admin.Core.Repository;
+using Castle.DynamicProxy;
 
 
 namespace Admin.Core.Aop
 namespace Admin.Core.Aop
 {
 {
     public class TransactionInterceptor : IInterceptor
     public class TransactionInterceptor : IInterceptor
     {
     {
-        IUnitOfWork _unitOfWork;
-        private readonly MyUnitOfWorkManager _unitOfWorkManager;
-        
-        public TransactionInterceptor(MyUnitOfWorkManager unitOfWorkManager)
+        private readonly TransactionAsyncInterceptor _transactionAsyncInterceptor;
+
+        public TransactionInterceptor(TransactionAsyncInterceptor transactionAsyncInterceptor)
         {
         {
-            _unitOfWorkManager = unitOfWorkManager;
+            _transactionAsyncInterceptor = transactionAsyncInterceptor;
         }
         }
 
 
         public void Intercept(IInvocation invocation)
         public void Intercept(IInvocation invocation)
         {
         {
-            var method = invocation.MethodInvocationTarget ?? invocation.Method;
-            if (method.HasAttribute<TransactionAttribute>())
-            {
-                InterceptTransaction(invocation, method);
-            }
-            else
-            {
-                invocation.Proceed();
-            }
-        }
-
-        private async void InterceptTransaction(IInvocation invocation, MethodInfo method)
-        {
-            try
-            {
-                var transaction = method.GetAttribute<TransactionAttribute>();
-                _unitOfWork = _unitOfWorkManager.Begin(transaction.Propagation, transaction.IsolationLevel);
-                invocation.Proceed();
-
-                dynamic returnValue = invocation.ReturnValue;
-                if (returnValue is Task)
-                {
-                    returnValue = await returnValue;
-                }
-
-                if (returnValue is IResponseOutput res && !res.Success)
-                {
-                    _unitOfWork.Rollback();
-                }
-                else
-                {
-                    _unitOfWork.Commit();
-                }
-            }
-            catch
-            {
-                _unitOfWork.Rollback();
-            }
-            finally
-            {
-                _unitOfWork.Dispose();
-            }
+            _transactionAsyncInterceptor.ToInterceptor().Intercept(invocation);
         }
         }
     }
     }
-
 }
 }

+ 7 - 4
Admin.Core/Startup.cs

@@ -353,6 +353,7 @@ namespace Admin.Core
                 if (_appConfig.Aop.Transaction)
                 if (_appConfig.Aop.Transaction)
                 {
                 {
                     builder.RegisterType<TransactionInterceptor>();
                     builder.RegisterType<TransactionInterceptor>();
+                    builder.RegisterType<TransactionAsyncInterceptor>();
                     interceptorServiceTypes.Add(typeof(TransactionInterceptor));
                     interceptorServiceTypes.Add(typeof(TransactionInterceptor));
                 }
                 }
                 #endregion
                 #endregion
@@ -361,16 +362,18 @@ namespace Admin.Core
                 var assemblyRepository = Assembly.Load("Admin.Core.Repository");
                 var assemblyRepository = Assembly.Load("Admin.Core.Repository");
                 builder.RegisterAssemblyTypes(assemblyRepository)
                 builder.RegisterAssemblyTypes(assemblyRepository)
                 .AsImplementedInterfaces()
                 .AsImplementedInterfaces()
-                .InstancePerDependency();
+                .InstancePerLifetimeScope()
+                .PropertiesAutowired();// 属性注入
                 #endregion
                 #endregion
 
 
                 #region Service
                 #region Service
                 var assemblyServices = Assembly.Load("Admin.Core.Service");
                 var assemblyServices = Assembly.Load("Admin.Core.Service");
                 builder.RegisterAssemblyTypes(assemblyServices)
                 builder.RegisterAssemblyTypes(assemblyServices)
                 .AsImplementedInterfaces()
                 .AsImplementedInterfaces()
-                .InstancePerDependency()
-                .EnableInterfaceInterceptors()
-                .InterceptedBy(interceptorServiceTypes.ToArray());
+                .InstancePerLifetimeScope()
+                .PropertiesAutowired()// 属性注入
+                .InterceptedBy(interceptorServiceTypes.ToArray())
+                .EnableInterfaceInterceptors();
                 #endregion
                 #endregion
             }
             }
             catch (Exception ex)
             catch (Exception ex)