Lind.DDD.Messaging框架通讯组件介绍
大 家好,今天有时间来介绍一下Lind.DDD框架里的消息机制,消息发送这块一般的实现方法是将Email,SMS等集成到一个公用类库里,而本身 Email和SMS没什么关系,它们也不会有什么接口约定,即你想实现某种消息的多态发送,不需要程序代码,基本不可能实现,而在Lind.DDD里面, 大叔将它进行了抽象,消息有自己的统一接口,而对于email和sms只是一种实现而以,这样,就可以发挥面向对象的特性,在sms,email甚至是 rtx上进行消息的灵活切换了,说到这样,您心动了吧!
Lind.DDD.Messaging框架图
aaarticlea/png;base64,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" alt="" />
接口规范
/// <summary>
/// Message Interface
/// Author:Garrett
/// </summary>
public interface IMessageManager
{
/// <summary>
/// Sends a message to a channel using a content item as the recipient
/// </summary>
/// <param name="recipient">接收者</param>
/// <param name="subject">主题</param>
/// <param name="body">消息主体</param>
/// <param name="serverVirtualPath">本参数可以没有,服务端模块级路径,只在xmpp中有意义</param>
void Send(string recipient, string subject, string body, string serverVirtualPath = null); /// <summary>
/// Sends a message to a channel using a set of content items as the recipients
/// </summary>
/// <param name="recipients">A set of content items to send the message to. Only one message may be sent if the channel manages it.</param>
/// <param name="type">A custom string specifying what type of message is sent. Used in even handlers to define the message.</param>
/// <param name="service">The name of the channel to use, e.g. "email"</param>
/// <param name="properties">A set of specific properties for the channel.</param>
void Send(IEnumerable<string> recipients, string subject, string body, string serverVirtualPath = null); /// <summary>
/// Async Sends a message to a channel using a set of content items as the recipients
/// </summary>
/// <param name="recipients">A set of content items to send the message to. Only one message may be sent if the channel manages it.</param>
/// <param name="type">A custom string specifying what type of message is sent. Used in even handlers to define the message.</param>
/// <param name="service">The name of the channel to use, e.g. "email"</param>
/// <param name="properties">A set of specific properties for the channel.</param>
/// <param name="isAsync">is Async</param>
void Send(IEnumerable<string> recipients, string subject, string body, bool isAsync, string serverVirtualPath = null);
}
从接口定义上,我们看到了异步的影子,大叔把异步这块写在了参数上,当然,一般情况来说,消息应该都是异步的。
消息上下文
/// <summary>
/// 消息实体
/// </summary>
public class MessageContext
{
/// <summary>
/// 消息类型
/// </summary>
public MessageType Type { get; set; }
/// <summary>
/// 消息头
/// </summary>
public string Subject { get; set; }
/// <summary>
/// 消息正文
/// </summary>
public string Body { get; set; }
/// <summary>
/// 接受方地址列表
/// </summary>
public IEnumerable<string> Addresses { get; set; }
/// <summary>
/// 是否处于准备发送状态
/// </summary>
public bool MessagePrepared { get; set; } public MessageContext()
{
Addresses = Enumerable.Empty<string>();//这时Addresses!=null,使用Addresses.ToList().ForEach(i => Console.WriteLine(i));不会引发异常
}
}
消息上下文就是消息的对象,类型于EF里的DataContext数据上下文或者HttpContext上下文,都是指实现某些功能的数据对象
消息生产者
/// <summary>
/// 消息生产者
/// 具体消息生产者是单例,如Email,SMS,Rtx等
/// </summary>
public sealed class MessageFactory
{
/// <summary>
/// 消息工厂
/// </summary>
public static IMessageManager GetService(MessageType messageType)
{
switch (messageType)
{
case MessageType.Email:
return EmailMessageManager.Instance;
case MessageType.SMS:
return SMSMessageManager.Instance;
case MessageType.RTX:
return RTXMessageManager.Instance;
case MessageType.XMPP:
return XMPPMessageManager.Instance;
default:
throw new NotImplementedException("消息生产者未被识别...");
}
} }
从生产者代码上可以看出,在一个领域项目里,你可以通过GetService来使用不同的消息,这是对象的,这前大叔的设计存在一些局限性,一个项目只能用一种消息机制,这对于项目来说,是不能满足了,所以,大叔在Lind.DDD框架里对它进行了改善!
Email实现者
/// <summary>
///Email消息服务
/// </summary>
internal class EmailMessageManager : IMessageManager
{
#region Singleton
private static object lockObj = new object();
public static EmailMessageManager Instance; static string email_Address = ConfigurationManager.AppSettings["Email_Address"];
static string email_DisplayName = ConfigurationManager.AppSettings["Email_DisplayName"];
static string email_Host = ConfigurationManager.AppSettings["Email_Host"];
static string email_Password = ConfigurationManager.AppSettings["Email_Password"];
static int email_Port = Convert.ToInt32(ConfigurationManager.AppSettings["Email_Port"] ?? "21");
static string email_UserName = ConfigurationManager.AppSettings["Email_UserName"]; static EmailMessageManager()
{
lock (lockObj)
{
if (Instance == null)
Instance = new EmailMessageManager();
}
}
private EmailMessageManager()
{ }
#endregion #region IMessageManager 成员 public void Send(string recipient, string subject, string body, string serverVirtualPath = null)
{
Send(new List<string> { recipient }, subject, body);
} public void Send(IEnumerable<string> recipients, string subject, string body, string serverVirtualPath = null)
{
Send(recipients, subject, body, false);
} public void Send(IEnumerable<string> recipients, string subject, string body, bool isAsync, string serverVirtualPath = null)
{
try
{
if (recipients != null && recipients.Any())
{
using (SmtpClient client = new SmtpClient()
{
Host = email_Host,
Port = email_Port,
Credentials = new NetworkCredential(email_UserName, email_Password),
EnableSsl = false,//设置为true会出现"服务器不支持安全连接的错误"
DeliveryMethod = SmtpDeliveryMethod.Network,
})
{ #region Send Message
var mail = new MailMessage
{
From = new MailAddress(email_Address, email_DisplayName),
Subject = subject,
Body = body,
IsBodyHtml = true,
};
MailAddressCollection mailAddressCollection = new MailAddressCollection();
recipients.ToList().ForEach(i =>
{
//email有效性验证
if (new Regex(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$").IsMatch(i))
mail.To.Add(i);
});
if (isAsync)
{
client.SendCompleted += new SendCompletedEventHandler(client_SendCompleted);
client.SendAsync(mail, recipients);
}
else
{
client.Send(mail);
}
#endregion
}
}
}
catch (Exception ex)
{
LoggerFactory.Instance.Logger_Info(ex.Message);
} } void client_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
string arr = null;
(e.UserState as List<string>).ToList().ForEach(i => { arr += i; });
//发送完成后要做的事件,可能是写日志
} #endregion
}
通过代码可以看它自已是个internal的,即对外不公开,对外只能通过消息生成者进行访问,它与SMS,RTX形成了一种策略模式的概念。
SMS实现者,请看Lind.DDD源码
RTX实现者,请看Lind.DDD源码
XMPP实现者,请看Lind.DDD源码
Lind.DDD.Messaging框架通讯组件介绍的更多相关文章
- Lind.DDD.Caching分布式数据集缓存介绍
回到目录 戏说当年 大叔原创的分布式数据集缓存在之前的企业级框架里介绍过,大家可以关注<我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器>,而今天主要对Lind.DDD.Cachin ...
- Lind.DDD.LindAspects方法拦截的介绍
回到目录 什么是LindAspects 之前写了关于Aspects的文章<Lind.DDD.Aspects通过Plugins实现方法的动态拦截~Lind里的AOP>,今天主要在设计思想上进 ...
- Lind.DDD.SSO单点登陆组件的使用(原创)
回到目录 一般sso的说明 在Lind.DDD框架里,有对单点登陆的集成,原理就是各个网站去sso网站统一登陆授权,之后在sso网站将登陆的token进行存储,存储方式随你(cache,redis,m ...
- Lind.DDD敏捷领域驱动框架~介绍
回到占占推荐博客索引 最近觉得自己的框架过于复杂,在实现开发使用中有些不爽,自己的朋友们也经常和我说,框架太麻烦了,要引用的类库太多:之前架构之所以这样设计,完全出于对职责分离和代码附复用的考虑,主要 ...
- Lind.DDD敏捷领域驱动框架~Lind.DDD各层介绍
回到目录 Lind.DDD项目主要面向敏捷,快速开发,领域驱动等,对于它的分层也是能合并的合并,比之前大叔的框架分层更粗糙一些,或者说更大胆一些,在开发人员使用上,可能会感觉更方便了,更益使用了,这就 ...
- Lind.DDD.Paging分页模块介绍
回到目录 分页组件网上有很多,MVC.Pager,JSPager等,通过实现方式大体分为前端分页和后端分页,前端分页是前台对list内存本地集合进行分页,缺点就是在大数据情况下,内存占用过高:后端分页 ...
- Lind.DDD.Repositories.Redis层介绍
回到目录 之前已经发生了 大叔之前介绍过关于redis的文章,有缓存,队列,分布式pub/sub,数据集缓存以及仓储redis的实现等等,而今天在Lind.DDD的持久化组件里,redis当然也有一席 ...
- Lind.DDD.Domain领域模型介绍
回到目录 Lind.DDD.Domain位于Lind.DDD核心项目中,它主要面向领域实体而设计,由一个IEntity的标识接口,EntityBase基类和N个Entity实体类组成,其中IEntit ...
- Lind.DDD.Events领域事件介绍
回到目录 闲话多说 领域事件大叔感觉是最不好讲的一篇文章,所以拖欠了很久,但最终还是在2015年年前(阴历)把这个知识点讲一下,事件这个东西早在C#1.0时代就有了,那时学起来也是一个费劲,什么是委托 ...
随机推荐
- spring快速入门(四)
一.在spring快速入门(三)的基础上,我们来了解BeanFactory及配置. Client package com.murong.client; import org.springframewo ...
- VVDocumenter 使用
函数说明文档插件下载链接 https://github.com/onevcat/VVDocumenter-Xcode 下载后,直接运行项目 升级Xcode后可能不能再次使用,需要做一些处理从Xcode ...
- 带你走近AngularJS - 基本功能介绍
带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自定义指令 ------------- ...
- 修改windows自带的Ctrl+Space输入法切换快捷键
使用场景: 多为我等码农使用一些编辑器时,编辑器的默认代码提示热键为 ctrl+space ,但这个热键被系统的输入法开关占用.如果遇到可以设置快捷键的编辑器还好,要是不能设置的话(比如火狐浏览器的代 ...
- java compiler level does not match the version of the installed java project facet 解决方案
项目出现 java compiler level does not match the version of the installed java project facet 错误,一般是项目移植出现 ...
- Introduction of OpenCascade Foundation Classes
Introduction of OpenCascade Foundation Classes Open CASCADE基础类简介 eryar@163.com 一.简介 1. 基础类概述 Foundat ...
- MVC4做网站后台:栏目管理3、删除栏目与左侧列表菜单
一.左侧列表菜单 打开视图Menu.cshtml,增加部分见红框 在category中添加脚本 //栏目菜单加载完毕函数 function CategoryMenu_Ready() { $('#cat ...
- 深入理解this机制系列第三篇——箭头函数
× 目录 [1]痛点 [2]解决 [3]基本用法[4]回调函数[5]注意事项 前面的话 this机制与函数调用有关,而作用域则与函数定义有关.有没有什么是可以将this机制和作用域联系起来的呢?本文将 ...
- First Blog
俗话说“笨鸟先飞”,遗憾的是我这只笨鸟直到今天才意识到个人博客的重要性. 原来记录下学习生活中的每一丝领悟与思考,可以让个人内在,对知识的理解得到更好的升华. 有梦的人很美,追梦的人更美.像我的座右铭 ...
- 基于keepalived搭建MySQL的高可用集群
MySQL的高可用方案一般有如下几种: keepalived+双主,MHA,MMM,Heartbeat+DRBD,PXC,Galera Cluster 比较常用的是keepalived+双主,MHA和 ...