回到目录

大 家好,今天有时间来介绍一下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. bootstrap-material-design-个人总结

    bootstrap-material-design-个人总结: 所需框架:1.boostrapt 3.0+2.jQuery 1.9.1+ 项目目录:Material/├── css/│ ├── boo ...

  2. Ajax_01之概述、响应

    1.URL.URI和URN URL:Unified Resource Locator:统一资源定位符: URI:Unified Resource Identifier:统一资源识别符: URN:Uni ...

  3. 深入浅出Hyper-V网络虚拟化技术

    年后综合症刚刚消失殆尽,转眼就要迎接各种新的工作任务了:之前写过一篇有关hyper-v网络虚拟化内容的博文,主要是从操作系统层面入手,概要性的总结了一下,基本也都是参考了大部分官方内容再加以个人修饰: ...

  4. 【WP开发】读写剪贴板

    在WP 8.1中只有Silverlight App支持操作剪贴板的API,Runtime App并不支持.不过,在WP 10中也引入了可以操作剪贴板的API. 顺便说点题外话,有人会说,我8.1的开发 ...

  5. 前端MVVM框架avalon揭秘 - 双向绑定原理

    avalon大家可能不熟悉,但是Knockout估计或多或少听过用过,那么说说KO的几个概念 监控属性(Observables)和依赖跟踪(Dependency tracking) 声明式绑定(Dec ...

  6. Web APi之认证(Authentication)两种实现方式后续【三】(十五)

    前言 之前一直在找工作中,过程也是令人着实的心塞,最后还是稳定了下来,博客也停止更新快一个月了,学如逆水行舟,不进则退,之前学的东西没怎么用,也忘记了一点,不过至少由于是切身研究,本质以及原理上的脉络 ...

  7. SubSonic3.0插件分页查询速度测试

    使用SubSonic3.0一段时间了,一直都想找机会测试一下各种查询分页速度,对比一下插件的查询效率到底怎么样,所以昨天写好了测试程序,准备好1K.1W.10W.50W和100W记录的数据表,早上详细 ...

  8. Ajax JQuery HTML 提交上传文件File HTML+ Ajax+ASP.NET+ WebService

    起因:公司最近有些项目用到了HTML+WebService的组合,发现访问速度等都快了许多,但是由于通过Ajax只能应付一些简单的文字类的传输,上传文件就捉襟见肘了,如果一直引用第三方的swf之类上传 ...

  9. Linux笔记之——Linux关机命令详解(转)

    原文连接:http://www.jb51.net/os/RedHat/1334.html 在linux下一些常用的关机/重启命令有shutdown.halt.reboot.及init,它们都可以达到重 ...

  10. 如何用Dummy实例执行数据库的还原和恢复

    今天实验了一下,如何在所有文件,包括数据文件,在线日志文件,控制文件都丢失的情况下,利用RMAN备份恢复和还原数据库.该实验的重点是用到了Dummy实例. 具体步骤如下: 备份数据库 [oracle@ ...