我心中的核心组件(可插拔的AOP)~第五回 消息组件
之所以把发消息拿出来,完全是因为微软的orchard项目,在这个项目里,将公用的与领域无关的功能模块进行抽象,形成了一个个的组件,这些组件通过引用和注入的方式进行工作,感觉对于应用程序的扩展性上有很大的提高,消息组件的提出是因为它的不固定性,从小方面说,项目模块的发消息的方式可能是不同的,有过模块是email,有的是数据库,有的是短信;而从大的方面说,对于项目与项目来说,它们发消息的方式也可能不同,所以,把它抽象出来,就显得很必要了。
对于一个消息来说,它的行为很固定,即发消息,Send,而考虑到网络阻塞问题,我们也同样提供了异常消息的发送,接口规范如下:
/// <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">A content item to send the message to.</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(string recipient, MessageType type, string subject, string body); /// <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, MessageType type, string subject, string body); /// <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, MessageType type, string subject, string body, bool isAsync); }
有了规范,就是实现这个规范,我们以Email为例,看一下 Email消息发送的实现代码:
/// <summary>
/// 默认发消息服务
/// </summary>
public class EmailMessageManager : IMessageManager
{ #region Delegate & Event
/// <summary>
/// 加入发送队列中
/// </summary>
/// <param name="context"></param>
public delegate void SendingEventHandler(MessageContext context);
/// <summary>
/// 发送消息
/// </summary>
/// <param name="context"></param>
public delegate void SentEventHandler(MessageContext context);
/// <summary>
/// 加入发送队列中
/// </summary>
public event SendingEventHandler Sending;
/// <summary>
/// 发送消息
/// </summary>
public event SentEventHandler Sent; void OnSending(MessageContext context)
{
if (Sending != null)
Sending(context);
}
void OnSent(MessageContext context)
{
if (Sent != null)
Sent(context);
}
#endregion #region IMessageManager 成员 public void Send(string recipient, MessageType type, string subject, string body)
{
Send(new List<string> { recipient }, type, subject, body);
} public void Send(IEnumerable<string> recipients, MessageType type, string subject, string body)
{
Send(recipients, type, subject, body, false);
} public void Send(IEnumerable<string> recipients, MessageType type, string subject, string body, bool isAsync)
{
if (recipients != null && recipients.Any())
{
using (SmtpClient client = new SmtpClient()
{
Host = MessageManager.Instance.Host,
Port = MessageManager.Instance.Port,
Credentials = new NetworkCredential(MessageManager.Instance.UserName, MessageManager.Instance.Password),
EnableSsl = false,//设置为true会出现"服务器不支持安全连接的错误"
DeliveryMethod = SmtpDeliveryMethod.Network,
})
{
#region Send Message
var mail = new MailMessage
{
From = new MailAddress(MessageManager.Instance.Address, MessageManager.Instance.DisplayName),
Subject = subject,
Body = body,
IsBodyHtml = true,
};
MailAddressCollection mailAddressCollection = new MailAddressCollection();
recipients.ToList().ForEach(i =>
{
mail.To.Add(i);
});
if (isAsync)
{
client.SendCompleted += new SendCompletedEventHandler(client_SendCompleted);
client.SendAsync(mail, recipients);
}
else
{
client.Send(mail);
}
#endregion
}
}
} void client_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
string arr = null;
(e.UserState as List<string>).ToList().ForEach(i => { arr += i; });
//发送完成后要做的事件,可能是写日志
} #endregion
}
OK,有了消息的行业,我们再来看它的主体,即消息体,一般由发送者,接受者集合,主题,正文,是否立即发送等几个参数组成,下面来分享一下:补充一句,如果消息体的实现是单一的,我们可以把行为写在消息体里,形成一个消息上下文,微软很多架构都是这样做的,如EF数据上下文DbContext,ObjectContext,linq to sql上下文DataContext,Http上下文HttpContext等等。
/// <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>();
}
}
有了主体,再来看一下主要消息的设置,我们可以使用config中的section节点来做这事,如下:
/// <summary>
/// Message块,在web.config中提供Message块定义
/// </summary>
internal class MessageSection : ConfigurationSection
{
/// <summary>
/// 账号
/// </summary>
[ConfigurationProperty("UserName", DefaultValue = "bfyxzls")]
public string UserName
{
get { return (string)this["UserName"]; }
set { this["UserName"] = value; }
}
/// <summary>
/// 密码
/// </summary>
[ConfigurationProperty("Password", DefaultValue = "gemini123")]
public string Password
{
get { return (string)this["Password"]; }
set { this["Password"] = value; }
}
/// <summary>
/// 邮件服务器地址
/// </summary>
[ConfigurationProperty("Host", DefaultValue = "smtp.sina.com")]
public string Host
{
get { return (string)this["Host"]; }
set { this["Host"] = value; }
}
/// <summary>
/// 端口号
/// </summary>
[ConfigurationProperty("Port", DefaultValue = "")]
public int Port
{
get { return (int)this["Port"]; }
set { this["Port"] = value; }
}
/// <summary>
/// 发件人的email地址
/// </summary>
[ConfigurationProperty("Address", DefaultValue = "bfyxzls@sina.com")]
public string Address
{
get { return (string)this["Address"]; }
set { this["Address"] = value; }
}
/// <summary>
/// 发送之后,在收件人端显示的名称
/// </summary>
[ConfigurationProperty("DisplayName", DefaultValue = "占占")]
public string DisplayName
{
get { return (string)this["DisplayName"]; }
set { this["DisplayName"] = value; }
} }
config中的配置信息如下:
<configuration>
<configSections>
<section name="MessageSection" type="Messaging.MessageSection"/>
</configSections>
<MessageSection UserName="" Password="gemini123" Host="smtp.qq.com" Port="" Address="853066980@qq.com" DisplayName="大占"></MessageSection>
</configuration>
OK,我们再来看一下,消息的类型,目前可以定义两种消息,当然,为了组件的扩展性,你的类型可以通过IoC去代替它,这样可以避免程序中的硬编码,维护更方便
/// <summary>
/// 消息类型
/// </summary>
public enum MessageType
{
/// <summary>
/// 电子邮件
/// </summary>
Email,
/// <summary>
/// 短信息
/// </summary>
ShortMessage, }
最后来看一下生产消息的对象,使用了简单工厂模式,当然这只是个例子,实现中,它应该是使用IoC动态生产的,呵呵。
/// <summary>
/// 消息生产者
/// </summary>
public class MessageFactory
{
/// <summary>
/// 消息对象
/// </summary>
public static IMessageManager Instance
{
get
{
MessageType messageType = MessageType.Email;//通过配置产生
switch (messageType)
{
case MessageType.Email:
return new EmailMessageManager();
case MessageType.ShortMessage:
throw new NotImplementedException("没实现呢,呵呵");
default:
throw new ArgumentException("您输入的参数有误");
}
}
}
}
我心中的核心组件(可插拔的AOP)~第五回 消息组件的更多相关文章
- 我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器
回到目录 AOP面向切面的编程,也称面向方面的编程,我更青睐于前面的叫法,将一个大系统切成多个独立的部分,而这个独立的部分又可以方便的插拔在其它领域的系统之中,这种编程的方式我们叫它面向切面,而这些独 ...
- 我心中的核心组件(可插拔的AOP)~大话开篇及目录
回到占占推荐博客索引 核心组件 我心中的核心组件,核心组件就是我认为在项目中比较常用的功能,如日志,异常处理,消息,邮件,队列服务,调度,缓存,持久化,分布式文件存储,NoSQL存储,IoC容器,方法 ...
- 我心中的核心组件(可插拔的AOP)~第四回 异常拦截器
回到目录 之前说过有关拦截器的文章,第二回 缓存拦截器,事实上,在那讲里说的最多是AOP和缓存组件,对于拦截的概念并没有详细的说明,这一讲,不说AOP,主要说一下拦截器,拦截器Interceptio ...
- 我心中的核心组件(可插拔的AOP)~第六回 消息组件~续
回到目录 上一回写消息组件已经是很久之前的事了,这一次准备把消息组件后续的东西说一下,事实上,第一篇文章主要讲的是发消息,而这一讲最要讲的是收消息,简单的说,就是消息到了服务器之后,如何从服务器实时的 ...
- 我心中的核心组件(可插拔的AOP)~调度组件quartz.net
回到目录 quartz.net是一个任务调度组件,它可以灵活的设置你的调试方式,按时间,按日期,按周期都可以很容易的实现,quartz不仅可以用在web中,而且还可以部署在winform,winser ...
- 我心中的核心组件(可插拔的AOP)~第十二回 IoC组件Unity
回到目录 说在前 Ioc组件有很多,之前也介绍过autofac,castle等,今天再来说一下在微软Nlayer DDD架构里使用的unity组件,今天主要说一下依靠注入,如果希望看拦截的用法,可以阅 ...
- 我心中的核心组件(可插拔的AOP)~第十三回 实现AOP的拦截组件Unity.Interception
回到目录 说在前 本节主要说一下Unity家族里的拦截组件,对于方法拦截有很多组件提供,基本上每个Ioc组件都有对它的实现,如autofac,它主要用在orchard项目里,而castle也有以拦截的 ...
- 我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)
回到目录 之前的讲过两篇关于日志组件的文章,分别是<第一回 日志记录组件之自主的Vlog>和<第三回 日志记录组件之log4net>,而今天主要说一下我自己开发的另一种日志 ...
- 我心中的核心组件(可插拔的AOP)~调度组件quartz.net续~任务管理器的开发
回到目录 对于任务调度来说,越来越多的团队选择了quartz,它在java和.net环境下表现都十分优秀,配置简单,功能强大,时间表达式配置灵活,但在使用时,还是感觉缺点什么,怎么说,你在服务器上安装 ...
随机推荐
- http statusCode(状态码) 200、300、400、500序列
201-206都表示服务器成功处理了请求的状态代码,说明网页可以正常访问. 200(成功) 服务器已成功处理了请求.通常,这表示服务器提供了请求的网页. 201(已创建) ...
- tomcat的CATALINA_HOME可以不用设置
不配置tomcat的环境变量也是可以运行的 用记事本打开tomcat/bin目录下面的startup.bat 在文本的前一部分有下面的脚本代码 rem Guess CATALINA_HOME if n ...
- reporting services rdl文件如何不分页
进入rdl文件中的xml内容,找到<page></page>标签,在该标签中,添加如下属性, <InteractiveHeight>0in</Interact ...
- Windows Phone 8.1 新特性 - 常用的启动器
本篇为大家介绍一下 Windows Phone 8.1 中部分常用启动器的实现方式.分别是 呼叫电话.发送短信.发送邮件.添加约会到日历.启动地图.地图路线显示.地图下载 和 地图更新. 1. 呼叫电 ...
- hdu 3397 Sequence operation(线段树:区间更新)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给你一个长度为n的0,1序列,支持下列五种操作, 操作0(0 a b):将a到b这个区间的 ...
- TortoiseSVN客户端使用说明
TortoiseSVN客户端使用说明 TortoiseSVN不是一个独立的窗口程序,而是集成在windows右键菜单中,下面对TortoiseSVN的菜单项做简要的说明.01.SVN Checkout ...
- Python学习之路—Day1
第1章 Python语言简介 1.1 Python是什么 Python(英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn)是什么呢?简单的说,它是一种计算机编程语言及一组配套的软件工具和库. ...
- dataview将excel表格的数据导出成txt文件
有时候需要处理大量的数据,且这些数据又存在于excel表格内,在平时的时候,我是非常喜欢这样的数据的,因为只要是excel表格内的数据,处理起来的方法就很方便.也可能我平时遇见的数据总是以一种杂乱无章 ...
- day9---多线程,线程锁,队列
进程.线程 http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html 使用threading模块实现多线程编程[综述] Pyt ...
- fallacies of distributed computing
The network is reliable. Latency is zero. Bandwidth is infinite. The network is secure. Topology doe ...