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

回到目录

时间: 2024-10-12 02:41:59

Lind.DDD.Messaging框架通讯组件介绍的相关文章

Lind.DDD.Caching分布式数据集缓存介绍

戏说当年 大叔原创的分布式数据集缓存在之前的企业级框架里介绍过,大家可以关注<我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器>,而今天主要对Lind.DDD.Caching进行更全面的解决,设计思想和主要核心内容进行讲解.其实在很多缓存架构在业界有很多,向.net运行时里也有Cache,也可以实现简单的数据缓存的功能,向前几年页面的静态化比较流行,就出现了很多Http的"拦截器",对当前HTTP响应的内容进行完整的页面缓存,缓存的文件大多数存储到磁盘里,访问的时间直

Spring MVC:框架及其组件介绍

图片来自百度 1.发起请求到前端控制器 2.前端控制器请求handlerMapping查找handler 可以根据xml配置 注解进行查找3.处理器映射器handlerMapping向前端控制器返回handler4.前端控制器调用处理器适配器处理handler5.处理器适配器执行handler6.handler处理完给适配器返回modelAndView7.处理器适配器向前端控制器返回ModelAndView    ModelAndView是SpringMVX+C的底层对象8.前端控制器请求视图解

Lind.DDD敏捷领域驱动框架~介绍

最近觉得自己的框架过于复杂,在实现开发使用中有些不爽,自己的朋友们也经常和我说,框架太麻烦了,要引用的类库太多:之前架构之所以这样设计,完全出于对职责分离和代码附复用的考虑,主要参考了微软的DDD大作<N_LayerAPP>这个项目,而在这几年的项目开发用,也尝到了这种职责分享框架的甜头,但在最近的开发中,也看到了其它框架的出现,如<ABP>项目,它主张简单框架,敏捷开发,在项目引用上将核心类库和持久层进行抽象分离,复用在各位领域项目之中,这在项目整个感觉上更加简单,也更容易被人们

Lind.DDD敏捷领域驱动框架~Lind.DDD各层介绍

回到目录 Lind.DDD项目主要面向敏捷,快速开发,领域驱动等,对于它的分层也是能合并的合并,比之前大叔的框架分层更粗糙一些,或者说更大胆一些,在开发人员使用上,可能会感觉更方便了,更益使用了,这就是大叔开发Lind.DDD框架的目的,让一切变得更简单... Lind.DDD层 主要是公用方法,组件,规约等,如日志组件(Logger),消息组件(Messaging),IOC,AOP,缓存(Caching),异常,请求/响应,用户授权(Authorization),安全校验,领域模型(Domai

Lind.DDD.Paging分页模块介绍

回到目录 分页组件网上有很多,MVC.Pager,JSPager等,通过实现方式大体分为前端分页和后端分页,前端分页是前台对list内存本地集合进行分页,缺点就是在大数据情况下,内存占用过高:后端分页就是UI把要返回的页号告诉后台,由后台组织数据并返回,这种方法就是我们经常看到的了:而根据后台集合种类又可以分类List和IQueryable,前者是本地集合,在返回数据时,直接把第几页共几条的集合返回:IQueryable是预查询集合,它是Linq的产物,在很多地里它不通用,除非你的ORM框架支持

Lind.DDD.Repositories.Redis层介绍

回到目录 之前已经发生了 大叔之前介绍过关于redis的文章,有缓存,队列,分布式pub/sub,数据集缓存以及仓储redis的实现等等,而今天在Lind.DDD的持久化组件里,redis当然也有一席之地,作为当今最红的key/value存储机制,它在nosql的阵营中发挥着无可代替的作用! 下面是redis文章系列的目录,大家可以进行参考,看目录 Redis学习笔记~Redis在windows环境下的安装 Redis学习笔记~Redis在.net中的应用 Redis学习笔记~Redis提供的五

Lind.DDD.Events领域事件介绍

回到目录 闲话多说 领域事件大叔感觉是最不好讲的一篇文章,所以拖欠了很久,但最终还是在2015年年前(阴历)把这个知识点讲一下,事件这个东西早在C#1.0时代就有了,那时学起来也是一个费劲,什么是委托,哪个是事件,搞的大家是糊里糊涂,进入C#2.0时代后,大叔也买了一本书,对于delegate和event这两个知识点看了至少有20几遍,感觉稍微有点明白了,明白了其中的真谛和用意. 委托:方法的规范,方法的模板,可以代表一类方法的集合 事件:委托的实例,事件在使用之前需要为它赋值,当然赋的就是一个

Lind.DDD.Domain领域模型介绍

回到目录 Lind.DDD.Domain位于Lind.DDD核心项目中,它主要面向领域实体而设计,由一个IEntity的标识接口,EntityBase基类和N个Entity实体类组成,其中IEntity主要用来标识,在仓储操作时,用它来表明操作的实体范围和约束:EntityBase定义了几个公用的属性,为了避免代码的重复,特意将状态,插入时间和更新时间定义到了EntityBase里,而为何不将主键定义进来呢,主要考虑到主键的类型是为确实的,还有就是不同类型的主键可能需要实现不同的特性,如Mong

Lind.DDD.Authorization用户授权介绍

回到目录 Lind.DDD.Authorization是Lind.DDD框架的组成部分,之所以把它封装到框架里,原因就是它的通用性,几乎在任何一个系统中,都少不了用户授权功能,用户授权对于任何一个系统来说都是必要的,像管理型的页面都需要用户先去登陆,然后拿到凭证,才可以进行访问,这在MVC和WebApi体系结构里是很容易实现的,像过滤器里的AuthorizeAttribute和ActionFilterAttribute都可以实现用户授权的功能. AuthorizeAttribute和Action