随着微服务的火热,DDD(领域驱动设计模式)思想风起云涌,冲击着整个软件生态系统。其中,事件总线那是必须知道的了,于是我便抱着一个学习DDD的心态搭建了一个博客网站,目前该网站正在建设阶段,后续会不断完善,这里我只是讲一下我里面所用到的事件总线。

事件总线,我的理解就是发布订阅模式,这里有一篇文章写的比较好,我就是按着这个文章来完成的事件总线:事件总线知多少。我之前按照他的文章结合自己写的,但是今天又看了下自己写的,发现好多都生疏了,所以觉得有必要来回忆下,这里只是我个人的理解,如有不对请指出。

     事件总线就肯定要有事件源,这里我定义一个Command事件源:   
    /// <summary>
/// 领域命令基类(此处文章里我称之为事件源)
/// </summary>
public class Command
{ }

 然后我根据事件源来定义一个事件源处理的接口和它的实现类:

    /// <summary>
/// 创建用户领域命令(创建事件源)
/// </summary>
public class CreateUserCommand: Command
{
public CreateUserCommand(User user)
{
User = user;
}
public User User { get; private set; } }
/// <summary>
/// 用户命令处理程序(处理事件源)
/// </summary>
public class UserCommandHandler : ICommandHandler<CreateUserCommand>,
{
private readonly IUserRepository _userRepository;
private readonly IEventBus _eventBus;
public UserCommandHandler(IUserRepository userRepository, IEventBus eventBus)
{
_userRepository = userRepository;
_eventBus = eventBus;
} public void Handler(CreateUserCommand command)
{
int count = _userRepository.SelectCountByAccount(command.User.Account);
if (count > 0)
{
_eventBus.RaiseEvent(new NotifyValidation("该账号已存在"));
return;
}
_userRepository.Insert(command.User);
}
}

此处我觉得已经完成了关于事件源的功能,那么我们就来思考根据这个事件源来处理发布订阅的关系。

就那注册用户功能来说,前面已经将注册用户的事件源已经写好了,那么发布订阅怎么处理呢?首先,我们应该清楚一个逻辑,那就是页面生成用户信息,后端获取信息生成UserModel,然后我们根据UserModel转为我们需要的CreateUserCommand,然后我们ICommandHandler根据CreateUserCommand来调用Handler,这是一个简单的调用逻辑。那么IcommandHnadler怎么知道调用哪一个Handler呢?那就是我将事件源和事件源处理类存入集合里面,这样我以后就会根据Command来获取到我的ICommandHandler了,又因为.net core遵循依赖注入原则,所以我需要往容器了注入ICommander和他的实现类,就是UserCommandhandler,这个时候可以说是已经将事件源都注册到了内存里了,以下是我的相关代码:

 
        /// <summary>
/// 临时存储类型数组
/// </summary>
private static Type[] serviceTypes = Assembly.Load("Blog.Domain").GetTypes(); private static ConcurrentDictionary<Type, IList<Type>> handlerMapping = new ConcurrentDictionary<Type, IList<Type>>(); public static IList<Type> GetOrAddHandlerMapping(this Type eventType)
{
return handlerMapping.GetOrAdd(eventType,(Type type)=>new List<Type>());
} /// <summary>
/// 注册事件总线(事件源)
/// </summary>
/// <typeparam name="TImplementation">ICommandler<CreateUserCommand></typeparam>
/// <typeparam name="TService">CreateUserCommand</typeparam>
/// <param name="serviceDescriptors"></param>
public static void AddEventBus<TImplementation, TService>(this IServiceCollection serviceDescriptors)
{
Type handler = typeof(TImplementation);
Type serviceType = serviceTypes.FirstOrDefault(s => handler.IsAssignableFrom(s));//获得接口的实现类
if (serviceType == null)
throw new ArgumentNullException(string.Format("类型{0}未找到实现类", handler.FullName));
serviceDescriptors.AddTransient(handler, serviceType);//.net core自带的IOC容器
GetOrAddHandlerMapping(typeof(TService)).Add(handler);//将事件源和事件源处理程序注册到内存里,可以说生成了一个订阅列表
}

    接下来我们再看发布与订阅,我要先定义一个发布订阅的中间件,

    /// <summary>
/// 中间件
/// </summary>
public interface IEventBus
{
/// <summary>
/// 发布
/// </summary>
/// <typeparam name="TEventData"></typeparam>
/// <param name="eventData"></param>
void Publish<TCommand>(TCommand command) where TCommand : Command;
}

  然后还有它的实现类,处理逻辑就是根据UserCommandHandler去ConcurrentDictionary里找到它的对应的ICommandHandler,然后在从IOC容器找到ICommandHandler的实现类,然后执行里面的方法,如下:

    public sealed class EventBus : IEventBus
{
private IServiceProvider _serviceProvider;
public EventBus(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
/// <summary>
/// 发布事件
/// </summary>
/// <typeparam name="TEventData"></typeparam>
/// <param name="eventData"></param>
public void Publish<TCommand>(TCommand command) where TCommand : Command
{
IList<Type> types=typeof(TCommand).GetOrAddHandlerMapping();
if (types == null || types.Count == 0)
throw new ServiceException("事件总线未注册:" + typeof(TCommand).Name);
foreach (var type in types)//从订阅列表里寻找
{
object obj = _serviceProvider.GetService(type);
if(type.IsAssignableFrom(obj.GetType()))
{
ICommandHandler<TCommand> handler = obj as ICommandHandler<TCommand>;
if (handler != null)
handler.Handler(command);//
}
}
}
}

  这个时候可以说已经完成了发布订阅,程序生成CreateUserCommand,这里我的理解为就是发布,调用Publish方法,这里我觉得就是订阅,然后最后执行Handler完成业务逻辑:

  public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IEventBus _eventBus;
/// <summary>
/// 根据UserModel转实体
/// </summary>
/// <param name="userModel"></param>
/// <returns></returns>
private User TransferModel(UserModel userModel)
{
return user;
}
public UserService(IUserRepository userRepository, IEventBus eventBus)
{
_userRepository = userRepository;
_eventBus = eventBus;
}
public void Insert(UserModel userModel)
{
userModel.Password = EncrypUtil.MD5Encry(userModel.Password);
var command = new CreateUserCommand(TransferModel(userModel));//创建事件源
_eventBus.Publish(command);//发布命令
}
}

还有就是最后的IServiceCollection注入了:

        /// <summary>
/// 服务集合
/// </summary>
/// <param name="services"></param>
public static void AddServices(this IServiceCollection services)
{
services.AddTransient<IUserRepository, UserRepository>();
services.AddTransient<IUserService, UserService>();
services.AddEventBus<ICommandHandler<CreateUserCommand>, CreateUserCommand>();
services.AddTransient<IEventBus,EventBus>()
services.DisposeServiceTypes();
}

  以上就是我对事件总线的具体应用,希望有大佬能指出我这菜鸟的不足指出!

好记性不如烂笔头,所以我把这个玩意用到了我的网站里面,我的个人站点的地址是:www.ttblog.site,源代码的地址是:https://github.com/Hansdas/BlogH.git,个人站点处于建设阶段,很多功能不完善,由于时间原因,所以进度比较慢,但是我也是每天回到家后都会去完善,自己做的饭再难吃也要吃完自己做的网站,不好看也要用心呵护。 

.net core下使用事件总线的更多相关文章

  1. ASP.NET Core Web API下事件驱动型架构的实现(三):基于RabbitMQ的事件总线

    在上文中,我们讨论了事件处理器中对象生命周期的问题,在进入新的讨论之前,首先让我们总结一下,我们已经实现了哪些内容.下面的类图描述了我们已经实现的组件及其之间的关系,貌似系统已经变得越来越复杂了. 其 ...

  2. 重温.NET下Assembly的加载过程 ASP.NET Core Web API下事件驱动型架构的实现(三):基于RabbitMQ的事件总线

    重温.NET下Assembly的加载过程   最近在工作中牵涉到了.NET下的一个古老的问题:Assembly的加载过程.虽然网上有很多文章介绍这部分内容,很多文章也是很久以前就已经出现了,但阅读之后 ...

  3. .NET Core 事件总线,分布式事务解决方案:CAP

    背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用的过程中也会遇到分布式事务的问题,那么 CAP 就是在这样的背景 ...

  4. .NET Core 事件总线,分布式事务解决方案:CAP 基于Kafka

    背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用的过程中也会遇到分布式事务的问题,那么 CAP 就是在这样的背景 ...

  5. 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)

    并发编程概述   前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...

  6. NET Core 事件总线

    NET Core 事件总线,分布式事务解决方案:CAP 背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用的过程中 ...

  7. 【转】.NET Core 事件总线,分布式事务解决方案:CAP

    [转].NET Core 事件总线,分布式事务解决方案:CAP 背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用 ...

  8. 基于ASP.NET Core 5.0使用RabbitMQ消息队列实现事件总线(EventBus)

    文章阅读请前先参考看一下 https://www.cnblogs.com/hudean/p/13858285.html 安装RabbitMQ消息队列软件与了解C#中如何使用RabbitMQ 和 htt ...

  9. .Net Core 基于CAP框架的事件总线

    .Net Core 基于CAP框架的事件总线 CAP 是一个在分布式系统中(SOA,MicroService)实现事件总线及最终一致性(分布式事务)的一个开源的 C# 库,她具有轻量级,高性能,易使用 ...

  10. ASP.NET Core基于微软微服务eShopOnContainer事件总线EventBus的实现

    这个EventBus的实现是基于微软微服务https://github.com/dotnet-architecture/eShopOnContainers项目的,我把它从项目中抽离出来,打包成nuge ...

随机推荐

  1. vim中ctags 的使用

    --- title: vim中ctags 的使用 EntryName: vim-config-with-ctags date: 2020-08-19 11:17:38 categories: tags ...

  2. 【基础整理】Mapping representation 机器人所用地图种类及相关介绍

    参考与前言 本文主要介绍 建图 Mapping 方面的一些 基础知识介绍与相关下游任务使用 涉及知识较为基础,SLAM大佬们可以提前退出了 主要针对应用为移动机器人与物流无人驾驶车:提前申明:大部分文 ...

  3. VBA-合并多个工作簿

    '合并多个工作薄,并以工作薄的名字给sheet表命名(每个工作薄只有一张表) Sub test() Dim str As String Dim wb As Workbook str = Dir(&qu ...

  4. FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt

    ​<FFmpeg开发实战:从零基础到短视频上线>一书的"10.2  FFmpeg推流和拉流"提到直播行业存在RTSP和RTMP两种常见的流媒体协议.除此以外,还有比较两 ...

  5. java生成word的解决方案比较

    1.Jacob Jacob是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁.通过Jacob实现了在Java平台上对微软Office的COM接口进行调用. 优点:调 ...

  6. yb课堂之个人信息接口开发 《十三》

    根据token从查询个人信息接口开发 直接解密token,获取个人信息 通过token解密查询数据库获取个人信息 UserController.java package net.ybclass.onl ...

  7. vscode配置项

    因为vscode的默认配置,导致现在用的不是很舒服.总结了以下配置能让你的vscode用着更舒服. 1: 问题: 输入log按tab快速生成代码后,提示居然没了? 解决方案: "editor ...

  8. AT_abc182_d 题解

    洛谷链接&Atcoder 链接 本篇题解为此题较简单做法及较少码量,并且码风优良,请放心阅读. 题目简述 从数轴的原点开始向正方向走. 第一次向前走 \(a_1\) 步,第二次向前走 \(a_ ...

  9. mysql面试汇总

    最近一直在关注mysql方面的面试题目,并且从最近的面试情况来看,mysql在java后端的面试中,肯定是必问的题目,所以这里有必要对这块的内容进行总结,大家可以根据下面的导图进行重点复习, 引擎 1 ...

  10. pytorch问题记录

    1.找不到fused 2.找不到torch_extensions 网上的教程一般都是linux系统的,Windows这个是在C盘目录下 3.c++开发环境中找不到vcvars64.bat 解决方法:重 ...