首页 > 其他分享 >ABP-VNEXT 学习笔记(六)事件总线--本地事件总线

ABP-VNEXT 学习笔记(六)事件总线--本地事件总线

时间:2022-09-20 09:33:11浏览次数:89  
标签:VNEXT 订阅 -- Volo 总线 Abp 事件 using public

事件总线,是我们在处理分布式和微服务的时候经常需要用到的,用于分布式事务解决方案。

事件总线基本就2个逻辑,1个发布事件,1个是订阅事件。

abp也提供了事件总线的处理机制

下面跟着学习本地事件总线

abp官网文档地址:https://docs.abp.io/zh-Hans/abp/latest/Local-Event-Bus

本地事件总线允许服务发布和订阅进程内事件. 这意味着如果两个服务(发布者和订阅者)在同一个进程中运行,那么它是合适的。这点很重要,也就是

本地事件,适用于发布者和订阅者都在同一个项目同一个进程里执行。他不适用于不同进程之间的协同。

事件可用于我们发生一个动作时,触发多种处理的操作,以往,我们都是在发生动作的业务逻辑里面写触发事件的调用函数。如果多个地方要触发,就需要多处写,不利于代码的解耦。

用了事件,就完全解耦并且是异步。

下面我们上代码,利用abp文档上的代码示例做训练讲解

 

ILocalEventBus

 

可以注入 ILocalEventBus 并且使用发布本地事件.

我们新建一个.NET6.0 的Asp.net Core MVC项目EventBus,nuget上引用Volo.Abp.Core、Volo.Abp.Autofac、Volo.Abp.AspNetCore.Mvc 包

然后一样创建一个EventBusModule.cs启动类,代码如下:

using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;

namespace EventBus
{
    [DependsOn(
    typeof(AbpAutofacModule),
    typeof(AbpAspNetCoreMvcModule)
    )]
    public class EventBusModule:AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        { }
        public override void OnApplicationInitialization(ApplicationInitializationContext context)
        {
            var app = context.GetApplicationBuilder();
            var env = context.GetEnvironment();

            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

         
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute(
            name: "areas",
            pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
          );
            });
        }
    }
}

Program.cs文件如下:

using EventBus;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Host.AddAppSettingsSecretsJson().UseAutofac(); //引入autofac作为IOC
await builder.AddApplicationAsync<EventBusModule>(); //将abp模块入口初始化
var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();
await app.InitializeApplicationAsync(); //初始化abp模块应用
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

以上是项目的基本配置。

下面开始事件总线相关代码

示例: 产品的存货数量发生变化时发布本地事件

新建一个MyService.cs类,作为我们的服务调用类,类中定义一个ChangeStockCountAsync方法,在方法中发布一个事件

using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Local;

namespace EventBus.Models
{
    public class MyService : ITransientDependency
    {
        private readonly ILocalEventBus _localEventBus;

        public MyService(ILocalEventBus localEventBus)
        {
            _localEventBus = localEventBus;
        }

        public virtual async Task ChangeStockCountAsync(Guid productId, int newCount)
        {
            //TODO: IMPLEMENT YOUR LOGIC...

            //PUBLISH THE EVENT
            await _localEventBus.PublishAsync(
                new StockCountChangedEvent
                {
                    ProductId = productId,
                    NewCount = newCount
                }
            );
        }
    }

    public class StockCountChangedEvent
    {
        public Guid ProductId { get; set; }

        public int NewCount { get; set; }
    }
}

PublishAsync 方法需要一个参数:事件对象,它负责保持与事件相关的数据,是一个简单的普通类:

StockCountChangedEvent 事件对象,用于参数传递。

 

接下来,我们定义两个订阅类,来订阅处理这个事件

一个服务可以实现 ILocalEventHandler<TEvent> 来处理事件.

示例: 处理上面定义的StockCountChangedEvent

新建一个MyHandler.cs类

using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;

namespace EventBus.Models
{
    public class MyHandler
         : ILocalEventHandler<StockCountChangedEvent>,
           ITransientDependency
    {
        public async Task HandleEventAsync(StockCountChangedEvent eventData)
        {
            //TODO: your code that does somthing on the event

            //这里处理事件

            var proId = eventData.ProductId;
            Console.WriteLine("MyHandler执行完毕");
        }
    }
}

 

我们再定义一个MyHandler2.cs 的订阅类,用于验证一个事件,是可以多个订阅处理的

using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;

namespace EventBus.Models
{
    public class MyHandler2
        : ILocalEventHandler<StockCountChangedEvent>,
          ITransientDependency
    {
        public async Task HandleEventAsync(StockCountChangedEvent eventData)
        {
            //TODO: your code that does somthing on the event

            //这里处理事件

            var proId = eventData.ProductId;

            Console.WriteLine("MyHandler2执行完毕");
        }
    }
}

OK,以上我们就完成了1个发布,2个订阅。

那我们跑起来看下,我们在Home控制器的index中调用Myservice中的ChangeStockCountAsync方法,验证2个订阅是否都执行了。

  public MyService myService { get; set; }
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public IActionResult Index()
        {
           
            myService.ChangeStockCountAsync(Guid.NewGuid(), 100).GetAwaiter();
            Console.WriteLine("任务执行完毕");
            return View();
        }

运行起来看结果:

 

 通过运行结果,我们可以确认以下2点
1: 2个订阅都有执行,验证了1个发布,可以多个订阅的处理方式

2:订阅和发布是异步的,发布不需要等订阅执行完业务逻辑才结束。

下面,我们再进一步验证一个问题

一个订阅的事件处理方法,能否订阅多个事件。比如有多个动作,会触发相同的行为。比如入库要增加库存,退货也要增加库存。

那么入库定义为一个事件,退货也定义为一个事件,但是订阅事件是同一个,就是增加库存。

我们对代码进行优化一下来验证。

我们在 myservice.cs中增加事件对象:InStockCountChangedEvent

同时,为了简便,我们直接在原有的ChangeStockCountAsync方法中,增加InStockCountChangedEvent事件的发布

完整代码如下:

using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Local;

namespace EventBus.Models
{
    public class MyService : ITransientDependency
    {
        private readonly ILocalEventBus _localEventBus;

        public MyService(ILocalEventBus localEventBus)
        {
            _localEventBus = localEventBus;
        }

        public virtual async Task ChangeStockCountAsync(Guid productId, int newCount)
        {
            //TODO: IMPLEMENT YOUR LOGIC...

            //PUBLISH THE EVENT
            await _localEventBus.PublishAsync(
                new StockCountChangedEvent
                {
                    ProductId = productId,
                    NewCount = newCount
                }
            );
            await _localEventBus.PublishAsync(
               new InStockCountChangedEvent
               {
                   ProductId = productId,
                   NewCount = newCount
               }
           );
        }
    }

    public class StockCountChangedEvent
    {
        public Guid ProductId { get; set; }

        public int NewCount { get; set; }
    }

    public class InStockCountChangedEvent
    {
        public Guid ProductId { get; set; }

        public int NewCount { get; set; }
    }
}

在MyHandler订阅事件处理中,我们增加InStockCountChangedEvent事件的订阅

代码如下:

using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;

namespace EventBus.Models
{
    public class MyHandler
         : ILocalEventHandler<StockCountChangedEvent>, ILocalEventHandler<InStockCountChangedEvent>,
           ITransientDependency
    {
        public async Task HandleEventAsync(StockCountChangedEvent eventData)
        {
            //TODO: your code that does somthing on the event

            //这里处理事件

            var proId = eventData.ProductId;
            Console.WriteLine("MyHandler处理StockCountChangedEvent事件完毕");
        }
        public async Task HandleEventAsync(InStockCountChangedEvent eventData)
        {
            //TODO: your code that does somthing on the event

            //这里处理事件

            var proId = eventData.ProductId;
            Console.WriteLine("MyHandler处理InStockCountChangedEvent事件完毕");
        }
    }
}

OK了,我们跑起来

 

 根据运行结果,我们可以看到2个事件都有执行。

这也验证了,一个订阅事件处理类,可以同时订阅多个事件并处理。

 

标签:VNEXT,订阅,--,Volo,总线,Abp,事件,using,public
From: https://www.cnblogs.com/fei686868/p/16708422.html

相关文章

  • C++ populate template array via random generator and finally sort,print
    #pragmaonce#pragmacomment(lib,"rpcrt4.lib")#include<algorithm>#include<cstring>#include<iostream>#include<random>#include<vector>#include<Windo......
  • 虚拟机无法ping通主机,主要是由于公用网络未启用,启用步骤如下:控制面板---->系统和安全-
    主机可以ping通虚拟机,虚拟机ping不通主机1、在本机安装了虚拟机,虚拟机中使用的是Ubuntu64位系统。 安装完成后,首先关闭了本机的防火墙,步骤如下:  控制面板--->......
  • 从网易获取股票数据
    importurllib.requestimportre##defdownback(a,b,c):##''''##a:已经下载的数据块##b:数据块的大小##c:远程文件的大小##'''##per=1......
  • css冲突
    当对同一个元素同时设置了两个css属性时,会遵循后面设置的那个(位置顺序为后)用!important也可以直接改变优先级为最大比如下面这个,h1被同时设置了两种颜色,如果不加!import......
  • Git报错:Updates were rejected because the tip of your current branch is behind
    错误说明出现这个错误的原因是git本地仓库的当前版本低于远程仓库的版本(大白话就是:你在github上进行的修改没有同步到本地git仓库中)。错误原因第一种错误的原因某一......
  • 磁盘如何存储数据?
    硬盘:把电平通过电磁流写到硬盘上,转换成硬盘里的磁道上的磁性。硬盘里实际上是类似于我们光盘的盘面和一个可以移动的机械臂。U盘,存储卡,SSD:他们里面是你所说得到特别细小的......
  • 【第一章】frida基础配置
    python环境➜~python--versionPython3.9.13➜~pip--versionpip22.2.2fromD:\Programs\Python\Python39\lib\site-packages\pip(python3.9)安装fridapipin......
  • k8s 容器自动重启 错误 代码
    参考文章https://betterprogramming.pub/understanding-docker-container-exit-codes-5ee79a1d58f6ExitCodesCommonexitcodesassociatedwithdockercontainersar......
  • 通用ORM的设计与实现
    介绍我们通用的ORM,基本模式都是想要脱离数据库的,几乎都在编程语言层面建立模型,由程序去与数据库打交道。虽然脱离了数据库的具体操作,但我们要建立各种模型文档,用代码去写......
  • 【解题报告】Power收集
    东方Project相关试题Power收集(注:我不是东方众哦但下次回家可以试着玩一下传送门先读题啦n*m矩阵,其中有K个格子上有P点,价值val[i][j],从第一行任意格子出发,每秒向下走......