1. 程式人生 > >Lind.DDD.Messaging框架通訊元件介紹

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原始碼

回到目錄