search
HomeBackend DevelopmentC#.Net Tutorial.Net Core distributed mail system

.Net Core distributed mail system

May 30, 2018 pm 03:24 PM
distributed

This article shares a distributed mail system built by NetCore, which mainly uses NetCore's Api and Console application. Since this system belongs The company is here so I can only share the design drawings and some classes or methods that are not designed for business;

Why is it the first time in the company to use NetCore for development

Why is it the first time in the company Using NetCore for development, aren’t some netcore APIs not comprehensive enough? Do you dare to try them? I'm afraid someone will ask me this. I can only tell you that NetCore has now released version 2.0. Many common packages of Framwork are already available. Moreover, its main focus is the MVC mode, which can efficiently develop systems and also has Many Core Nuget packages are supported, and it has reached the point where you can almost use it with confidence. So what if some things are not supported? You can use Interface to connect it from other places. A nice solution. In order to make this excellent language C# widely used, we are working hard silently.

The articles I am currently writing about NetCore

AspNetCore - MVC Practical Series Directory

.NetCoreUpload Several examples of multiple files

Open source a cross-platform service plug-in - TaskCore.MainForm

NET Core-Study Notes

##Asp.NetCore1.1 version no longer has the project .json, in this way to generate a cross-platform package

Feature link - Distributed email system design diagram

Distributed Mail System Description

In fact, as you can see from the above picture, I mainly use the Api+ service model, which is also a default combination often used by Internet companies now; Use the api to accept requests to insert

to-be-sent emailsqueueand storage, and then deploy multiple NetCore cross-platform services (services here refer to: console applications)To do distributed processing operations, Cross-platform serviceThe main operations are:

. Email sending

. Notification of email sending status (if the sub-business needs to be notified, then the business party needs to be notified of the status of email sending)

. Notification failure processing (automatically bound Send an email to the designated responsible person)

. Fill the queue (if the data in the outgoing email queue or notification queue is incomplete, the queue data needs to be repaired)

Uniform verification entrance of Api interface

Here I use the simplest way,

InheritanceController encapsulates a parent BaseController to allow the Controller of each API to perform authentication in a unified manner; Let’s take a look at the verification code of overriding 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 <= 0) { moResponse.Msg = "发送者Id无效"; return; }
 18                 else if (string.IsNullOrWhiteSpace(baseRq.FuncName)) { moResponse.Msg = "业务方法名不正确"; return; }
 19 
 20                 //token验证
 21                 var strToken = PublicClass._Md5($"{baseRq.UserName}{baseRq.AccId}", "");
 22                 if (!strToken.Equals(baseRq.Token, StringComparison.OrdinalIgnoreCase)) { moResponse.Msg = "Token验证失败"; return; }
 23 
 24                 //验证发送者Id
 25                 if (string.IsNullOrWhiteSpace(baseRq.Ip))
 26                 {
 27                     var account = _db.EmailAccount.SingleOrDefault(b => 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[] { &#39;,&#39; }, 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         }

Mail request parent entity:

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

第三方Nuget包的便利

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

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

 1 /// <summary> 
 2         /// 发送邮件 
 3         /// </summary> 
 4         /// <param> 
 5         /// <param> 
 6         /// <param> 
 7         /// <param> 
 8         /// <param> 
 9         /// <returns></returns>
 10         public static bool _SendEmail(
 11             Dictionary<string> 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         }</string>

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         /// <summary> 
  13         /// 获取redis操作类对象 
  14         /// </summary> 
  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         /// <summary> 
  35         /// 获取并发链接管理器对象 
  36         /// </summary> 
  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         /// <summary> 
  57         /// 获取链接管理器 58         /// </summary> 
  59         /// <param> 
  60         /// <returns></returns> 
  61         public ConnectionMultiplexer GetManager(string connectionString) 
  62         { 
  63             return ConnectionMultiplexer.Connect(connectionString); 
  64         } 
  65  
  66         /// <summary> 
  67         /// 获取操作数据库对象 
  68         /// </summary> 
  69         /// <returns></returns> 
  70         public IDatabase GetDb() 
  71         { 
  72             return Manager.GetDatabase(_Db); 
  73         } 
  74         #endregion 
  75  
  76         #region 操作方法 
  77  
  78         #region string 操作 
  79  
  80         /// <summary> 
  81         /// 根据Key移除 
  82         /// </summary> 
  83         /// <param> 
  84         /// <returns></returns> 
  85         public async Task<bool> Remove(string key) 
  86         { 
  87             var db = this.GetDb(); 
  88  
  89             return await db.KeyDeleteAsync(key); 
  90         } 
  91  
  92         /// <summary> 
  93         /// 根据key获取string结果 
  94         /// </summary> 
  95         /// <param> 
  96         /// <returns></returns> 
  97         public async Task<string> Get(string key) 
  98         { 
  99             var db = this.GetDb();
  100             return await db.StringGetAsync(key);
  101         }
  102 
  103         /// <summary>
  104         /// 根据key获取string中的对象
  105         /// </summary>
  106         /// <typeparam></typeparam>
  107         /// <param>
  108         /// <returns></returns>
  109         public async Task<t> Get<t>(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<t>(_str);
  118             }
  119             catch (Exception ex) { }
  120             return t;
  121         }
  122 
  123         /// <summary>
  124         /// 存储string数据
  125         /// </summary>
  126         /// <param>
  127         /// <param>
  128         /// <param>
  129         /// <returns></returns>
  130         public async Task<bool> 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         /// <summary>
  141         /// 存储对象数据到string
  142         /// </summary>
  143         /// <typeparam></typeparam>
  144         /// <param>
  145         /// <param>
  146         /// <param>
  147         /// <returns></returns>
  148         public async Task<bool> Set<t>(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         /// <summary>
  169         /// list长度
  170         /// </summary>
  171         /// <typeparam></typeparam>
  172         /// <param>
  173         /// <returns></returns>
  174         public async Task<long> GetListLen<t>(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         /// <summary>
  186         /// 获取队列出口数据并移除
  187         /// </summary>
  188         /// <typeparam></typeparam>
  189         /// <param>
  190         /// <returns></returns>
  191         public async Task<t> GetListAndPop<t>(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<t>(_str);
  200             }
  201             catch (Exception ex) { }
  202             return t;
  203         }
  204 
  205         /// <summary>
  206         /// 集合对象添加到list左边
  207         /// </summary>
  208         /// <typeparam></typeparam>
  209         /// <param>
  210         /// <param>
  211         /// <returns></returns>
  212         public async Task<long> SetLists<t>(string key, List<t> 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         /// <summary>
  234         /// 单个对象添加到list左边
  235         /// </summary>
  236         /// <typeparam></typeparam>
  237         /// <param>
  238         /// <param>
  239         /// <returns></returns>
  240         public async Task<long> SetList<t>(string key, T value)
  241         {
  242             var result = 0L;
  243             try
  244             {
  245                 result = await this.SetLists(key, new List<t> { value });
  246             }
  247             catch (Exception ex) { }
  248             return result;
  249         }
  250 
  251 
  252         #endregion
  253 
  254         #region 额外扩展
  255 
  256         /// <summary>
  257         /// 手动回收管理器对象
  258         /// </summary>
  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     }</t></t></long></t></t></long></t></t></t></t></long></t></bool></bool></t></t></t></string></bool>

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

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

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

The above is the detailed content of .Net Core distributed mail system. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
The Community of C# .NET Developers: Resources and SupportThe Community of C# .NET Developers: Resources and SupportMay 06, 2025 am 12:11 AM

The C#.NET developer community provides rich resources and support, including: 1. Microsoft's official documents, 2. Community forums such as StackOverflow and Reddit, and 3. Open source projects on GitHub. These resources help developers improve their programming skills from basic learning to advanced applications.

The C# .NET Advantage: Features, Benefits, and Use CasesThe C# .NET Advantage: Features, Benefits, and Use CasesMay 05, 2025 am 12:01 AM

The advantages of C#.NET include: 1) Language features, such as asynchronous programming simplifies development; 2) Performance and reliability, improving efficiency through JIT compilation and garbage collection mechanisms; 3) Cross-platform support, .NETCore expands application scenarios; 4) A wide range of practical applications, with outstanding performance from the Web to desktop and game development.

Is C# Always Associated with .NET? Exploring AlternativesIs C# Always Associated with .NET? Exploring AlternativesMay 04, 2025 am 12:06 AM

C# is not always tied to .NET. 1) C# can run in the Mono runtime environment and is suitable for Linux and macOS. 2) In the Unity game engine, C# is used for scripting and does not rely on the .NET framework. 3) C# can also be used for embedded system development, such as .NETMicroFramework.

The .NET Ecosystem: C#'s Role and BeyondThe .NET Ecosystem: C#'s Role and BeyondMay 03, 2025 am 12:04 AM

C# plays a core role in the .NET ecosystem and is the preferred language for developers. 1) C# provides efficient and easy-to-use programming methods, combining the advantages of C, C and Java. 2) Execute through .NET runtime (CLR) to ensure efficient cross-platform operation. 3) C# supports basic to advanced usage, such as LINQ and asynchronous programming. 4) Optimization and best practices include using StringBuilder and asynchronous programming to improve performance and maintainability.

C# as a .NET Language: The Foundation of the EcosystemC# as a .NET Language: The Foundation of the EcosystemMay 02, 2025 am 12:01 AM

C# is a programming language released by Microsoft in 2000, aiming to combine the power of C and the simplicity of Java. 1.C# is a type-safe, object-oriented programming language that supports encapsulation, inheritance and polymorphism. 2. The compilation process of C# converts the code into an intermediate language (IL), and then compiles it into machine code execution in the .NET runtime environment (CLR). 3. The basic usage of C# includes variable declarations, control flows and function definitions, while advanced usages cover asynchronous programming, LINQ and delegates, etc. 4. Common errors include type mismatch and null reference exceptions, which can be debugged through debugger, exception handling and logging. 5. Performance optimization suggestions include the use of LINQ, asynchronous programming, and improving code readability.

C# vs. .NET: Clarifying the Key Differences and SimilaritiesC# vs. .NET: Clarifying the Key Differences and SimilaritiesMay 01, 2025 am 12:12 AM

C# is a programming language, while .NET is a software framework. 1.C# is developed by Microsoft and is suitable for multi-platform development. 2..NET provides class libraries and runtime environments, and supports multilingual. The two work together to build modern applications.

Beyond the Hype: Assessing the Current Role of C# .NETBeyond the Hype: Assessing the Current Role of C# .NETApr 30, 2025 am 12:06 AM

C#.NET is a powerful development platform that combines the advantages of the C# language and .NET framework. 1) It is widely used in enterprise applications, web development, game development and mobile application development. 2) C# code is compiled into an intermediate language and is executed by the .NET runtime environment, supporting garbage collection, type safety and LINQ queries. 3) Examples of usage include basic console output and advanced LINQ queries. 4) Common errors such as empty references and type conversion errors can be solved through debuggers and logging. 5) Performance optimization suggestions include asynchronous programming and optimization of LINQ queries. 6) Despite the competition, C#.NET maintains its important position through continuous innovation.

The Future of C# .NET: Trends and OpportunitiesThe Future of C# .NET: Trends and OpportunitiesApr 29, 2025 am 12:02 AM

The future trends of C#.NET are mainly focused on three aspects: cloud computing, microservices, AI and machine learning integration, and cross-platform development. 1) Cloud computing and microservices: C#.NET optimizes cloud environment performance through the Azure platform and supports the construction of an efficient microservice architecture. 2) Integration of AI and machine learning: With the help of the ML.NET library, C# developers can embed machine learning models in their applications to promote the development of intelligent applications. 3) Cross-platform development: Through .NETCore and .NET5, C# applications can run on Windows, Linux and macOS, expanding the deployment scope.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function