AspNetCore AOP

前言

AOP。。。

1.基础知识

AOP是对OOP的一种补充,即面向切面编程,一种编程思想。

AOP的优势是面向切面编程,每个切面负责独立的系统逻辑,降低代码的复杂度,提高代码的复用率。可以随意调整顺序,随意插拔。用于对业务逻辑进行增强。面向切面编程可以使得系统逻辑和业务逻辑进行分离。

系统逻辑:比如身份认证,异常处理,参数校验

业务逻辑:就是我们真正关心不得不写的业务逻辑。

image-20231113232545707

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

image-20231113233228726

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管道核心代码

image-20231113235938634


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.链路器模式

image-20231115162048346

请求类:

image-20231115162116133

IChain:此接口主要是把过滤器和过滤器联系起来,保存下一个过滤器的执行

IFilter:执行当前过滤器

IServlet:请求到达具体执行的方法。

image-20231115162134681

模版方法处理请求

image-20231115162551386

WebHost核心代码:

image-20231115162659517

递归处理filter:

image-20231115162852799

代码:

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

实现代理类

image-20231115172445787

链路器模式:

递归获取下一个链路

image-20231115172349049

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

image-20231115173647763

把所有服务注入到ServiceCollection

注意:高生命级别可以依赖低生命级别,低生命级别不能依赖高生命级别

  1. 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

image-20231116011815398

处理命令,继承 IRequestHandler<in TRequest, TResponse>

image-20231116011845875

7.2Mediator通知

INotification: 表示通知接口

INotificationHandler: 通知处理接口

image-20231116012055562

7.3代码

image-20231116012251733

 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 = "上海" });
}

posted @   peng_boke  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示