第五节:集成全局返回值处理、详解Ypf.Utils帮助类层、核心功能测试
一. 集成全局返回值处理
参考:
https://www.cnblogs.com/yaopengfei/p/12362554.html
1. 背景
在Core Mvc 3.x版本中,通过return Json的模式返回给前端, DateTime类型不友好(当然可以在后台强转,或者在前端转换),而且会将参数默认成首字母小写, 不是我们想要的,我们需要的是DateTime指定格式,参数名传什么显示什么。
2. 解决方案
我们这里采用基于Core自带的【System.Text.Json】程序集实现,需要额外引入其他程序集。
(1). 在YpfCore.AdminWeb层中Models文件夹下,新增DatetimeJsonConverter类,用于处理需要转换的时间类型。
代码如下:
/// <summary> /// 全局日期格式转换类 /// 基于【System.Text.Json】程序集 /// </summary> public class DatetimeJsonConverter : JsonConverter<DateTime> { public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { if (DateTime.TryParse(reader.GetString(), out DateTime date)) return date; } return reader.GetDateTime(); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); } }
(2). 在ConfigureService中进行注册。
代码分享:
services.AddControllersWithViews() //全局返回格式处理 .AddJsonOptions(options => { //格式化日期时间格式 options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter()); //参数格式首字母小写(=null 则表示参数原样输出) //options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; options.JsonSerializerOptions.PropertyNamingPolicy = null; //取消Unicode编码 options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); //忽略空值 options.JsonSerializerOptions.IgnoreNullValues = true; //允许额外符号 options.JsonSerializerOptions.AllowTrailingCommas = true; //反序列化过程中属性名称是否使用不区分大小写的比较 options.JsonSerializerOptions.PropertyNameCaseInsensitive = false; });
二. 详解Ypf.Utils帮助类层
截图如下:
1. Attributes
a.SkipAllAttribute:跨过系统所有校验。
b.SkipLoginAttribute:跨过登录验证。
c.SkipJwtAttribute:跨过JWT验证的特性。
代码分享:
/// <summary> /// 跨过系统所有校验 /// </summary> public class SkipAllAttribute : Attribute { } /// <summary> /// 跨过JWT校验 /// </summary> public class SkipJwtAttribute : Attribute { } /// <summary> /// 跨过登录校验 /// </summary> public class SkipLoginAttribute : Attribute { }
2. Common
a. ConfigHelp: 读取配置文件类,不依赖Core MVC的注入,支持.json和xml文件的读取。
b. MailHelp: 邮件发送帮助类。
c. RequestHelp: Get和Post请求,Post请求支持表单和JOSN两种格式,不依赖Core MVC注入。
d. SftpHelp: SFTP请求相关的类
代码分享:
configHelp
/// <summary> /// 读取配置文件 /// 依赖程序集:【 Microsoft.Extensions.Configuration】、【Microsoft.Extensions.Configuration.FileExtensions】 /// 【Microsoft.Extensions.Configuration.Json】、【 Microsoft.Extensions.Configuration.xml】 /// </summary> public static class ConfigHelp { /// <summary> /// 读取Json类型的配置文件 /// </summary> /// <param name="key">键名</param> /// <param name="FilePath">文件路径,默认为:appsettings.json</param> /// <returns></returns> public static string GetString(string key, string FilePath = "appsettings.json") { var configurationBuilder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile(FilePath, optional: true, reloadOnChange: true); var configuration = configurationBuilder.Build(); return configuration[key]; } /// <summary> /// 读取Xml类型的配置文件 /// </summary> /// <param name="key">键名</param> /// <param name="FilePath">文件路径,默认为:myXml.json</param> /// <returns></returns> public static string GetXmlString(string key, string FilePath = "myXml.json") { var configurationBuilder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddXmlFile(FilePath, optional: true, reloadOnChange: true); var configuration = configurationBuilder.Build(); return configuration[key]; } }
MailHelp
public class MailHelp { #region 01-发送邮件 /// <summary> /// 发送邮件 /// </summary> /// <param name="subject">主题</param> /// <param name="content">内容</param> /// <param name="receiveAddress">收件人邮箱</param> /// <param name="attachFileList">附件路径列表</param> /// <param name="senderName">发件人姓名</param> /// <returns></returns> public static string SendEmail(string subject, string content, string receiveAddress, List<string> attachFileList = null,string senderName = "" ) { string fromto = "1111@qq.com"; //发件人邮箱地址 string name = "brucelee@qq.com"; //发件人用户名 string upass = "lxxxx"; //发件人密码 string smtp = "smtp.juttec.com"; //发件SMTP服务器(如果用qq邮箱发,则是:smtp.qq.com) SmtpClient _smtpClient = new SmtpClient(); _smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;//指定电子邮件发送方式 _smtpClient.Host = smtp; //指定SMTP服务器 _smtpClient.Credentials = new System.Net.NetworkCredential(name, upass);//用户名和密码 MailMessage _mailMessage = new MailMessage(); //表示可以使用SmtpClient发送电子邮件 //发件人,发件人名 _mailMessage.From = new MailAddress(fromto, senderName); //收件人 _mailMessage.To.Add(receiveAddress); _mailMessage.SubjectEncoding = Encoding.UTF8; //Encoding.GetEncoding("gb2312"); //主题内容编码 _mailMessage.Subject = subject;//主题 _mailMessage.Body = content;//内容 //设置附件 if (attachFileList != null && attachFileList.Count > 0) { foreach (var item in attachFileList) { _mailMessage.Attachments.Add(new Attachment(item)); } } _mailMessage.BodyEncoding = Encoding.UTF8; //Encoding.GetEncoding("gb2312");//正文编码 _mailMessage.IsBodyHtml = true;//设置为HTML格式 _mailMessage.Priority = MailPriority.Normal;//MailPriority.High;//优先级 try { _smtpClient.Send(_mailMessage); //将指定的邮件发送到 SMTP 服务器以便传递。 return "ok"; } catch (Exception ) { return "error"; } } #endregion #region 复杂发送(暂时注释) //private readonly static string SmtpServer = "smtp.wedn.net"; //private readonly static int SmtpServerPort = 25; //private readonly static bool SmtpEnableSsl = false; //private readonly static string SmtpUsername = "server@wedn.net"; //private readonly static string SmtpDisplayName = "Wedn.Net"; //private readonly static string SmtpPassword = "2014@itcast"; ///// <summary> ///// 发送邮件到指定收件人 ///// </summary> ///// <param name="to">收件人地址</param> ///// <param name="subject">主题</param> ///// <param name="mailBody">正文内容(支持HTML)</param> ///// <param name="copyTos">抄送地址列表</param> ///// <returns>是否发送成功</returns> //public static bool Send(string to, string subject, string mailBody, params string[] copyTos) //{ // return Send(new[] { to }, subject, mailBody, copyTos, new string[] { }, MailPriority.Normal); //} ///// <summary> ///// 发送邮件到指定收件人 ///// </summary> ///// <remarks> ///// 2013-11-18 18:55 Created By iceStone ///// </remarks> ///// <param name="tos">收件人地址列表</param> ///// <param name="subject">主题</param> ///// <param name="mailBody">正文内容(支持HTML)</param> ///// <param name="ccs">抄送地址列表</param> ///// <param name="bccs">密件抄送地址列表</param> ///// <param name="priority">此邮件的优先级</param> ///// <param name="attachments">附件列表</param> ///// <returns>是否发送成功</returns> ///// <exception cref="System.ArgumentNullException">attachments</exception> //public static bool Send(string[] tos, string subject, string mailBody, string[] ccs, string[] bccs, MailPriority priority, params Attachment[] attachments) //{ // if (attachments == null) throw new ArgumentNullException("attachments"); // if (tos.Length == 0) return false; // //创建Email实体 // var message = new MailMessage(); // message.From = new MailAddress(SmtpUsername, SmtpDisplayName); // message.Subject = subject; // message.Body = mailBody; // message.BodyEncoding = Encoding.UTF8; // message.IsBodyHtml = true; // message.Priority = priority; // //插入附件 // foreach (var attachment in attachments) // { // message.Attachments.Add(attachment); // } // //插入收件人地址,抄送地址和密件抄送地址 // foreach (var to in tos.Where(c => !string.IsNullOrEmpty(c))) // { // message.To.Add(new MailAddress(to)); // } // foreach (var cc in ccs.Where(c => !string.IsNullOrEmpty(c))) // { // message.CC.Add(new MailAddress(cc)); // } // foreach (var bcc in bccs.Where(c => !string.IsNullOrEmpty(c))) // { // message.CC.Add(new MailAddress(bcc)); // } // //创建SMTP客户端 // var client = new SmtpClient // { // Host = SmtpServer, // Credentials = new System.Net.NetworkCredential(SmtpUsername, SmtpPassword), // DeliveryMethod = SmtpDeliveryMethod.Network, // EnableSsl = SmtpEnableSsl, // Port = SmtpServerPort // }; // //client.SendCompleted += Client_SendCompleted; // //try // //{ // //发送邮件 // client.Send(message); // //client.SendAsync(message,DateTime.Now.ToString()); // //client.Dispose(); // //message.Dispose(); // return true; // //} // //catch (Exception) // //{ // // throw; // //} //} #endregion }
RequestHelp
/// <summary> /// 基于HttpClientFactory的请求封装 /// 依赖【Microsoft.Extensions.DependencyInjection】和 【Microsoft.Extensions.Http】 /// 可以直接调用,在CoreMvc中不再需要注入AddHttpClient了,因为下面封装里已Add进去了 /// </summary> public class RequestHelp { /// <summary> /// Get请求 /// </summary> /// <param name="url">请求地址</param> /// <returns></returns> public static string MyGetRequest(string url) { var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); IHttpClientFactory clientFactory = serviceProvider.GetService<IHttpClientFactory>(); var request = new HttpRequestMessage(HttpMethod.Get, url); var client = clientFactory.CreateClient(); var response = client.SendAsync(request).Result; var myResult = response.Content.ReadAsStringAsync().Result; return myResult; } /// <summary> /// Post请求-表单形式 /// </summary> /// <param name="url">请求地址</param> /// <param name="content">请求内容</param> /// <returns></returns> public static string MyPostRequest(string url, string content) { var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); IHttpClientFactory clientFactory = serviceProvider.GetService<IHttpClientFactory>(); var request = new HttpRequestMessage(HttpMethod.Post, url); //内容的处理 request.Content = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded"); var client = clientFactory.CreateClient(); var response = client.SendAsync(request).Result; var myResult = response.Content.ReadAsStringAsync().Result; return myResult; } /// <summary> /// Post请求-Json形式 /// </summary> /// <param name="url">请求地址</param> /// <param name="content">请求内容</param> /// <returns></returns> public static string MyPostRequestJson(string url, object content) { var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); IHttpClientFactory clientFactory = serviceProvider.GetService<IHttpClientFactory>(); var request = new HttpRequestMessage(HttpMethod.Post, url); //内容的处理 request.Content = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json"); var client = clientFactory.CreateClient(); var response = client.SendAsync(request).Result; var myResult = response.Content.ReadAsStringAsync().Result; return myResult; } }
SftpHelp
/// <summary> /// SFTP相关的帮助类 /// 依赖程序集:【SSH.NET】 /// </summary> public class SftpHelp { #region 字段或属性 private SftpClient sftp; /// <summary> /// SFTP连接状态 /// </summary> public bool Connected { get { return sftp.IsConnected; } } #endregion #region 构造 /// <summary> /// 构造 /// </summary> /// <param name="host">host</param> /// <param name="user">用户名</param> /// <param name="pwd">密码</param> public SftpHelp(string host, string user, string pwd) { sftp = new SftpClient(host, user, pwd); } #endregion #region 连接SFTP /// <summary> /// 连接SFTP /// </summary> /// <returns>true成功</returns> public bool Connect() { if (!Connected) { sftp.Connect(); } return true; } #endregion #region 断开SFTP /// <summary> /// 断开SFTP /// </summary> public void Disconnect() { try { if (sftp != null && Connected) { sftp.Disconnect(); } } catch (Exception ex) { LogUtils.Error(ex); //throw new Exception(string.Format("断开SFTP失败,原因:{0}", ex.Message)); } } #endregion #region SFTP上传文件 /// <summary> /// SFTP上传文件 /// </summary> /// <param name="localPath">本地路径</param> /// <param name="remotePath">远程路径</param> public void Put(string localPath, string remotePath) { try { using (var file = File.OpenRead(localPath)) { Connect(); sftp.UploadFile(file, remotePath); Disconnect(); } } catch (Exception ex) { LogUtils.Error(ex); //throw new Exception(string.Format("SFTP文件上传失败,原因:{0}", ex.Message)); } } #endregion #region SFTP获取文件 /// <summary> /// SFTP获取文件 /// </summary> /// <param name="remotePath">远程路径</param> /// <param name="localPath">本地路径</param> /// <returns></returns> public bool Get(string remotePath, string localPath) { try { Connect(); var byt = sftp.ReadAllBytes(remotePath); Disconnect(); File.WriteAllBytes(localPath, byt); return true; } catch (Exception ex) { LogUtils.Error(ex); //throw new Exception(string.Format("SFTP文件获取失败,原因:{0}", ex.Message)); return false; } } #endregion #region 删除SFTP文件 /// <summary> /// 删除SFTP文件 /// </summary> /// <param name="remoteFile">远程路径</param> public bool Delete(string remoteFile) { var isDelete = false; try { Connect(); sftp.Delete(remoteFile); isDelete = true; Disconnect(); } catch (Exception ex) { LogUtils.Error(ex); //throw new Exception(string.Format("SFTP文件删除失败,原因:{0}", ex.Message)); } return isDelete; } #endregion #region 获取SFTP文件列表 /// <summary> /// 获取SFTP文件列表 /// </summary> /// <param name="remotePath">远程目录</param> /// <param name="fileSuffix">文件后缀</param> /// <returns></returns> public ArrayList GetFileList(string remotePath, string fileSuffix) { var objList = new ArrayList(); try { Connect(); var files = sftp.ListDirectory(remotePath); Disconnect(); foreach (var file in files) { string name = file.Name; if (name.Length > (fileSuffix.Length + 1) && fileSuffix == name.Substring(name.Length - fileSuffix.Length)) { objList.Add(name); } } } catch (Exception ex) { LogUtils.Error(ex); //throw new Exception(string.Format("SFTP文件列表获取失败,原因:{0}", ex.Message)); } return objList; } #endregion #region 移动SFTP文件 /// <summary> /// 移动SFTP文件 /// </summary> /// <param name="oldRemotePath">旧远程路径</param> /// <param name="newRemotePath">新远程路径</param> public void Move(string oldRemotePath, string newRemotePath) { try { Connect(); sftp.RenameFile(oldRemotePath, newRemotePath); Disconnect(); } catch (Exception ex) { LogUtils.Error(ex); //throw new Exception(string.Format("SFTP文件移动失败,原因:{0}", ex.Message)); } } #endregion }
3. Extensions
a. CacheStrategyExtensions: 定义缓存策略扩展方法,用于选择内存缓存、Redis缓存(提供两种程序集)、或者什么不用。
b. CoreMvcExtensions: 提供Cookie和Session的注册、日志的注册、HttpClient的注册的扩展方法。
c. SERedisHelp:基于程序集StackExchange.Redis的帮助类
d. SessionExtensions: 两种组件的Session扩展方式。
e. SortExtension:根据字段名称进行升序和降序排列的扩展,支持单字段和多字段。
代码分享:
CacheStrategyExtensions
/// <summary> /// 缓存策略扩展 /// </summary> public static class CacheStrategyExtensions { /// <summary> /// 添加缓存类型 /// (最后无论哪种模式,都把AddMemoryCache注入,方便单独使用IMemoryCache)(视情况而定) /// </summary> /// <param name="services"></param> /// <param name="CacheType">有4种取值 (Redis:代表基于CSRedisCore使用redis缓存, 并实例化redis相关对象. Memory:代表使用内存缓存; /// StackRedis: 代表基于StackExchange.Redis初始化; "null":表示什也不注入)</param> /// <returns></returns> public static IServiceCollection AddCacheStrategy(this IServiceCollection services, string CacheType) { switch (CacheType) { case "Memory": { services.AddDistributedMemoryCache(); }; break; case "Redis": { //基于CSRedisCore初始化 //初始化redis的两种使用方式 var csredis = new CSRedisClient(ConfigHelp.GetString("RedisStr")); services.AddSingleton(csredis); RedisHelper.Initialization(csredis); //初始化缓存基于redis services.AddSingleton<IDistributedCache>(new CSRedisCache(csredis)); }; break; case "StackRedis": { //基于StackExchange.Redis初始化(该程序集这里不初始化缓存) var connectionString = ConfigHelp.GetString("RedisStr"); services.AddSingleton(new SERedisHelp(connectionString)); }; break; case "null": { //什么也不注入 }; break; default: throw new Exception("缓存类型无效"); } //最后都把AddMemoryCache注入,方便单独使用IMemoryCache进行内存缓存(视情况而定) //services.AddMemoryCache(); return services; } }
CoreMvcExtensions:
/// <summary> /// CoreMvc基础服务注册扩展 /// </summary> public static class CoreMvcExtensions { /// <summary> /// Cookie和Session策略 /// (基于redis的Session策略注释,如果开启,需要把CacheStrategyExtensions中的AddMemoryCache注释掉) /// </summary> /// <param name="services"></param> /// <param name="CacheType">Session载体,Memory基于内存存储,StackRedis基于Redis存储,null什么也不注册</param> /// <returns></returns> public static IServiceCollection AddCookieAndSession(this IServiceCollection services, string CacheType) { //1.Cookie策略 services.Configure<CookiePolicyOptions>(options => { options.CheckConsentNeeded = context => false; options.MinimumSameSitePolicy = SameSiteMode.None; }); //2. Session相关配置 //2.1 配置Session相关的载体 switch (CacheType) { case "Memory": { services.AddDistributedMemoryCache(); }; break; case "StackRedis": { //需要把其它封装中的AddMemoryCache 或 AddDistributedMemoryCache都注释掉 services.AddStackExchangeRedisCache(options => { options.Configuration = ConfigHelp.GetString("RedisStr"); //options.InstanceName = "SampleInstance"; //给key加个前缀 }); }; break; case "null": { //什么也不注册 }; break; default: throw new Exception("Session载体无效"); } //2.2 注册Session服务 services.AddSession(options => { //Session的过期时间(多次访问将会被重置,默认过期时间为20分钟) //另外IIS的闲置超时选项也需要配置 options.IdleTimeout = TimeSpan.FromMinutes(120); //Cookie是必须的(默认是false),可以覆盖上面的cookie策略 options.Cookie.IsEssential = true; }); return services; } /// <summary> /// 注册日志服务 /// </summary> /// <param name="services"></param> /// <returns></returns> public static IServiceCollection AddLogStrategy(this IServiceCollection services, string logType = "SeriLog") { if (logType == "Log4net") { LogUtils2.InitLog(); } else { LogUtils.InitLog(); } return services; } /// <summary> /// 注册HttpClient服务 /// </summary> /// <param name="services"></param> /// <returns></returns> public static IServiceCollection AddMyHttpClient(this IServiceCollection services) { //1.基本用法 services.AddHttpClient(); //2. 命名客户端(用于指定表头和请求根目录---目前用不到) services.AddHttpClient("client1", c => { c.BaseAddress = new Uri("http://localhost:15319/"); c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample"); }); return services; } }
SERedisHelp
/// <summary> /// redis链接帮助类 /// 基于程序集:StackExchange.Redis /// </summary> public class SERedisHelp { private string _connectionString; //连接字符串 private int _defaultDB; //默认数据库 private readonly ConnectionMultiplexer connectionMultiplexer; /// <summary> /// 构造函数 /// </summary> /// <param name="connectionString"></param> /// <param name="defaultDB">默认使用Redis的0库</param> public SERedisHelp(string connectionString, int defaultDB = 0) { _connectionString = connectionString; _defaultDB = defaultDB; connectionMultiplexer = ConnectionMultiplexer.Connect(_connectionString); } /// <summary> /// 获取数据库 /// </summary> /// <returns></returns> public IDatabase GetDatabase() { return connectionMultiplexer.GetDatabase(_defaultDB); } }
SessionExtensions:
/// <summary> /// Session的两种扩展方式 /// 依赖程序集:【Microsoft.AspNetCore.Http】和【Microsoft.AspNetCore.Http.Extensions】 /// 两种序列化模式:【Newtonsoft.Json】和 【protobuf-net】 /// 其中 【protobuf-net】序列化的类名上要加 [ProtoContract],属性上要加 [ProtoMember(1)] [ProtoMember(2)] /// </summary> public static class SessionExtensions { #region 01-利用Newtonsoft.Json进行扩展 public static void Set<T>(this ISession session, string key, T value) { session.SetString(key, JsonConvert.SerializeObject(value)); } public static T Get<T>(this ISession session, string key) { var value = session.GetString(key); return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value); } #endregion #region 02-利用protobuf-net进行扩展 public static void Set2<T>(this ISession session, string key, T value) { using (MemoryStream stream = new MemoryStream()) { Serializer.Serialize(stream, value); byte[] byteArrary = stream.ToArray(); session.Set(key, byteArrary); } } public static T Get2<T>(this ISession session, string key) { byte[] byteArray = session.Get(key); if (byteArray == null) { return default(T); } else { using (MemoryStream stream = new MemoryStream(byteArray)) { return Serializer.Deserialize<T>(stream); } } } #endregion }
SortExtentsion:
/// <summary> /// 排序的扩展 /// </summary> public static class SortExtension { #region 01-根据string名称排序扩展(单字段) /// <summary> /// 根据string名称排序扩展(单字段) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source">排序数据源</param> /// <param name="sortName">排序名称</param> /// <param name="sortDirection">排序方式 asc或desc</param> /// <returns></returns> public static IQueryable<T> DataSorting<T>(this IQueryable<T> source, string sortName, string sortDirection) { string sortingDir = string.Empty; if (sortDirection.ToUpper().Trim() == "ASC") { sortingDir = "OrderBy"; } else if (sortDirection.ToUpper().Trim() == "DESC") { sortingDir = "OrderByDescending"; } ParameterExpression param = Expression.Parameter(typeof(T), sortName); PropertyInfo pi = typeof(T).GetProperty(sortName); Type[] types = new Type[2]; types[0] = typeof(T); types[1] = pi.PropertyType; Expression expr = Expression.Call(typeof(Queryable), sortingDir, types, source.Expression, Expression.Lambda(Expression.Property(param, sortName), param)); IQueryable<T> query = source.AsQueryable().Provider.CreateQuery<T>(expr); return query; } #endregion #region 02-根据多个string名称排序扩展(多字段) /// <summary> /// 根据多个string名称排序扩展(多字段) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="data">数据源</param> /// <param name="orderParams">排序类</param> /// <returns></returns> public static IQueryable<T> DataManySorting<T>(this IQueryable<T> data, params FiledOrderParam[] orderParams) where T : class { var parameter = Expression.Parameter(typeof(T), "p"); if (orderParams != null && orderParams.Length > 0) { for (int i = 0; i < orderParams.Length; i++) { var property = typeof(T).GetProperty(orderParams[i].PropertyName); if (property != null) { var propertyAccess = Expression.MakeMemberAccess(parameter, property); var orderByExpr = Expression.Lambda(propertyAccess, parameter); string methodName = i > 0 ? orderParams[i].IsDesc ? "ThenByDescending" : "ThenBy" : orderParams[i].IsDesc ? "OrderByDescending" : "OrderBy"; var resultExp = Expression.Call( typeof(Queryable), methodName, new Type[] { typeof(T), property.PropertyType }, data.Expression, Expression.Quote(orderByExpr) ); data = data.Provider.CreateQuery<T>(resultExp); } } } return data; } #endregion } /// <summary> /// 排序类 /// </summary> public class FiledOrderParam { //是否降序 public bool IsDesc { get; set; } //排序名称 public string PropertyName { get; set; } }
4. Log
a. Log4net: 提供配置文件和帮助类(后续将废弃)
b. SeriLog: 提供LogUtils帮助类
代码分享:
详见前面的日志章节:https://www.cnblogs.com/yaopengfei/p/14244416.html
5. Safe
a. JWTHelp:Jwt加密和解密相关的帮助类。
b. SecurityHelp:各种加密、解密相关算法。
代码分享:
JWTHelp:
/// <summary> /// Jwt的加密和解密 /// 注:加密和加密用的是用一个密钥 /// 依赖程序集:【JWT】 /// </summary> public class JWTHelp { /// <summary> /// JWT加密算法 /// </summary> /// <param name="payload">负荷部分,存储使用的信息</param> /// <param name="secret">密钥</param> /// <param name="extraHeaders">存放表头额外的信息,不需要的话可以不传</param> /// <returns></returns> public static string JWTJiaM(IDictionary<string, object> payload, string secret, IDictionary<string, object> extraHeaders = null) { IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); IJsonSerializer serializer = new JsonNetSerializer(); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder); var token = encoder.Encode(payload, secret); return token; } /// <summary> /// JWT解密算法(新的7.x版本写法) /// </summary> /// <param name="token">需要解密的token串</param> /// <param name="secret">密钥</param> /// <returns></returns> public static string JWTJieM(string token, string secret) { try { IJsonSerializer serializer = new JsonNetSerializer(); IDateTimeProvider provider = new UtcDateTimeProvider(); IJwtValidator validator = new JwtValidator(serializer, provider); IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); // symmetric IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm); var json = decoder.Decode(token, secret, true); //校验通过,返回解密后的字符串 return json; } catch (TokenExpiredException) { //表示过期 return "expired"; } catch (SignatureVerificationException) { //表示验证不通过 return "invalid"; } catch (Exception) { return "error"; } } ///// <summary> ///// JWT解密算法(旧的5.x版本写法) ///// </summary> ///// <param name="token">需要解密的token串</param> ///// <param name="secret">密钥</param> ///// <returns></returns> //public static string JWTJieM(string token, string secret) //{ // try // { // IJsonSerializer serializer = new JsonNetSerializer(); // IDateTimeProvider provider = new UtcDateTimeProvider(); // IJwtValidator validator = new JwtValidator(serializer, provider); // IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); // IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder); // var json = decoder.Decode(token, secret, true); // //校验通过,返回解密后的字符串 // return json; // } // catch (TokenExpiredException) // { // //表示过期 // return "expired"; // } // catch (SignatureVerificationException) // { // //表示验证不通过 // return "invalid"; // } // catch (Exception) // { // return "error"; // } //} }
SecurityHelp:
/// <summary> /// 各种加密解密算法 /// 依赖程序集【NETCore.Encrypt】 /// </summary> public class SecurityHelp { /// <summary> /// Base64编码 /// </summary> /// <param name="srcString">需要编码的字符串</param> /// <returns></returns> public static string Base64Encrypt(string srcString) { return EncryptProvider.Base64Encrypt(srcString); //default encoding is UTF-8 } /// <summary> /// Base64编码 /// </summary> /// <param name="encString">需要解码的字符串</param> /// <returns></returns> public static string Base64Decrypt(string encString) { return EncryptProvider.Base64Decrypt(encString); //default encoding is UTF-8 } /// <summary> /// MD5加密 /// </summary> /// <param name="srcString">需要加密的字符串</param> /// <param name="num">位数,默认为32位,也可以是16位</param> /// <returns></returns> public static string Md5(string srcString, int num = 32) { if (num == 32) { return EncryptProvider.Md5(srcString); //默认32位 } else { return EncryptProvider.Md5(srcString, MD5Length.L16); //16位 } } /// <summary> /// SHA系列算法 /// </summary> /// <param name="srcString">需要加密的字符串</param> /// <param name="kind">类型</param> /// <returns></returns> public static string SHA(string srcString, string kind = "Sha512") { if (kind.Equals("Sha1")) { return EncryptProvider.Sha1(srcString); } else if (kind.Equals("Sha256")) { return EncryptProvider.Sha256(srcString); } else if (kind.Equals("Sha384")) { return EncryptProvider.Sha384(srcString); } else { return EncryptProvider.Sha512(srcString); } } /// <summary> /// HMAC系列算法 /// </summary> /// <param name="srcString">需要加密的字符串</param> /// <param name="secretKey">密钥</param> /// <param name="kind">类型</param> /// <returns></returns> public static string HMAC(string srcString, string secretKey, string kind = "HMACSHA512") { if (kind.Equals("HMACMD5")) { return EncryptProvider.HMACMD5(srcString, secretKey); } else if (kind.Equals("HMACSHA1")) { return EncryptProvider.HMACSHA1(srcString, secretKey); } else if (kind.Equals("HMACSHA256")) { return EncryptProvider.HMACSHA256(srcString, secretKey); } else if (kind.Equals("HMACSHA384")) { return EncryptProvider.HMACSHA384(srcString, secretKey); } else { return EncryptProvider.HMACSHA512(srcString, secretKey); } } /// <summary> /// 生成AES算法所需的Key和iv /// (当然这里可以自己指定并保存好) /// </summary> /// <param name="key">加密所需的key</param> /// <param name="iv">加密所需的矢量</param> public static void CreateAesKey(ref string key, ref string iv) { //利用算法生成key和iv(32位和16位),当然这里可以自己指定并保存好 var aesKey = EncryptProvider.CreateAesKey(); key = aesKey.Key; iv = aesKey.IV; } /// <summary> /// AES加密算法 /// </summary> /// <param name="srcString">需要加密的字符串</param> /// <param name="secretKey">密钥</param> /// <param name="iv">矢量(可以不填)</param> /// <returns></returns> public static string AESEncrypt(string srcString, string secretKey, string iv = "") { if (string.IsNullOrEmpty(iv)) { return EncryptProvider.AESEncrypt(srcString, secretKey); //表示不需要iv矢量的AES加密算法 } else { return EncryptProvider.AESEncrypt(srcString, secretKey, iv); //表示需要iv矢量的AES加密算法 } } /// <summary> /// AES解密算法 /// </summary> /// <param name="encString">需要解密的字符串</param> /// <param name="secretKey">密钥</param> /// <param name="iv">矢量(可以不填)</param> /// <returns></returns> public static string AESDecrypt(string encString, string secretKey, string iv = "") { if (string.IsNullOrEmpty(iv)) { return EncryptProvider.AESDecrypt(encString, secretKey); //表示不需要iv矢量的AES解密算法 } else { return EncryptProvider.AESDecrypt(encString, secretKey, iv); //表示需要iv矢量的AES解密算法 } } /// <summary> /// DES加密算法 /// </summary> /// <param name="srcString">需要加密的字符串</param> /// <param name="secretKey">密钥(这里的密钥需要是24位)</param> /// <returns></returns> public static string EDSEncrypt(string srcString, string secretKey) { return EncryptProvider.DESEncrypt(srcString, secretKey); } /// <summary> /// DES解密算法 /// </summary> /// <param name="encString">需要解密的字符串</param> /// <param name="secretKey">密钥</param> /// <returns></returns> public static string DESDecrypt(string encString, string secretKey) { return EncryptProvider.DESDecrypt(encString, secretKey); } /// <summary> /// 生成RSA算法所需的Key和iv /// (当然这里可以自己指定并保存好) /// </summary> /// <param name="PublicKey">公钥</param> /// <param name="PrivateKey">私钥</param> public static void CreateRsaKey(ref string PublicKey, ref string PrivateKey) { //利用算法生成公钥和私钥,然后保存;当然这里可以自己指定并保存好 var rsaKey = EncryptProvider.CreateRsaKey(); //default is 2048 // var rsaKey = EncryptProvider.CreateRsaKey(RsaSize.R3072); PublicKey = rsaKey.PublicKey; PrivateKey = rsaKey.PrivateKey; } /// <summary> /// RSA加密算法 /// </summary> /// <param name="srcString">需要加密的字符串</param> /// <param name="publicKey">公钥 加密</param> /// <returns></returns> public static string RSAEncrypt(string srcString, string publicKey) { return EncryptProvider.RSAEncrypt(publicKey, srcString); //公钥加密 } /// <summary> /// RSA解密算法 /// </summary> /// <param name="encString">需要解密的字符串</param> /// <param name="privateKey">私钥 解密</param> /// <returns></returns> public static string RSADecrypt(string encString, string privateKey) { return EncryptProvider.RSADecrypt(privateKey, encString); //私钥解密 } } public enum RsaSize { R2048 = 2048, R3072 = 3072, R4096 = 4096 }
6. Transform
a. JsonHelp: JSON序列化和反序列的方法,目前利用的还是NewTonSoft.Json, 基于Core3.1中 【System.Text.Json】的序列化功能不是很完善,暂时注释。
代码分享:
/// <summary> /// Json的序列化和反序列化 /// 依赖程序集:Newtonsoft.Json; 和 Core 3.x内置的System.Text.Json /// System.Text.Json 不完善,有很多问题:https://www.cnblogs.com/dudu/p/11562019.html /// </summary> public class JsonHelp { #region 01-将JSON转换成JSON字符串 /// <summary> ///将JSON转换成JSON字符串 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <returns></returns> public static string ToJsonString<T>(T obj) { return JsonConvert.SerializeObject(obj); //Newtonsoft.Json写法 } #endregion #region 02-将字符串转换成JSON对象 /// <summary> /// 将字符串转换成JSON对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="content"></param> /// <returns></returns> public static T ToObject<T>(string content) { return JsonConvert.DeserializeObject<T>(content); //Newtonsoft.Json写法 } #endregion #region 03-将JSON转换成JSON字符串(目前不成熟) /// <summary> ///将JSON转换成JSON字符串 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <returns></returns> public static string ToJsonString2<T>(T obj) { return System.Text.Json.JsonSerializer.Serialize(obj); } #endregion #region 04-将字符串转换成JSON对象(目前不成熟) /// <summary> /// 将字符串转换成JSON对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="content"></param> /// <returns></returns> public static T ToObject2<T>(string content) { return System.Text.Json.JsonSerializer.Deserialize<T>(content); } #endregion }
三. 核心功能测试
1. 根据字段名称进行升/降序
代码分享:
{ int pageIndex = 2; int pageSize = 5; //1.分开写法 var list1 = _baseService.Entities<T_SysUser>().Where(u => u.id != "fk").DataSorting("addTime", "desc").Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); //2. 封装调用 int count = 0; var list2 = _baseService.GetPageListByName<T_SysUser>(pageIndex, pageSize, out count, u => u.id != "fk", "addTime", "desc"); //3.多字段排序 FiledOrderParam[] param = { new FiledOrderParam(){IsDesc=false,PropertyName="addTime"}, new FiledOrderParam(){IsDesc=true,PropertyName="id"} }; var list3 = _baseService.Entities<T_SysUser>().Where(u => u.id != "fk").DataManySorting(param).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); }
对应SQL的语句:
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。