.netcore利用DI实现订阅者模式 - xms
结合DI,实现发布者与订阅者的解耦,属于本次事务的对象主体不应定义为订阅者,因为订阅者不应与发布者产生任何关联
一、发布者订阅者模式

发布者发出一个事件主题,一个或多个订阅者接收这个事件,中间通过事件总线通讯(消息队列),并且发布者与订阅者这两者间是无状态的,根据产品实际场景需要,可以自己实现单机单点的发布订阅,也可选择使用目前流行的分布式消息中间件:
RabbitMQ、ActiveMQ、RocketMQ、kafka等
二、观察者与订阅者的区别
观察者与业务主体是耦合的,并且是即时通知的;订阅者与业务主体完全解耦,只通过中间的信息通道通知,互相不知道对方的存在,可以是同步也可以是异步
三、具体实现
本文主要讲解单点模式,有需要随时可以扩展为分布式方案
发布者接口:
namespace Xms.Event.Abstractions
{
/// <summary>
/// 事件发布接口
/// </summary>
public interface IEventPublisher
{
/// <summary>
/// 发布事件
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="e"></param>
void Publish<TEvent>(TEvent e);
}
}
发布者实现:
using System;
using System.Linq;
using Xms.Event.Abstractions;
using Xms.Infrastructure.Inject;
using Xms.Logging.AppLog; namespace Xms.Event
{
/// <summary>
/// 事件发布者
/// </summary>
public class EventPublisher : IEventPublisher
{
private readonly ILogService _logService;
private readonly IServiceResolver _serviceResolver; public EventPublisher(ILogService logService
, IServiceResolver serviceResolver)
{
_logService = logService;
_serviceResolver = serviceResolver;
} #region Methods /// <summary>
/// 发布事件
/// </summary>
/// <typeparam name="TEvent">事件类</typeparam>
/// <param name="e">事件对象</param>
public virtual void Publish<TEvent>(TEvent e)
{
//获取所有事件接收者
var consumers = _serviceResolver.GetAll<IConsumer<TEvent>>().ToList();
foreach (var consumer in consumers)
{
try
{
//处理事件
consumer.HandleEvent(e);
}
catch (Exception exception)
{
_logService.Error(exception);
}
}
} #endregion Methods
}
}
订阅(消费)者接口:
namespace Xms.Event.Abstractions
{
/// <summary>
/// 事件接收接口
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IConsumer<T>
{
/// <summary>
/// 处理事件
/// </summary>
/// <param name="eventMessage">事件</param>
void HandleEvent(T eventMessage);
}
}
事件(消息):
这里只给出一个作为示例,实际上一般会有记录的:“创建”、“修改”、“删除”,流程相关的:“发起审批”、“审批通过”、“审批完成”等等
namespace Xms.Flow.Core.Events
{
/// <summary>
/// 工作流启动后事件
/// </summary>
public class WorkFlowStartedEvent
{
public WorkFlowStartUpContext Context { get; set; }
public WorkFlowExecutionResult Result { get; set; }
}
}
服务注册:
详细实现回看.netcore之DI批量注入(支持泛型)
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Xms.Core;
using Xms.Infrastructure.Inject; namespace Xms.Event
{
/// <summary>
/// 事件模块服务注册
/// </summary>
public class ServiceRegistrar : IServiceRegistrar
{
public int Order => ; public void Add(IServiceCollection services, IConfiguration configuration)
{
//event publisher
services.AddScoped<Event.Abstractions.IEventPublisher, Event.EventPublisher>();
//event consumers
services.RegisterScope(typeof(Event.Abstractions.IConsumer<>));
}
}
}
四、应用场景
比如在工作流启动审批后发送通知
using System.Collections.Generic;
using Xms.Context;
using Xms.Event.Abstractions;
using Xms.Flow.Core.Events;
using Xms.Infrastructure.Utility;
using Xms.Localization.Abstractions;
using Xms.Notify.Abstractions;
using Xms.Notify.Internal; namespace Xms.EventConsumers.Notify
{
/// <summary>
/// 工作流启动审批后发送通知
/// </summary>
public class WorkflowStartedNotify : IConsumer<WorkFlowStartedEvent>
{
private readonly IAppContext _appContext;
private readonly ILocalizedTextProvider _loc;
private readonly IEnumerable<INotify> _notifies; public WorkflowStartedNotify(IAppContext appContext
, IEnumerable<INotify> notifies)
{
_appContext = appContext;
_loc = _appContext.GetFeature<ILocalizedTextProvider>();
_notifies = notifies;
}
public void HandleEvent(WorkFlowStartedEvent eventMessage)
{
//当前节点处理人
foreach (var handlerId in eventMessage.Result.NextHandlerId)
{
//通知方式:微信、短信、邮件、系统消息等
var msg = _loc["workflow_newtasknotify"].FormatWith(eventMessage.Context.EntityMetaData.LocalizedName);
//发送消息
foreach (var notifier in _notifies)
{
notifier.Send(new InternalNotifyBody()
{
TypeCode =
,
Subject = msg
,
Content = "到你审批了,快到碗里来"
,
ToUserId = handlerId
,
LinkTo = "/entity/create?entityid=" + eventMessage.Context.EntityMetaData.EntityId + "&recordid=" + eventMessage.Context.ObjectId
});
}
}
}
}
}
四、总结
前面讲解了订阅者模式的基本概念及与观察者的区别,后面展示了具体实现及实际应用场景,大家记住一点就行,这些设计模式最终都是为了达到解藕的目的,要查看完整代码,请回到这一章
xms跨平台基础框架 - 基于.netcore
.netcore利用DI实现订阅者模式 - xms的更多相关文章
- .netcore之DI批量注入(支持泛型) - xms
一旦系统内模块比较多,按DI标准方法去逐个硬敲AddScoped/AddSingleton/AddTransient缺乏灵活性且效率低下,所以批量注入提供了很大的便捷性,特别是对于泛型的服务类,下面介 ...
- 利用DI实现级联删除 - xms跨平台基础框架 - 基于.netcore
一.引言 所谓级联删除是指删除一条记录后,附带关联记录也一起删除,比如删除客户后,联系人也一起删除: 以往我们会依赖于数据库表的外键约束,但存在着明显的问题,增加数据库压力.提示不友好.职责越界.事务 ...
- AngularJS的简单订阅发布模式例子
控制器之间的交互方式广播 broadcast, 发射 emit 事件 类似于 js中的事件 , 可以自己定义事件 向上传递直到 document 在AngularJs中 向上传递直到 rootScop ...
- js设计模式之代理模式以及订阅发布模式
为啥将两种模式放在一起呢?因为这样文章比较长啊. 写博客的目的我觉得首要目的是整理自己的知识点,进而优化个人所得知识体系.知识成为个人的知识,就在于能够用自己的话表达同一种意义. 本文是设计模式系列文 ...
- RabbitMQ (五) 订阅者模式之分发模式 ( fanout )
前面讲到了简单队列和工作队列. 这两种队列有个非常明显的缺点 : 生产者发送的消息,只能进入到一个队列. 消息只能进入到一个队列就意味着消息只能被一个消费者消费. 尽管工作队列模式中,一个队列中的消息 ...
- C#事件支持发布者/订阅者模式(观察者模式)
C#事件支持发布者/订阅者模式,发布者将事件通知给订阅者,而订阅者在事件发生时调用已经注册好的事件处理函数. public delegate void delUpdate(); //委 ...
- Android 订阅-发布者模式-详解
1.概念简述 Android 简称观察者模式, GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”. 有 ...
- Publisher/Subscriber 订阅-发布模式
Publisher/Subscriber 订阅-发布模式 本博后续将陆续整理这些年做的一些预研demo,及一些前沿技术的研究,与大家共研技术,共同进步. 关于发布订阅有很多种实现方式,下面主要介绍WC ...
- 设计模式---订阅发布模式(Subscribe/Publish)
设计模式---订阅发布模式(Subscribe/Publish) 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象.这个主题对象在自身状态变化时,会通知所有订阅者对象,使 ...
随机推荐
- Java集合总结—再也不怕面试问到集合了
Java集合总结 1.常见的集合 Map接口和Collection接口是所有集合框架的父接口: Collection接口的子接口包括:Set接口和List接口 Map接口的实现类主要有:HashMap ...
- JVM本地方法栈及native方法
看到虚拟机栈和本地方法栈的区别的时候有点疑惑,因为本地方法栈为虚拟机的Native方法服务.以下转载一篇关于native方法的介绍: http://blog.csdn.net/wike163/arti ...
- 解决VS2017授权问题及没有Add ArcGIS License Checking问题
内容源自:ArcGIS Engine+C#入门经典 老版本采用: 控件布局好后,需要对程序添加License许可.在Visual Studio的菜单栏上单击“项目”→单击“Add ArcGIS Lic ...
- 手写OOXML文档——导出xlsx格式表格文档
一.准备工作: 2个js库,另外把样式文件抽离出来 require('file-saver'); import JSZip from 'jszip' import {stylesData,theme1 ...
- Zabbix 2.2系列注入+getsehll
Zabbix 是一个开源的企业级性能监控解决方案. 官方网站:http://www.zabbix.com Zabbix 的jsrpc的profileIdx2参数存在insert方式的SQL注入漏洞,攻 ...
- Vue 全家桶,深入Vue 的世界
内容简介: Vue 实例上的属性 Vue 生命周期 Vue 数据绑定 computed 计算属性 watch 监听器 Vue 组件 Vue 组件 extend Vue 组件高级属性 Vue 的rend ...
- [Luogu3112] [USACO14DEC]后卫马克Guard Mark
题意翻译 FJ将飞盘抛向身高为H(1 <= H <= 1,000,000,000)的Mark,但是Mark被N(2 <= N <= 20)头牛包围.牛们可以叠成一个牛塔,如果叠 ...
- css 动画animation基本属性(干货)
/* 动画名称 */ animation-name: cloud; /* 属性定义动画完成一个周期所需要的时间,以秒或毫秒计 */ animation-duration:1s; /* 属性定义动画何时 ...
- 哈夫曼树C++实现详解
哈夫曼树的介绍 Huffman Tree,中文名是哈夫曼树或霍夫曼树,它是最优二叉树. 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树. 这个定 ...
- 清理git仓库
参考 https://harttle.land/2016/03/22/purge-large-files-in-gitrepo.html https://git-scm.com/docs/git-re ...