搜狗提交网站收录入口,重庆商城网站制作报价,网站建设维护升级,陕西省建设网站 五大员过期本篇分享的是由NetCore搭建的分布式邮件系统#xff0c;主要采用NetCore的Api和控制台应用程序#xff0c;由于此系统属于公司的所以这里只能分享设计图和一些单纯不设计业务的类或方法#xff1b; 为什么要在公司中首例采用NetCore做开发
为什么要在公司中首例采用NetCore…本篇分享的是由NetCore搭建的分布式邮件系统主要采用NetCore的Api和控制台应用程序由于此系统属于公司的所以这里只能分享设计图和一些单纯不设计业务的类或方法 为什么要在公司中首例采用NetCore做开发
为什么要在公司中首例采用NetCore做开发有些netcoreapi不是还不全面么您都敢尝试恐怕会有人这样问我我只能告诉你NetCore现在出2.0版本了很多Framwork的常用封装都已经有了况且她主打的是MVC模式能够高效的开发系统也有很多Core的Nuget包支持了已经到达了几乎可以放心大胆使用的地步退一万不说有些东西不支持那这又如何可以采用接口的方式从其他地方对接过来也是一种不错的处理方案。为了让C#这门优秀的语言被广泛应用默默努力着。 正片环节 - 分布式邮件系统设计图 分布式邮件系统说明
其实由上图可以知晓这里我主要采用了Api服务的模式这也是现在互联网公司经常采用的一种搭配默认利用api接受请求插入待发送邮件队列和入库然后通过部署多个NetCore跨平台服务(这里服务指的是控制台应用)来做分布式处理操作跨平台服务主要操作有
. 邮件发送
. 邮件发送状态的通知如果需要通知子业务那么需要通知业务方邮件发送的状态
. 通知失败处理(自动往绑定的责任人发送一封邮件)
. 填充队列(如果待发邮件队列或者通知队列数据不完整需要修复队列数据)
Api接口的统一验证入口
这里我用最简单的方式继承Controller封装了一个父级的BaseController来让各个api的Controller基础统一来做身份验证;来看看重写 public override void OnActionExecuting(ActionExecutingContext context) 的验证代码
public override void OnActionExecuting(ActionExecutingContext context) { base.OnActionExecuting(context); var moResponse new MoBaseRp(); try { #region 安全性验证 var key request; if (!context.ActionArguments.ContainsKey(key)) { moResponse.Msg 请求方式不正确; return; } var request context.ActionArguments[key]; var baseRq request as MoBaseRq; //暂时不验证登录账号密码 if (string.IsNullOrWhiteSpace(baseRq.UserName) || string.IsNullOrWhiteSpace(baseRq.UserPwd)) { moResponse.Msg 登录账号或密码不能为空; return; } else if (baseRq.AccId 0) { moResponse.Msg 发送者Id无效; return; } else if (string.IsNullOrWhiteSpace(baseRq.FuncName)) { moResponse.Msg 业务方法名不正确; return; } //token验证 var strToken PublicClass._Md5(${baseRq.UserName}{baseRq.AccId}, ); if (!strToken.Equals(baseRq.Token, StringComparison.OrdinalIgnoreCase)) { moResponse.Msg Token验证失败; return; } //验证发送者Id if (string.IsNullOrWhiteSpace(baseRq.Ip)) { var account _db.EmailAccount.SingleOrDefault(b b.Id baseRq.AccId); if (account null) { moResponse.Msg 发送者Id无效。; return; } else { if (account.Status ! (int)EnumHelper.EmStatus.启用) { moResponse.Msg 发送者Id已禁用; return; } //验证ip var ipArr account.AllowIps.Split(new char[] { , }, StringSplitOptions.RemoveEmptyEntries); //当前请求的Ip var nowIp this.GetUserIp(); baseRq.Ip nowIp; //默认*为所有ip , 匹配ip if (!ipArr.Any(b b.Equals(*)) !ipArr.Any(b b.Equals(nowIp))) { moResponse.Msg 请求IP为授权; return; } } } else { var account _db.EmailAccount.SingleOrDefault(b b.Id baseRq.AccId b.AllowIps.Any(bb bb.Equals(baseRq.Ip))); if (account null) { moResponse.Msg 发送者未授权; return; } else if (account.Status ! (int)EnumHelper.EmStatus.启用) { moResponse.Msg 发送者Id已禁用; return; } } //内容非空格式验证 if (!context.ModelState.IsValid) { var values context.ModelState.Values.Where(b b.Errors.Count 0); if (values.Count() 0) { moResponse.Msg values.First().Errors.First().ErrorMessage; return; } } #endregion moResponse.Status 1; } catch (Exception ex) { moResponse.Msg O No请求信息错误; } finally { if (moResponse.Status 0) { context.Result Json(moResponse); } } }
邮件请求父类实体
/// summary /// 邮件请求父类 /// /summary public class MoBaseRq { public string UserName { get; set; } public string UserPwd { get; set; } /// summary /// 验证tokenMd5(账号配置发送者账号信息的IdIp) 必填 /// /summary public string Token { get; set; } /// summary /// 配置发送者账号信息的Id 必填 /// /summary public int AccId { get; set; } /// summary /// 业务方法名称 /// /summary public string FuncName { get; set; } /// summary /// 请求者Ip如果客户端没赋值默认服务端获取 /// /summary public string Ip { get; set; } }
第三方Nuget包的便利 此邮件系统使用到了第三方包这也能够看出有很多朋友正为开源便利NetCore的推广努力着
首先看看MailKit(邮件发送)包通过安装下载命令 Install-Package MailKit 能够下载最新包然后你不需要做太花哨的分装只需要正对于邮件发送的服务器端口账号密码做一些设置基本就行了如果可以您可以直接使用我的代码
/// summary /// 发送邮件 /// /summary /// param namedicToEmail/param /// param nametitle/param /// param namecontent/param /// param namename/param /// param namefromEmail/param /// returns/returns public static bool _SendEmail( Dictionarystring, string dicToEmail, string title, string content, string name 爱留图网, string fromEmail 841202396qq.com, string host smtp.qq.com, int port 587, string userName 841202396qq.com, string userPwd 123123) { var isOk false; try { if (string.IsNullOrWhiteSpace(title) || string.IsNullOrWhiteSpace(content)) { return isOk; } //设置基本信息 var message new MimeMessage(); message.From.Add(new MailboxAddress(name, fromEmail)); foreach (var item in dicToEmail.Keys) { message.To.Add(new MailboxAddress(item, dicToEmail[item])); } message.Subject title; message.Body new TextPart(html) { Text content }; //链接发送 using (var client new SmtpClient()) { // For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS) client.ServerCertificateValidationCallback (s, c, h, e) true; //采用qq邮箱服务器发送邮件 client.Connect(host, port, false); // Note: since we dont have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove(XOAUTH2); //qq邮箱密码(安全设置短信获取后的密码) ufiaszkkulbabejh client.Authenticate(userName, userPwd); client.Send(message); client.Disconnect(true); } isOk true; } catch (Exception ex) { } return isOk; }
Redis方面的操作包StackExchange.Redis现在NetCore支持很多数据库驱动例如Sqlservermysqlpostgressqldb2等这么用可以参考下这篇文章AspNetCore - MVC实战系列一之Sqlserver表映射实体模型不仅如此还支持很多缓存服务如MemorycachRedis这里讲到的就是Redis我利用Redis的list的队列特性来做分布式任务存储尽管目前我用到的只有一个主Redis服务还没有业务场景需要用到主从复制等功能这里分享的代码是基于StackExchange.Redis基础上封装对于stringlist的操作
public class StackRedis : IDisposable { #region 配置属性 基于 StackExchange.Redis 封装 //连接串 注IP:端口,属性,属性) public string _ConnectionString 127.0.0.1:6377,passwordshenniubuxing3; //操作的库注默认0库 public int _Db 0; #endregion #region 管理器对象 /// summary /// 获取redis操作类对象 /// /summary private static StackRedis _StackRedis; private static object _locker_StackRedis new object(); public static StackRedis Current { get { if (_StackRedis null) { lock (_locker_StackRedis) { _StackRedis _StackRedis ?? new StackRedis(); return _StackRedis; } } return _StackRedis; } } /// summary /// 获取并发链接管理器对象 /// /summary private static ConnectionMultiplexer _redis; private static object _locker new object(); public ConnectionMultiplexer Manager { get { if (_redis null) { lock (_locker) { _redis _redis ?? GetManager(this._ConnectionString); return _redis; } } return _redis; } } /// summary /// 获取链接管理器 /// /summary /// param nameconnectionString/param /// returns/returns public ConnectionMultiplexer GetManager(string connectionString) { return ConnectionMultiplexer.Connect(connectionString); } /// summary /// 获取操作数据库对象 /// /summary /// returns/returns public IDatabase GetDb() { return Manager.GetDatabase(_Db); } #endregion #region 操作方法 #region string 操作 /// summary /// 根据Key移除 /// /summary /// param namekey/param /// returns/returns public async Taskbool Remove(string key) { var db this.GetDb(); return await db.KeyDeleteAsync(key); } /// summary /// 根据key获取string结果 /// /summary /// param namekey/param /// returns/returns public async Taskstring Get(string key) { var db this.GetDb(); return await db.StringGetAsync(key); } /// summary /// 根据key获取string中的对象 /// /summary /// typeparam nameT/typeparam /// param namekey/param /// returns/returns public async TaskT GetT(string key) { var t default(T); try { var _str await this.Get(key); if (string.IsNullOrWhiteSpace(_str)) { return t; } t JsonConvert.DeserializeObjectT(_str); } catch (Exception ex) { } return t; } /// summary /// 存储string数据 /// /summary /// param namekey/param /// param namevalue/param /// param nameexpireMinutes/param /// returns/returns public async Taskbool Set(string key, string value, int expireMinutes 0) { var db this.GetDb(); if (expireMinutes 0) { return db.StringSet(key, value, TimeSpan.FromMinutes(expireMinutes)); } return await db.StringSetAsync(key, value); } /// summary /// 存储对象数据到string /// /summary /// typeparam nameT/typeparam /// param namekey/param /// param namevalue/param /// param nameexpireMinutes/param /// returns/returns public async Taskbool SetT(string key, T value, int expireMinutes 0) { try { var jsonOption new JsonSerializerSettings() { ReferenceLoopHandling ReferenceLoopHandling.Ignore }; var _str JsonConvert.SerializeObject(value, jsonOption); if (string.IsNullOrWhiteSpace(_str)) { return false; } return await this.Set(key, _str, expireMinutes); } catch (Exception ex) { } return false; } #endregion #region List操作注可以当做队列使用 /// summary /// list长度 /// /summary /// typeparam nameT/typeparam /// param namekey/param /// returns/returns public async Tasklong GetListLenT(string key) { try { var db this.GetDb(); return await db.ListLengthAsync(key); } catch (Exception ex) { } return 0; } /// summary /// 获取队列出口数据并移除 /// /summary /// typeparam nameT/typeparam /// param namekey/param /// returns/returns public async TaskT GetListAndPopT(string key) { var t default(T); try { var db this.GetDb(); var _str await db.ListRightPopAsync(key); if (string.IsNullOrWhiteSpace(_str)) { return t; } t JsonConvert.DeserializeObjectT(_str); } catch (Exception ex) { } return t; } /// summary /// 集合对象添加到list左边 /// /summary /// typeparam nameT/typeparam /// param namekey/param /// param namevalues/param /// returns/returns public async Tasklong SetListsT(string key, ListT values) { var result 0L; try { var jsonOption new JsonSerializerSettings() { ReferenceLoopHandling ReferenceLoopHandling.Ignore }; var db this.GetDb(); foreach (var item in values) { var _str JsonConvert.SerializeObject(item, jsonOption); result await db.ListLeftPushAsync(key, _str); } return result; } catch (Exception ex) { } return result; } /// summary /// 单个对象添加到list左边 /// /summary /// typeparam nameT/typeparam /// param namekey/param /// param namevalue/param /// returns/returns public async Tasklong SetListT(string key, T value) { var result 0L; try { result await this.SetLists(key, new ListT { value }); } catch (Exception ex) { } return result; } #endregion #region 额外扩展 /// summary /// 手动回收管理器对象 /// /summary public void Dispose() { this.Dispose(_redis); } public void Dispose(ConnectionMultiplexer con) { if (con ! null) { con.Close(); con.Dispose(); } } #endregion #endregion }
用到Redis的那些操作就添加哪些就行了也不用太花哨能用就行
如何生成跨平台的api服务和应用程序服务
这小节的内容最重要由于之前有相关的文章这里就不用再赘述了来这里看看Asp.NetCore1.1版本没了project.json这样来生成跨平台包
原文地址http://www.cnblogs.com/wangrudong003/p/6898386.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注