• Lind.DDD.Messaging框架通讯组件介绍


    回到目录

    大 家好,今天有时间来介绍一下Lind.DDD框架里的消息机制,消息发送这块一般的实现方法是将Email,SMS等集成到一个公用类库里,而本身 Email和SMS没什么关系,它们也不会有什么接口约定,即你想实现某种消息的多态发送,不需要程序代码,基本不可能实现,而在Lind.DDD里面, 大叔将它进行了抽象,消息有自己的统一接口,而对于email和sms只是一种实现而以,这样,就可以发挥面向对象的特性,在sms,email甚至是 rtx上进行消息的灵活切换了,说到这样,您心动了吧!

    Lind.DDD.Messaging框架图

    接口规范

        /// <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源码

    回到目录

  • 相关阅读:
    ABP 菜单 修改
    C# 过滤器
    RabbitMQ框架构建系列(三)——Net实现RabbitMQ之Producer
    RabbitMQ系列(二)RabbitMQ基础介绍
    RabbitMQ系列(一)AMPQ协议
    MVC 解读WebConfig
    MVC过滤器特性
    asp.net中使用JQueryEasyUI
    asp.net请求到响应的整个过程
    Redis的下载安装部署(Windows)
  • 原文地址:https://www.cnblogs.com/lori/p/5097747.html
Copyright © 2020-2023  润新知