.Net Core分布式邮件系统

left: 30px;”>本篇分享的是由NetCore搭建的分布式邮件系统,主要采用NetCore的Api控制台应用程序,由于此系统属于公司的所以这里只能分享设计图和一些单纯不设计业务的类或方法;

为什么要在公司中首例采用NetCore做开发

为什么要在公司中首例采用NetCore做开发,有些netcoreapi不是还不全面么,您都敢尝试?恐怕会有人这样问我,我只能告诉你NetCore现在出2.0版本了,很多Framwork的常用封装都已经有了,况且她主打的是MVC模式,能够高效的开发系统,也有很多Core的Nuget包支持了,已经到达了几乎可以放心大胆使用的地步,退一万不说有些东西不支持那这又如何,可以采用接口的方式从其他地方对接过来也是一种不错的处理方案。为了让C#这门优秀的语言被广泛应用,默默努力着。

目前我写的NetCore方面的文章

AspNetCore – MVC实战系列目录

.NetCore上传多文件的几种示例

开源一个跨平台运行的服务插件 – TaskCore.MainForm

NET Core-学习笔记

Asp.NetCore1.1版本没了project.json,这样来生成跨平台包

 

正片环节 – 分布式邮件系统设计图

.Net Core分布式邮件系统

分布式邮件系统说明

其实由上图可以知晓这里我主要采用了Api+服务的模式,这也是现在互联网公司经常采用的一种搭配默认;利用api接受请求插入待发送邮件队列和入库,然后通过部署多个NetCore跨平台服务(这里服务指的是:控制台应用)来做分布式处理操作,跨平台服务主要操作有:

. 邮件发送

. 邮件发送状态的通知(如果需要通知子业务,那么需要通知业务方邮件发送的状态)

. 通知失败处理(自动往绑定的责任人发送一封邮件)

. 填充队列(如果待发邮件队列或者通知队列数据不完整,需要修复队列数据)

Api接口的统一验证入口

这里我用最简单的方式,继承Controller封装了一个父级的BaseController,来让各个api的Controller基础统一来做身份验证;来看看重写 public override void OnActionExecuting(ActionExecutingContext context) 的验证代码:

 1 public override void OnActionExecuting(ActionExecutingContext context)  2         {  3             base.OnActionExecuting(context);  4   5             var moResponse = new MoBaseRp();  6             try  7             {  8   9                 #region 安全性验证 10  11                 var key = "request"; 12                 if (!context.ActionArguments.ContainsKey(key)) { moResponse.Msg = "请求方式不正确"; return; } 13                 var request = context.ActionArguments[key]; 14                 var baseRq = request as MoBaseRq; 15                 //暂时不验证登录账号密码 16                 if (string.IsNullOrWhiteSpace(baseRq.UserName) || string.IsNullOrWhiteSpace(baseRq.UserPwd)) { moResponse.Msg = "登录账号或密码不能为空"; return; } 17                 else if (baseRq.AccId  b.Id == baseRq.AccId); 28                     if (account == null) { moResponse.Msg = "发送者Id无效。"; return; } 29                     else 30                     { 31                         if (account.Status != (int)EnumHelper.EmStatus.启用) 32                         { 33                             moResponse.Msg = "发送者Id已禁用"; return; 34                         } 35  36                         //验证ip 37                         var ipArr = account.AllowIps.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 38                         //当前请求的Ip 39                         var nowIp = this.GetUserIp(); 40                         baseRq.Ip = nowIp; 41                         //默认*为所有ip , 匹配ip 42                         if (!ipArr.Any(b => b.Equals("*")) && !ipArr.Any(b => b.Equals(nowIp))) 43                         { 44                             moResponse.Msg = "请求IP为授权"; return; 45                         } 46                     } 47                 } 48                 else 49                 { 50                     var account = _db.EmailAccount.SingleOrDefault(b => b.Id == baseRq.AccId && b.AllowIps.Any(bb => bb.Equals(baseRq.Ip))); 51                     if (account == null) { moResponse.Msg = "发送者未授权"; return; } 52                     else if (account.Status != (int)EnumHelper.EmStatus.启用) 53                     { 54                         moResponse.Msg = "发送者Id已禁用"; return; 55                     } 56                 } 57  58                 //内容非空,格式验证 59                 if (!context.ModelState.IsValid) 60                 { 61                     var values = context.ModelState.Values.Where(b => b.Errors.Count > 0); 62                     if (values.Count() > 0) 63                     { 64                         moResponse.Msg = values.First().Errors.First().ErrorMessage; 65                         return; 66                     } 67                 } 68  69                 #endregion 70  71                 moResponse.Status = 1; 72             } 73             catch (Exception ex) 74             { 75                 moResponse.Msg = "O No请求信息错误"; 76             } 77             finally 78             { 79                 if (moResponse.Status == 0) { context.Result = Json(moResponse); } 80             } 81         }

登录后复制

邮件请求父类实体:

 1 ///   2     /// 邮件请求父类  3     ///   4     public class MoBaseRq  5     {  6   7         public string UserName { get; set; }  8   9         public string UserPwd { get; set; } 10  11         ///  12         /// 验证token(Md5(账号+配置发送者账号信息的Id+Ip))   必填 13         ///  14         public string Token { get; set; } 15  16         ///  17         /// 配置发送者账号信息的Id  必填 18         ///  19         public int AccId { get; set; } 20  21         ///  22         /// 业务方法名称 23         ///  24         public string FuncName { get; set; } 25  26         ///  27         /// 请求者Ip,如果客户端没赋值,默认服务端获取 28         ///  29         public string Ip { get; set; } 30  31     }

登录后复制

第三方Nuget包的便利

此邮件系统使用到了第三方包,这也能够看出有很多朋友正为开源,便利,NetCore的推广努力着;

首先看看MailKit(邮件发送)包,通过安装下载命令: Install-Package MailKit 能够下载最新包,然后你不需要做太花哨的分装,只需要正对于邮件发送的服务器,端口,账号,密码做一些设置基本就行了,如果可以您可以直接使用我的代码:

 1 ///   2         /// 发送邮件  3         ///   4         ///   5         ///   6         ///   7         ///   8         ///   9         ///  10         public static bool _SendEmail( 11             Dictionary dicToEmail, 12             string title, string content, 13             string name = "爱留图网", string fromEmail = "841202396@qq.com", 14             string host = "smtp.qq.com", int port = 587, 15             string userName = "841202396@qq.com", string userPwd = "123123") 16         { 17             var isOk = false; 18             try 19             { 20                 if (string.IsNullOrWhiteSpace(title) || string.IsNullOrWhiteSpace(content)) { return isOk; } 21  22                 //设置基本信息 23                 var message = new MimeMessage(); 24                 message.From.Add(new MailboxAddress(name, fromEmail)); 25                 foreach (var item in dicToEmail.Keys) 26                 { 27                     message.To.Add(new MailboxAddress(item, dicToEmail[item])); 28                 } 29                 message.Subject = title; 30                 message.Body = new TextPart("html") 31                 { 32                     Text = content 33                 }; 34  35                 //链接发送 36                 using (var client = new SmtpClient()) 37                 { 38                     // For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS) 39                     client.ServerCertificateValidationCallback = (s, c, h, e) => true; 40  41                     //采用qq邮箱服务器发送邮件 42                     client.Connect(host, port, false); 43  44                     // Note: since we don't have an OAuth2 token, disable 45                     // the XOAUTH2 authentication mechanism. 46                     client.AuthenticationMechanisms.Remove("XOAUTH2"); 47  48                     //qq邮箱,密码(安全设置短信获取后的密码)  ufiaszkkulbabejh 49                     client.Authenticate(userName, userPwd); 50  51                     client.Send(message); 52                     client.Disconnect(true); 53                 } 54                 isOk = true; 55             } 56             catch (Exception ex) 57             { 58  59             } 60             return isOk; 61         }

登录后复制

Redis方面的操作包StackExchange.Redis,现在NetCore支持很多数据库驱动(例如:Sqlserver,mysql,postgressql,db2等)这么用可以参考下这篇文章AspNetCore – MVC实战系列(一)之Sqlserver表映射实体模型,不仅如此还支持很多缓存服务(如:Memorycach,Redis),这里讲到的就是Redis,我利用Redis的list的队列特性来做分布式任务存储,尽管目前我用到的只有一个主Redis服务还没有业务场景需要用到主从复制等功能;这里分享的代码是基于StackExchange.Redis基础上封装对于string,list的操作:

  1   public class StackRedis : IDisposable    2     {    3         #region 配置属性   基于 StackExchange.Redis 封装    4         //连接串 (注:IP:端口,属性=,属性=)    5         public string _ConnectionString = "127.0.0.1:6377,password=shenniubuxing3";    6         //操作的库(注:默认0库)    7         public int _Db = 0;    8         #endregion    9    10         #region 管理器对象   11    12         ///    13         /// 获取redis操作类对象   14         ///    15         private static StackRedis _StackRedis;   16         private static object _locker_StackRedis = new object();   17         public static StackRedis Current   18         {   19             get   20             {   21                 if (_StackRedis == null)   22                 {   23                     lock (_locker_StackRedis)   24                     {   25                         _StackRedis = _StackRedis ?? new StackRedis();   26                         return _StackRedis;   27                     }   28                 }   29    30                 return _StackRedis;   31             }   32         }   33    34         ///    35         /// 获取并发链接管理器对象   36         ///    37         private static ConnectionMultiplexer _redis;   38         private static object _locker = new object();   39         public ConnectionMultiplexer Manager   40         {   41             get   42             {   43                 if (_redis == null)   44                 {   45                     lock (_locker)   46                     {   47                         _redis = _redis ?? GetManager(this._ConnectionString);   48                         return _redis;   49                     }   50                 }   51    52                 return _redis;   53             }   54         }   55    56         ///    57         /// 获取链接管理器 58         ///    59         ///    60         ///    61         public ConnectionMultiplexer GetManager(string connectionString)   62         {   63             return ConnectionMultiplexer.Connect(connectionString);   64         }   65    66         ///    67         /// 获取操作数据库对象   68         ///    69         ///    70         public IDatabase GetDb()   71         {   72             return Manager.GetDatabase(_Db);   73         }   74         #endregion   75    76         #region 操作方法   77    78         #region string 操作   79    80         ///    81         /// 根据Key移除   82         ///    83         ///    84         ///    85         public async Task Remove(string key)   86         {   87             var db = this.GetDb();   88    89             return await db.KeyDeleteAsync(key);   90         }   91    92         ///    93         /// 根据key获取string结果   94         ///    95         ///    96         ///    97         public async Task Get(string key)   98         {   99             var db = this.GetDb();  100             return await db.StringGetAsync(key);  101         }  102   103         ///   104         /// 根据key获取string中的对象  105         ///   106         ///   107         ///   108         ///   109         public async Task Get(string key)  110         {  111             var t = default(T);  112             try  113             {  114                 var _str = await this.Get(key);  115                 if (string.IsNullOrWhiteSpace(_str)) { return t; }  116   117                 t = JsonConvert.DeserializeObject(_str);  118             }  119             catch (Exception ex) { }  120             return t;  121         }  122   123         ///   124         /// 存储string数据  125         ///   126         ///   127         ///   128         ///   129         ///   130         public async Task Set(string key, string value, int expireMinutes = 0)  131         {  132             var db = this.GetDb();  133             if (expireMinutes > 0)  134             {  135                 return db.StringSet(key, value, TimeSpan.FromMinutes(expireMinutes));  136             }  137             return await db.StringSetAsync(key, value);  138         }  139   140         ///   141         /// 存储对象数据到string  142         ///   143         ///   144         ///   145         ///   146         ///   147         ///   148         public async Task Set(string key, T value, int expireMinutes = 0)  149         {  150             try  151             {  152                 var jsonOption = new JsonSerializerSettings()  153                 {  154                     ReferenceLoopHandling = ReferenceLoopHandling.Ignore  155                 };  156                 var _str = JsonConvert.SerializeObject(value, jsonOption);  157                 if (string.IsNullOrWhiteSpace(_str)) { return false; }  158   159                 return await this.Set(key, _str, expireMinutes);  160             }  161             catch (Exception ex) { }  162             return false;  163         }  164         #endregion  165   166         #region List操作(注:可以当做队列使用)  167   168         ///   169         /// list长度  170         ///   171         ///   172         ///   173         ///   174         public async Task GetListLen(string key)  175         {  176             try  177             {  178                 var db = this.GetDb();  179                 return await db.ListLengthAsync(key);  180             }  181             catch (Exception ex) { }  182             return 0;  183         }  184   185         ///   186         /// 获取队列出口数据并移除  187         ///   188         ///   189         ///   190         ///   191         public async Task GetListAndPop(string key)  192         {  193             var t = default(T);  194             try  195             {  196                 var db = this.GetDb();  197                 var _str = await db.ListRightPopAsync(key);  198                 if (string.IsNullOrWhiteSpace(_str)) { return t; }  199                 t = JsonConvert.DeserializeObject(_str);  200             }  201             catch (Exception ex) { }  202             return t;  203         }  204   205         ///   206         /// 集合对象添加到list左边  207         ///   208         ///   209         ///   210         ///   211         ///   212         public async Task SetLists(string key, List values)  213         {  214             var result = 0L;  215             try  216             {  217                 var jsonOption = new JsonSerializerSettings()  218                 {  219                     ReferenceLoopHandling = ReferenceLoopHandling.Ignore  220                 };  221                 var db = this.GetDb();  222                 foreach (var item in values)  223                 {  224                     var _str = JsonConvert.SerializeObject(item, jsonOption);  225                     result += await db.ListLeftPushAsync(key, _str);  226                 }  227                 return result;  228             }  229             catch (Exception ex) { }  230             return result;  231         }  232   233         ///   234         /// 单个对象添加到list左边  235         ///   236         ///   237         ///   238         ///   239         ///   240         public async Task SetList(string key, T value)  241         {  242             var result = 0L;  243             try  244             {  245                 result = await this.SetLists(key, new List { value });  246             }  247             catch (Exception ex) { }  248             return result;  249         }  250   251   252         #endregion  253   254         #region 额外扩展  255   256         ///   257         /// 手动回收管理器对象  258         ///   259         public void Dispose()  260         {  261             this.Dispose(_redis);  262         }  263   264         public void Dispose(ConnectionMultiplexer con)  265         {  266             if (con != null)  267             {  268                 con.Close();  269                 con.Dispose();  270             }  271         }  272   273         #endregion  274   275         #endregion  276     }

登录后复制

用到Redis的那些操作就添加哪些就行了,也不用太花哨能用就行;

如何生成跨平台的api服务和应用程序服务

这小节的内容最重要,由于之前有相关的文章,这里就不用再赘述了,来这里看看:Asp.NetCore1.1版本没了project.json,这样来生成跨平台包

以上就是.Net Core分布式邮件系统的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2494418.html

(0)
上一篇 2025年3月5日 01:51:59
下一篇 2025年2月24日 22:57:26

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • C#开发中如何处理分布式事务和消息传递问题及解决方法

    C#开发中如何处理分布式事务和消息传递问题及解决方法 在分布式系统中,分布式事务和消息传递是常见的问题。分布式事务指的是涉及多个数据库或服务的事务,而消息传递则指的是系统中不同组件之间的异步通信。本文将介绍在C#开发中如何处理这些问题,并提…

    2025年3月5日
    200
  • 使用Redis实现分布式排行榜

    随着互联网的发展,越来越多的在线游戏、社交平台、电子商务等应用需要实时展示排行榜,这就要求我们需要一个高性能、可扩展的方案来实现分布式排行榜。本文将介绍如何使用redis实现分布式排行榜。 Redis是一个开源的内存数据存储系统,而且支持多…

    数据库 2025年3月4日
    200
  • 使用Redis实现分布式计数器

    什么是分布式计数器? 在分布式系统中,多个节点之间需要对共同的状态进行更新和读取,而计数器是其中一种应用最广泛的状态之一。通俗地讲,计数器就是一个变量,每次被访问时其值就会加1或减1,用于跟踪某个系统进展的指标。而分布式计数器则指的是在分布…

    数据库 2025年3月4日
    200
  • Redis实现分布式任务队列的方法

    随着互联网的发展,分布式系统逐渐成为了互联网应用开发的趋势之一。在分布式系统中,任务队列是一个非常重要的组件,它能够帮助开发者合理地分配任务,提高系统的效率。redis作为一种高性能的缓存数据库,也因为具有良好的分布式特性而被广泛应用于任务…

    数据库 2025年3月4日
    200
  • Redis实现分布式语音识别的方法与应用实例

    redis实现分布式语音识别的方法与应用实例 随着人工智能技术的不断发展以及语音技术的日益完善,分布式语音识别成为了一个备受关注的领域。分布式语音识别可以使得语音识别系统的性能获得更好的扩展性和容错性,并且可以使得整个语音识别过程更加高效。…

    数据库 2025年3月4日
    200
  • Go语言中的分布式与云计算结合

    随着云计算的迅速发展,分布式计算也成为了越来越重要的技术。而在这个背景下,go语言的分布式计算能力也受到了越来越多的关注。go语言的轻量级、高并发、良好的内存管理等特点,使得其在分布式计算领域中有着较为显著的优势。本文将分析go语言在分布式…

    编程技术 2025年3月2日
    200
  • 如何使用Go语言框架构建分布式数据库

    随着互联网的不断发展,数据量的增长速度越来越快,对于单机数据库来说,存储和处理海量数据的压力是非常大的,因此,分布式数据库成为了一个越来越流行的选择。go语言是一种高效、简洁、易于学习的语言,其强大的并发处理能力(内置goroutine和c…

    编程技术 2025年3月2日
    200
  • Go 语言中的分布式事务处理怎样实现?

    随着互联网应用规模不断扩大和垂直服务的逐渐拆分,分布式系统的发展变得越来越重要。随之而来的问题是,如何在这样的系统中处理事务一致性的问题。这篇文章将介绍 go 语言中的一些主流分布式事务处理方案,以及它们的实现原理。 传统 ACID 事务 …

    编程技术 2025年3月2日
    200
  • 使用Go语言编写高效的分布式日志管理系统

    随着互联网应用的不断扩张,系统日志管理变得越来越重要。而传统的日志管理方式已经无法满足大规模分布式系统日志管理的需求。因此,分布式日志管理系统逐渐成为了企业的必备工具。而go语言则成为了分布式日志管理系统的优秀选择,因为go语言拥有高效的并…

    编程技术 2025年3月2日
    200
  • 实用技巧:使用Go语言实现分布式缓存系统

    随着互联网应用的日益广泛和业务的复杂度不断提高,分布式系统逐渐成为了现代应用程序设计的必经之路。而作为一门新兴的编程语言,go语言在分布式系统中也有着广泛的应用。今天,我们将介绍如何使用go语言实现一个简单但实用的分布式缓存系统。 一、什么…

    编程技术 2025年3月2日
    200

发表回复

登录后才能评论