回到目录

大 家好,今天有时间来介绍一下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框架通讯组件介绍的更多相关文章

  1. Lind.DDD.Caching分布式数据集缓存介绍

    回到目录 戏说当年 大叔原创的分布式数据集缓存在之前的企业级框架里介绍过,大家可以关注<我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器>,而今天主要对Lind.DDD.Cachin ...

  2. Lind.DDD.LindAspects方法拦截的介绍

    回到目录 什么是LindAspects 之前写了关于Aspects的文章<Lind.DDD.Aspects通过Plugins实现方法的动态拦截~Lind里的AOP>,今天主要在设计思想上进 ...

  3. Lind.DDD.SSO单点登陆组件的使用(原创)

    回到目录 一般sso的说明 在Lind.DDD框架里,有对单点登陆的集成,原理就是各个网站去sso网站统一登陆授权,之后在sso网站将登陆的token进行存储,存储方式随你(cache,redis,m ...

  4. Lind.DDD敏捷领域驱动框架~介绍

    回到占占推荐博客索引 最近觉得自己的框架过于复杂,在实现开发使用中有些不爽,自己的朋友们也经常和我说,框架太麻烦了,要引用的类库太多:之前架构之所以这样设计,完全出于对职责分离和代码附复用的考虑,主要 ...

  5. Lind.DDD敏捷领域驱动框架~Lind.DDD各层介绍

    回到目录 Lind.DDD项目主要面向敏捷,快速开发,领域驱动等,对于它的分层也是能合并的合并,比之前大叔的框架分层更粗糙一些,或者说更大胆一些,在开发人员使用上,可能会感觉更方便了,更益使用了,这就 ...

  6. Lind.DDD.Paging分页模块介绍

    回到目录 分页组件网上有很多,MVC.Pager,JSPager等,通过实现方式大体分为前端分页和后端分页,前端分页是前台对list内存本地集合进行分页,缺点就是在大数据情况下,内存占用过高:后端分页 ...

  7. Lind.DDD.Repositories.Redis层介绍

    回到目录 之前已经发生了 大叔之前介绍过关于redis的文章,有缓存,队列,分布式pub/sub,数据集缓存以及仓储redis的实现等等,而今天在Lind.DDD的持久化组件里,redis当然也有一席 ...

  8. Lind.DDD.Domain领域模型介绍

    回到目录 Lind.DDD.Domain位于Lind.DDD核心项目中,它主要面向领域实体而设计,由一个IEntity的标识接口,EntityBase基类和N个Entity实体类组成,其中IEntit ...

  9. Lind.DDD.Events领域事件介绍

    回到目录 闲话多说 领域事件大叔感觉是最不好讲的一篇文章,所以拖欠了很久,但最终还是在2015年年前(阴历)把这个知识点讲一下,事件这个东西早在C#1.0时代就有了,那时学起来也是一个费劲,什么是委托 ...

随机推荐

  1. Echarts使用

    Echarts使用 |版权声明:此文为本人原创,望尊重原创 前言:     和朋友聊天的过程中,朋友提到了Echarts.我当时不知道那个是用来做什么的.回到家我就百度了,开始自己看文档学习.本文是自 ...

  2. 谈初学Java历程

    学习Java一个月左右,本来很早就想好好静下心来写一点东西了.但由于不想手写,文档写了不知道放在哪好,所以一直拖着.最近注册了博客园,还是挺方便的. 即将大学毕业了,则面临了所以大学生所面临的问题,就 ...

  3. is_null, empty, isset, unset对比

    is_null, empty, isset, unset 我们先来看看这4个函数的描述 isset 判断变量是否已存在(配置)unset 把变量删除(释放)掉empty 判断变量是否为空is_null ...

  4. weblogic10内存溢出解决方法

    在开发过程中经常会遇到weblogic内存溢出问题,用下面的办法解决了. 找到domain/bin下的setDomainEnv.cmd文件,里面可以找到以下四行代码,将值该打一倍,重启服务. set ...

  5. Spring学习记录(四)---bean之间的关系:继承、依赖

         继承 这里说的继承和java的继承是不一样的,不是父类子类.但思想很相似,是父bean和子bean 1.父bean是一个实例时.它本身是一个完整的bean 2.父bean是模板,抽象bean ...

  6. Security10:授予访问Object的权限

    1,将访问Object的权限授予Database Role 或 User 的语法如下 GRANT <permission> [ ,...n ] ON [ OBJECT :: ][ sche ...

  7. 深入理解DOM节点类型第七篇——文档节点DOCUMENT

    × 目录 [1]特征 [2]快捷访问 [3]文档写入 前面的话 文档节点document,隶属于表示浏览器的window对象,它表示网页页面,又被称为根节点.本文将详细介绍文档节点document的内 ...

  8. EntityFramework之原始查询如何查询未映射的值,你又知道多少?

    前言 今天又倒腾了下EF,如题所示,遇到了一些问题,并最终通过尝试找到了解决方案,可能不是最终的解决方案,若你有更好的解决方案,望告知,同时通过阅读此文,定让你收获不少. 引入 当我们查询时一直是中规 ...

  9. 解决FragmentTabHost切换标题栏变更问题

    现在都流行FragmentTabHost布局.但是所有的fragment都是共享一个actionbar,但是我们又想给每个fragment定义自定义的标题栏.百度google了好久也没有找到解决方案. ...

  10. Util应用程序框架公共操作类(九):Lambda表达式扩展

    上一篇对Lambda表达式公共操作类进行了一些增强,本篇使用扩展方法对Lambda表达式进行扩展. 修改Util项目的Extensions.Expression.cs文件,代码如下. using Sy ...