第五节:集成全局返回值处理、详解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
    {
    }
View Code

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];
        }

    }
View Code

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

    }
View Code

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;
        }

    }
View Code

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
    }
View Code

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;
        }
    }
View Code

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;
        }

    }
View Code

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);
        }
    }
View Code

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
    }
View Code

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; }
    }
View Code

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";
        //    }
        //}


    }
View Code

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
    }
View Code

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
    }
View Code

 

三. 核心功能测试

 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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 

 

posted @ 2021-01-18 15:49  Yaopengfei  阅读(270)  评论(2编辑  收藏  举报