AspNetCore AOP
前言
AOP。。。
1.基础知识
AOP是对OOP的一种补充,即面向切面编程,一种编程思想。
AOP的优势是面向切面编程,每个切面负责独立的系统逻辑,降低代码的复杂度,提高代码的复用率。可以随意调整顺序,随意插拔。用于对业务逻辑进行增强。面向切面编程可以使得系统逻辑和业务逻辑进行分离。
系统逻辑:比如身份认证,异常处理,参数校验
业务逻辑:就是我们真正关心不得不写的业务逻辑。
new AOPDemo().Method1();
Console.ReadKey();
public class AOPDemo
{
public void Method1()
{
try
{
Console.WriteLine(1);
Method2();
Console.WriteLine(4);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public void Method2()
{
Console.WriteLine(2);
Method3();
Console.WriteLine(3);
}
public void Method3()
{
Console.WriteLine("OK!!!!!");
}
}
2.静态代理
假设我们需要实现一个IList接口,我们知道IList接口有很多方法,实现成本非常高。我们可以通过代理模式来实现
代理模式可以降低实现的成本,还可以对目标对象进行加强。代理者不需要实现具体的业务逻辑,只需要编写加强逻辑即可。
2.1IEnumerable
using System.Collections;
var target = new List<object>();
var collection = new MyEnumerable(target);
var it = collection.GetEnumerator();
Console.WriteLine("Hello, World!");
Console.ReadKey();
class MyEnumerable : IEnumerable<object>
{
private IEnumerable<object> _target;
public MyEnumerable(IEnumerable<object> target)
{
_target = target;
}
public IEnumerator<object> GetEnumerator()
{
// 调用GetEnumerator之前可以增加逻辑
Console.WriteLine("调用迭代器了!!!");
// 通过target来实现,代理类之关系加强逻辑,不关心接口实现
return _target.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_target).GetEnumerator();
}
}
2.2IWater
可以看到系统逻辑和业务逻辑进行了分离,系统逻辑写到了不同的切面。切面之间何以随意组合,增减。这就是AOP思想的一种呈现方式。
静态代理的本质是子类继承父类,或者实现接口,对目标对象进行增强。
静态代理的弊端是只能实现一个接口(标准),无法代理其他类型的实列。他的切面的可复用率有限,限定在它实现的接口。
var target = new Water();
var proxy1 = new WaterProxy1(target);
var proxy2 = new WaterProxy2(proxy1);
proxy2.Invoke();
// 可以调换执行顺序
//var target = new Water();
//var proxy2 = new WaterProxy2(target);
//var proxy1 = new WaterProxy1(proxy2);
//proxy2.Invoke();
public interface IWater { void Invoke(); }
public class Water : IWater
{
public void Invoke()
{
//业务逻辑
Console.WriteLine("水已经净化了");
}
}
public class WaterProxy1 : IWater
{
private readonly IWater _target;
public WaterProxy1(IWater target)
{
_target = target;
}
public void Invoke()
{
Console.WriteLine("开始消毒杀菌");//系统逻辑
_target.Invoke();
Console.WriteLine("完成消毒杀菌");//系统逻辑
}
}
public class WaterProxy2 : IWater
{
private readonly IWater _target;
public WaterProxy2(IWater target)
{
_target = target;
}
public void Invoke()
{
Console.WriteLine("开始去除杂质");//系统逻辑
_target.Invoke();
Console.WriteLine("完成去除杂质");//系统逻辑
}
}
3.管道模式
3.1实现
AspNetCore管道核心代码
var buidler = new ApplicationBuilder();
buidler.Use(next =>
{
return async context =>
{
Console.WriteLine("清理杂质1");
await next(context);
Console.WriteLine("清理杂质2");
};
});
buidler.Use(next =>
{
return async context =>
{
Console.WriteLine("杀菌消毒1");
await next(context);
Console.WriteLine("杀菌消毒2");
};
});
buidler.Use(next =>
{
return async context =>
{
Console.WriteLine("水已净化");
};
});
var app = buidler.Build();
app(new HttpContext());
Console.WriteLine("Hello, World!");
Console.ReadKey();
public class HttpContext
{
// 请求参数
public string Request { get; set; }
// 响应数据
public string Response { get; set; }
}
// 定义一个委托
public delegate Task RequestDelegate(HttpContext context);
public class ApplicationBuilder
{
private readonly List<Func<RequestDelegate, RequestDelegate>> _components = new();
public void Use(Func<RequestDelegate, RequestDelegate> middleware)
{
_components.Add(middleware);
}
public RequestDelegate Build()
{
RequestDelegate app = context =>
{
throw new InvalidOperationException("无效的管道!");
};
for (int i = _components.Count - 1; i > -1; i--)
{
app = _components[i](app);
}
return app;
}
}
3.2优化
var buidler = new ApplicationBuilder();
buidler.Use(async (context, next) =>
{
Console.WriteLine("杀菌消毒1");
await next();
Console.WriteLine("杀菌消毒2");
});
buidler.Use(async (context, next) =>
{
Console.WriteLine("清理杂质1");
await next();
Console.WriteLine("清理杂质2");
});
buidler.Run(context =>
{
Console.WriteLine("水已净化");
return Task.CompletedTask;
});
var app = buidler.Build();
await app(new HttpContext());
public class HttpContext
{
// 请求参数
public string Request { get; set; }
// 响应数据
public string Response { get; set; }
}
// 定义一个委托
public delegate Task RequestDelegate(HttpContext context);
public class ApplicationBuilder
{
private readonly List<Func<RequestDelegate, RequestDelegate>> _components = new();
#region
public void Use(Func<RequestDelegate, RequestDelegate> middleware)
{
_components.Add(middleware);
}
public void Use(Func<HttpContext, Func<Task>, Task> middleware)
{
_components.Add(next =>
{
//RequestDelegate rd = async context =>
//{
// await middleware(context, () => next(context));
//};
//return rd;
return async context =>
{
await middleware(context, () => next(context));
};
});
}
public void Run(Func<HttpContext, Task> middleware)
{
// _:丢弃语法
_components.Add(_ =>
{
return async context =>
{
await middleware(context);
};
});
}
public RequestDelegate Build()
{
RequestDelegate app = context =>
{
throw new InvalidOperationException("无效的管道!");
};
for (int i = _components.Count - 1; i > -1; i--)
{
app = _components[i](app);
}
return app;
}
#endregion
}
4.模版方法
模版方法比较简单,类似if else。
var context = new HttpContext()
{
Method = "GET"
};
IServlet servlet = new HelloServlet();
await servlet.InvokeAsync(context);
public class HttpContext
{
public string Request { get; set; }
public string Response { get; set; }
public string Method { get; set; }
}
public interface IServlet
{
Task InvokeAsync(HttpContext context);
}
public abstract class HttpServlet : IServlet
{
public async Task InvokeAsync(HttpContext context)
{
if (context.Method == "GET")
{
await GetAsync(context);
}
else if (context.Method == "POST")
{
await PostAsync(context);
}
else
{
throw new ArgumentException("请求方式错误!");
}
}
// 具体路线通过抽象方法由子类实现
public abstract Task GetAsync(HttpContext context);
public abstract Task PostAsync(HttpContext context);
}
public class HelloServlet : HttpServlet
{
public override Task GetAsync(HttpContext context)
{
Console.WriteLine("GET:Hello");
return Task.CompletedTask;
}
public override Task PostAsync(HttpContext context)
{
Console.WriteLine("POST:Hello");
return Task.CompletedTask;
}
}
5.链路器模式
请求类:
IChain:此接口主要是把过滤器和过滤器联系起来,保存下一个过滤器的执行
IFilter:执行当前过滤器
IServlet:请求到达具体执行的方法。
模版方法处理请求
WebHost核心代码:
递归处理filter:
代码:
using Microsoft.VisualBasic;
var host = new WebHost();
host.AddFilter(new Filter1());
host.AddFilter(new Filter2());
var servlet = new HelloServlet();
await host.ExecuteAsync(new HttpContext("GET"), servlet);
Console.ReadKey();
public class HttpContext
{
public string Method { get; }
public HttpContext(string method)
{
Method = method;
}
}
// 链路器
public interface IChain
{
Task NextAsync();
}
// 用于执行filter
public interface IFilter
{
Task InvokeAsync(HttpContext context, IChain chain);
}
// 执行请求
public interface IServlet
{
Task InvokeAsync(HttpContext context);
}
//适配Filter链路,用于执行Filter
public class FilterChain : IChain
{
private readonly IFilter _filter;
private readonly IChain _chain;
private readonly HttpContext _context;
public FilterChain(IFilter filter, HttpContext context, IChain chain)
{
_filter = filter;
_chain = chain;
_context = context;
}
public async Task NextAsync()
{
await _filter.InvokeAsync(_context, _chain);
}
}
//适配Filter链路,用于执行Servlet
public class ServletChain : IChain
{
private readonly IServlet _servlet;
private readonly HttpContext _context;
public ServletChain(IServlet servlet, HttpContext context)
{
_servlet = servlet;
_context = context;
}
public async Task NextAsync()
{
await _servlet.InvokeAsync(_context);
}
}
public class Filter1 : IFilter
{
public async Task InvokeAsync(HttpContext context, IChain chain)
{
Console.WriteLine("身份认证开始");
await chain.NextAsync();
Console.WriteLine("身份认证结束");
}
}
public class Filter2 : IFilter
{
public async Task InvokeAsync(HttpContext context, IChain chain)
{
Console.WriteLine("授权认证开始");
await chain.NextAsync();
Console.WriteLine("授权认证结束");
}
}
public abstract class HttpServlet : IServlet
{
public async Task InvokeAsync(HttpContext context)
{
if (context.Method == "GET")
{
await GetAsync(context);
}
else if (context.Method == "POST")
{
await PostAsync(context);
}
else
{
throw new ArgumentException("请求方式错误!");
}
}
public abstract Task GetAsync(HttpContext context);
public abstract Task PostAsync(HttpContext context);
}
public class HelloServlet : HttpServlet
{
public override Task GetAsync(HttpContext context)
{
Console.WriteLine("GET:Hello World");
return Task.CompletedTask;
}
public override Task PostAsync(HttpContext context)
{
Console.WriteLine("POST:Hello World");
return Task.CompletedTask;
}
}
public class WebHost
{
private readonly List<IFilter> _filters = new List<IFilter>();
public void AddFilter(IFilter filter)
{
_filters.Add(filter);
}
public async Task ExecuteAsync(HttpContext context, IServlet servlet)
{
if (_filters.Any())
{
var fileter = _filters[0];
var chain = GetFilterChain(context, servlet, _filters.ToArray(), 1);
await fileter.InvokeAsync(context, chain);
}
else
{
await servlet.InvokeAsync(context);
}
}
private IChain GetFilterChain(HttpContext context, IServlet servlet, IFilter[] filters, int index)
{
if (index < filters.Length)
{
var filter = filters[index];
// 用递归构建下一个链路器
var next = GetFilterChain(context, servlet, filters, index + 1);
return new FilterChain(filter, context, next);
}
else
{
return new ServletChain(servlet, context);
}
}
}
6.动态代理
动态代理可以通过Castle.Core来实现。我们说静态代理和动态代理的区别是,静态代理在代码编译之前就已经确立的代理关系。而动态代理的原理是,在编译之后,运行时通过Emit来动态创建目标对象的子类,或者实现目标对象的接口。把拦截器织入到动态生成的类中,这里的拦截器可以织入到任意的实现类中。(Emit技术可以在运行时生成一个class,大家可以通过打印castle.core返回的实列的类名来进行验证)
动态代理和静态代理的本质都是继承或者实现,但是静态代理是需要手动编写代理类,而动态代理由框架动态生成代理类。动态代理性能更差,对异步支持不友好。
注意:如果是通过实现类的方式,那么无论静态代理还是动态代理,都只能代理父类中的虚函数(virtual),因为子类只能重写父类中的虚函数。所以建议使用接口的方式。
优点:
动态代理不需要写代理类,代理类自动生成。静态代理需要写代理类
缺点:
只能重写虚方法,如果需要重写所有方法,需要使用接口
异步支持差
反射,性能差
6.1Castle.Core
安装包:
<ItemGroup>
<PackageReference Include="Castle.Core" Version="5.1.1" />
</ItemGroup>
6.2实现Castle.Core
实现代理类
链路器模式:
递归获取下一个链路
var target = new UserService();
IUser proxy = new UserProxy(target, new Interceptor1(), new Interceptor2());
proxy.Invoke();
public class UserProxy : IUser
{
private readonly IUser _target;
private readonly IInterceptor[] _interceptors;
public UserProxy(IUser target,params IInterceptor[] interceptors)
{
_target = target;
_interceptors = interceptors;
}
public void Invoke()
{
var method = _target.GetType().GetMethod(nameof(IUser.Invoke));
InvocationUtilities.Invoke(_target, _interceptors, method, new object[] { });
}
}
public static class InvocationUtilities
{
private static IInvocation GetNextInvocation(IInvocation target, IInterceptor[] interceptorps, int index)
{
if (index < interceptorps.Length)
{
var proxy = interceptorps[index];
var next = GetNextInvocation(target, interceptorps, index + 1);
var args = new object[] { next };
var method = typeof(IInterceptor).GetMethod(nameof(IInterceptor.Intercept));
return new NextInvocation(proxy, args, method);
}
else
{
return target;
}
}
public static void Invoke(object target, IInterceptor[] interceptors, MethodInfo? method, object[] arguments)
{
if (method == null)
{
throw new ArgumentNullException(nameof(method));
}
var targetInvocation = new NextInvocation(target, arguments, method);
if (interceptors.Any())
{
var inteceptor = interceptors[0];
var invocation = GetNextInvocation(targetInvocation, interceptors, 1);
inteceptor.Intercept(invocation);
}
else
{
targetInvocation.Proceed();
}
}
// 因为是反射调用,因此只需要实现一个链路器
class NextInvocation : IInvocation
{
public object[] Arguments { get; }
public object InvocationTarget { get; }
public MethodInfo Method { get; }
public NextInvocation(object target, object[] arguments, MethodInfo method)
{
Arguments = arguments;
Method = method;
InvocationTarget = target;
}
public void Proceed()
{
Method.Invoke(InvocationTarget, Arguments);
}
#region other
public Type[] GenericArguments => throw new NotImplementedException();
public MethodInfo MethodInvocationTarget => throw new NotImplementedException();
public object Proxy => throw new NotImplementedException();
public object ReturnValue { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public Type TargetType => throw new NotImplementedException();
public IInvocationProceedInfo CaptureProceedInfo()
{
throw new NotImplementedException();
}
public object GetArgumentValue(int index)
{
throw new NotImplementedException();
}
public MethodInfo GetConcreteMethod()
{
throw new NotImplementedException();
}
public MethodInfo GetConcreteMethodInvocationTarget()
{
throw new NotImplementedException();
}
public void SetArgumentValue(int index, object value)
{
throw new NotImplementedException();
}
#endregion
}
}
6.3 实现Castle.Core的ProxyGenerator
public static class ProxyGenerator
{
static AssemblyBuilder _assemblyBuilder;
static ModuleBuilder _moduleBuilder;
static ProxyGenerator()
{
//创建一个程序集
var assemblyName = new AssemblyName("DynamicProxies");
_assemblyBuilder = AssemblyBuilder
.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
//创建一个模块
_moduleBuilder = _assemblyBuilder.DefineDynamicModule("Proxies");
}
public static TInterface Create<TInterface>(object target, params IInteceptor[] inteceptor)
where TInterface : class
{
#region 定义类型
//定义一个class,如果这个类型已定义直接返回,缓存
var typeName = $"{target.GetType().Name}EmitProxy";
var typeBuilder = _moduleBuilder.DefineType(
typeName,
TypeAttributes.Public,
typeof(object),
new Type[]
{
typeof(TInterface)
});
#endregion
#region 定义字段
//定义字段
var targetFieldBuilder = typeBuilder.DefineField("target", typeof(object), FieldAttributes.Private);
var inteceptorFieldBuilder = typeBuilder.DefineField("inteceptor", typeof(IInteceptor[]), FieldAttributes.Private);
#endregion
#region 定义构造器
//定义构造器
var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.ExplicitThis, new Type[]
{
typeof(TInterface),
typeof(IInteceptor[])
});
//获取IL编辑器
var generator = constructorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);//加载this
generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes) ?? throw new InvalidOperationException());
generator.Emit(OpCodes.Nop);
// this._target = target;
generator.Emit(OpCodes.Ldarg_0);//加载this
generator.Emit(OpCodes.Ldarg_1);//加载target参数
generator.Emit(OpCodes.Stfld, targetFieldBuilder);//加载target字段
// this._inteceptor = inteceptor;
generator.Emit(OpCodes.Ldarg_0);//加载this
generator.Emit(OpCodes.Ldarg_2);//加载inteceptor参数
generator.Emit(OpCodes.Stfld, inteceptorFieldBuilder);//加载inteceptor字段
generator.Emit(OpCodes.Ret);
#endregion
#region 实现接口
var methods = typeof(TInterface).GetMethods();
foreach (var item in methods)
{
var parameterTypes = item.GetParameters().Select(s => s.ParameterType).ToArray();
var methodBuilder = typeBuilder.DefineMethod(item.Name,
MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.HideBySig,
CallingConventions.Standard | CallingConventions.HasThis,
item.ReturnType,
parameterTypes);
var generator1 = methodBuilder.GetILGenerator();
//init
var methodInfoLocal = generator1.DeclareLocal(typeof(MethodInfo));
var argumentLocal = generator1.DeclareLocal(typeof(object[]));
generator1.Emit(OpCodes.Nop);//{
// MethodInfo method = this.GetType().GetMethod("Log");
generator1.Emit(OpCodes.Ldarg_0);
generator1.Emit(OpCodes.Ldfld, targetFieldBuilder);//this._target
generator1.Emit(OpCodes.Callvirt, typeof(object).GetMethod(nameof(Type.GetType), Type.EmptyTypes));
generator1.Emit(OpCodes.Ldstr, item.Name);
generator1.Emit(OpCodes.Callvirt, typeof(Type).GetMethod(nameof(Type.GetMethod), new Type[] { typeof(string)}));
generator1.Emit(OpCodes.Stloc, methodInfoLocal);
// object[] array = new object[0];
generator1.Emit(OpCodes.Ldc_I4,1);
generator1.Emit(OpCodes.Newarr, typeof(object));
generator1.Emit(OpCodes.Stloc, argumentLocal);
// array[0] = message;
generator1.Emit(OpCodes.Ldloc, argumentLocal);
generator1.Emit(OpCodes.Ldc_I4, 0);
generator1.Emit(OpCodes.Ldarg_1);
generator1.Emit(OpCodes.Stelem_Ref);
// InvocationUtilities.Invoke(_inteceptors, _target, method, array);
generator1.Emit(OpCodes.Ldarg_0);
generator1.Emit(OpCodes.Ldfld, inteceptorFieldBuilder);//this._interceptor
generator1.Emit(OpCodes.Ldarg_0);
generator1.Emit(OpCodes.Ldfld, targetFieldBuilder);//this._target
generator1.Emit(OpCodes.Ldloc, methodInfoLocal);
generator1.Emit(OpCodes.Ldloc, argumentLocal);
generator1.Emit(OpCodes.Call, typeof(InvocationUtilities).GetMethod(nameof(InvocationUtilities.Invoke)));
generator1.Emit(OpCodes.Nop);
generator1.Emit(OpCodes.Ret);
}
#endregion
//创建:这个type可以用一个线程安全的字典缓存起来,第二次需要这个代理类的时候,就不需要在生成一次emit代码了。
var type = typeBuilder.CreateType() ?? throw new ArgumentException();
var instance = Activator.CreateInstance(type, target, inteceptor);
return (TInterface)instance;
}
}
6.4ServiceCollection使用Castle.Core
把所有服务注入到ServiceCollection
注意:高生命级别可以依赖低生命级别,低生命级别不能依赖高生命级别
-
var services = new ServiceCollection(); services.AddSingleton(new ProxyGenerator()); services.AddSingleton<IInterceptor, Interceptor1>(); services.AddSingleton<IInterceptor, Interceptor2>(); services.AddSingleton<Logger>(); services.AddScoped(typeof(IUser), sp => { var generator = sp.GetRequiredService<ProxyGenerator>(); var interceptors = sp.GetServices<IInterceptor>().ToArray(); var target = ActivatorUtilities.CreateInstance(sp, typeof(UserService)); return generator.CreateInterfaceProxyWithTarget(typeof(IUser), target, interceptors); }); var sp = services.BuildServiceProvider(); var user = sp.GetRequiredService<IUser>(); user.Invoke();
7.Mediator
7.1Mediator基本使用
安装包:
<ItemGroup>
<PackageReference Include="MediatR" Version="12.1.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
</ItemGroup>
创建命令,实现IRequest
处理命令,继承 IRequestHandler<in TRequest, TResponse>
7.2Mediator通知
INotification: 表示通知接口
INotificationHandler: 通知处理接口
7.3代码
public class CreateUserCommandResponse
{
public int UserId { get; set; }
}
public class CreateUserCommand : IRequest<CreateUserCommandResponse>
{
public int UserId { get; set; }
public string UserName { get; set; }
}
public class CreateUserCommandEvent : INotification
{
public int UserId { get; set; }
public string UserName { get; set; }
}
public class MQCreateUserEeventHandler : INotificationHandler<CreateUserCommandEvent>
{
public Task Handle(CreateUserCommandEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"已发布MQ。UserId:{notification.UserId},UserName:{notification.UserName}");
return Task.CompletedTask;
}
}
public class EmailCreateUserEeventHandler : INotificationHandler<CreateUserCommandEvent>
{
public Task Handle(CreateUserCommandEvent notification, CancellationToken cancellationToken)
{
Console.WriteLine($"已发布Email。UserId:{notification.UserId},UserName:{notification.UserName}");
return Task.CompletedTask;
}
}
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, CreateUserCommandResponse>
{
private readonly IMediator _mediator;
public CreateUserCommandHandler(IMediator mediator)
{
_mediator = mediator;
}
public Task<CreateUserCommandResponse> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("创建用户成功");
_mediator.Publish(new CreateUserCommandEvent() { UserId = request.UserId, UserName = request.UserName });
return Task.FromResult(new CreateUserCommandResponse() { UserId = 1 });
}
}
var services = new ServiceCollection();
services.AddMediatR(configuration =>
{
configuration.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ExceptionPipelineBehavior<,>));
configuration.AddBehavior(typeof(IPipelineBehavior<,>), typeof(TransactionPipelineBehavior<,>));
configuration.RegisterServicesFromAssemblyContaining<Program>();
configuration.Lifetime = ServiceLifetime.Scoped;
});
var sp = services.BuildServiceProvider();
var mediator = sp.GetRequiredService<IMediator>();
await mediator.Send(new CreateUserCommand() { UserId = 1, UserName = "Peng" });
8.Mediator管道事务
安装包:
<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.21" />
<PackageReference Include="MediatR" Version="12.1.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="MySql.Data" Version="8.2.0" />
</ItemGroup>
DbContext:
public class DbContext : IDisposable
{
private readonly IDbConnection _connection;
private DbContextTransaction? _transaction;
public DbContext(IDbConnection connection)
{
_connection = connection;
}
public bool HasActivedTransaction => _transaction != null;
public DbContextTransaction BegionTransaction()
{
//if (_connection.State != ConnectionState.Open)
//{
// _connection.Open();
//}
//if (HasActivedTransaction == false)
//{
// _transaction = new DbContextTransaction(_connection.BeginTransaction());
//}
//return _transaction;
_connection.Open();
_transaction = new DbContextTransaction(_connection.BeginTransaction());
return _transaction;
}
public void CommitTransaction()
{
_transaction?.CommitTransaction();
_transaction = null;
}
public void RollbackTransaction()
{
_transaction?.RollingTransaction();
_transaction = null;
}
public void Dispose()
{
_connection.Dispose();
}
public async Task<int> ExecuteAsync(string sql, object? parameter = null)
{
return await _connection.ExecuteAsync(sql, parameter, _transaction?.GetDbTransaction());
}
public async Task<T> ExecuteScalarAsync<T>(string sql, object? parameter = null)
{
return await _connection.ExecuteScalarAsync<T>(sql, parameter, _transaction?.GetDbTransaction());
}
public async Task<IEnumerable<T>> QueryAsync<T>(string sql, object? parameter = null)
{
return await _connection.QueryAsync<T>(sql, parameter, _transaction?.GetDbTransaction());
}
}
public class DbContextTransaction : IDisposable
{
private IDbTransaction? _transaction;
private readonly bool _isDisposabled;
public DbContextTransaction(IDbTransaction? transaction)
{
_transaction = transaction;
}
public IDbTransaction? GetDbTransaction() { return _transaction; }
public void Dispose()
{
if (_isDisposabled)
{
return;
}
RollingTransaction();
}
public void RollingTransaction()
{
_transaction?.Rollback();
_transaction = null;
}
public void CommitTransaction()
{
_transaction?.Commit();
_transaction = null;
}
}
事务处理管道:
internal class TransactionPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull
{
private readonly DbContext _context;
public TransactionPipelineBehavior(IMediator mediator, DbContext context)
{
_context = context;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
TResponse response;
try
{
if (_context.HasActivedTransaction)
{
return await next();
}
using ( var tran = _context.BegionTransaction())
{
response = await next();
_context.CommitTransaction();
}
}
catch (Exception ex)
{
_context.RollbackTransaction();
throw;
}
return response;
}
}
异常处理管道
internal class ExceptionPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
TResponse response;
try
{
response = await next();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
return response;
}
}
命令处理类:
public class CreateUserCommandResponse
{
public int UserId { get; set; }
}
public class CreateUserCommand : IRequest<CreateUserCommandResponse>
{
public int UserId { get; set; }
public string UserName { get; set; }
public string LoginName { get; set; }
public string LoginPassword { get; set; }
public string Address { get; set; }
}
public class CreateUserAddressCommand : IRequest
{
public int UserId { get; set; }
public int UserInfoId { get; set; }
public string Address { get; set; }
}
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, CreateUserCommandResponse>
{
private readonly IMediator _mediator;
private readonly DbContext _context;
public CreateUserCommandHandler(IMediator mediator, DbContext context)
{
_mediator = mediator;
_context = context;
}
public async Task<CreateUserCommandResponse> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
//Console.WriteLine("创建用户成功");
var sql = "INSERT INTO userinfo(UserName,LoginName,LoginPassword) VALUES(@UserName,@LoginName,@LoginPassword);SELECT LAST_INSERT_ID()";
var userInfoId = await _context.ExecuteScalarAsync<int>(sql, new { request.UserName, request.LoginName, request.LoginPassword });
//_mediator.Publish(new CreateUserCommandEvent() { UserId = request.UserId, UserName = request.UserName });
await _mediator.Send(new CreateUserAddressCommand { UserInfoId = userInfoId, Address = request.Address });
return await Task.FromResult(new CreateUserCommandResponse() { UserId = userInfoId });
}
}
public class CreateUserAddressCommandHandler : IRequestHandler<CreateUserAddressCommand>
{
private readonly IMediator _mediator;
private readonly DbContext _context;
public CreateUserAddressCommandHandler(IMediator mediator, DbContext context)
{
_mediator = mediator;
_context = context;
}
public async Task Handle(CreateUserAddressCommand request, CancellationToken cancellationToken)
{
var sql = "INSERT INTO userinfo_other(UserInfoId,Address) VALUES(@UserInfoId,@Address);SELECT @@identity;";
await _context.ExecuteAsync(sql, new { request.UserInfoId, request.Address });
}
}
测试代码:
配置事务核心代码:
configuration.AddBehavior(typeof(IPipelineBehavior<,>), typeof(TransactionPipelineBehavior<,>));
var services = new ServiceCollection();
services.AddScoped<IDbConnection>(sp =>
{
var connstr = "server=localhost;user id=root;password=root;database=testdb";
return new MySqlConnection(connstr);
});
services.AddScoped<DbContext>();
services.AddMediatR(configuration =>
{
configuration.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ExceptionPipelineBehavior<,>));
configuration.AddBehavior(typeof(IPipelineBehavior<,>), typeof(TransactionPipelineBehavior<,>));
configuration.RegisterServicesFromAssemblyContaining<Program>();
configuration.Lifetime = ServiceLifetime.Scoped;
});
var sp = services.BuildServiceProvider();
//var mediator = sp.GetRequiredService<IMediator>();
using (var scope = sp.CreateScope())
{
var mediator = sp.GetRequiredService<IMediator>();
await mediator.Send(new CreateUserCommand() { UserId = 1, UserName = "zhangsan", LoginName = "zhangsan", LoginPassword = "789", Address = "上海" });
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?