打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
我心中的核心组件(可插拔的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等等。

有了主体,再来看一下主要消息的设置,我们可以使用config中的section节点来做这事,如下:

config中的配置信息如下:

OK,我们再来看一下,消息的类型,目前可以定义两种消息,当然,为了组件的扩展性,你的类型可以通过IoC去代替它,这样可以避免程序中的硬编码,维护更方便

最后来看一下生产消息的对象,使用了简单工厂模式,当然这只是个例子,实现中,它应该是使用IoC动态生产的,呵呵。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
规则引擎 Drools(七):运行时组件 Channel
09. SDR 发布订阅
单点登录CAS与权限管理框架Shiro集成
C#使用RabbitMQ
RabbitMQ系列(一):Windows下RabbitMQ安装及入门
在集成Spring Axis 的环境下webservice的发布和部署 - Aflye...
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服