清风博客 https://www.skyfinder.cc 人生贵知心,定交无暮早 Fri, 28 Feb 2020 04:15:27 +0000 zh-CN hourly 1 https://wordpress.org/?v=5.3.2 2020年春节随笔 https://www.skyfinder.cc/2020/02/28/2020newyearrecord/ https://www.skyfinder.cc/2020/02/28/2020newyearrecord/#respond Fri, 28 Feb 2020 04:00:00 +0000 https://www.skyfinder.cc/?p=2550

今年的春节可能是我们经历过的最特别的春节了,为了预防新型冠状病毒感染,全国延长春节假期,延迟开工开学,亿万中国人坚守家中,平常热闹的街道和场所空荡无人。因为疫情的存在,我也和全国大部分人一样呆在家中,吃喝睡。

今年疫情严重的有点厉害,都封路禁行,出去买东西都很是困难。不过这也是没有办法的事情,毕竟疫情严重,为了安全还是安分点好,一旦出现意外就有可能因为病情严重导致生命终结,从而被拉去火葬场。

其实这个春节过的挺糟心的,在疫情还没有严重时候,就连武汉都没有重视的时候。这个时候也基本快过春节了,我也由外地回家(火车途径武汉),想来我是多么的幸运,如果不是车停在武昌站是晚上,兴许我会到站台跑一圈,那样也许会出一个意外。也许幸运,也许是上天怜悯,自己安全到家,家人们也都相对安全。

我到家之后也随时关注新闻,当武汉以及全国各个省市区都还没有一级应急响应的时候,为了应对这个新型冠状病毒专门到药店去买口罩,奈何这穷地方很多药店都没有N95口罩,就连普通医用口罩也不多,几经查找最终找到药店买了河南飘安集团有限公司产生的1大包(10小包,1小包20只)口罩,我想这总该可以应对这个春节期间的日常防护吧!疫情爆发,各地封路禁行,我还庆幸自己准备了口罩。在这个特殊的春节里,我以及家人都带着这种口罩,春节过去后,网上就有各种新闻表示假口罩很多,其中最严重的仿冒产品就是河南飘安集团有限公司生产的一次性口罩,几经对比并确认自己所买的口罩是假的,毕竟河南飘安集团有限公司也发了声明,图片、特征什么的都公布,与自己买口罩一个鸟样。在此次疫情之前,我从来没有用过口罩,医用口罩也没有近距离接触,至于口罩的真假识别就更不晓得啦。这个情况把我吓的一哆嗦,还好附近没有出现过病例,要不然自己乃至全家都逃不过呀。医疗器械都卖假的,这是在谋杀呀,太可怕啦。本想报警举报,但是想想还是放弃了,疫情期间我怕麻烦呀,本来就是假的,在因为去派出所报警增加感染率就不太值当了。其实我不报警还有一个原因,我们本地警察的名声不太好。下面就亮一亮我买的口罩是什么样子的吧,也警示大家买任何东西的时候都擦亮眼睛。

新年过后还有一个伤心的事情,就是族内的一个亲人走了,我该称之为大大( dà dà ),因病故去,为之守灵两个晚上。因为疫情原因,办理后事也比较简单,当前规定不允许人群聚集,所以赶到这个时候也没有什么办。但愿一路走好,来生无灾无病。说起生死,这是一个沉重话题,总能让人想起更多伤心的事情。算了,不说了!!!

转载请注明:清风博客 » 2020年春节随笔

]]>
https://www.skyfinder.cc/2020/02/28/2020newyearrecord/feed/ 0
Linux Centos 7更换国内源 https://www.skyfinder.cc/2020/02/27/linux-centos-7-update-yum/ https://www.skyfinder.cc/2020/02/27/linux-centos-7-update-yum/#respond Thu, 27 Feb 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=2539 由于Linux Centos 官方的源在国外服务器, 使用官方源速度慢的出奇,所以要更换为国内的源,于是有了以下内容。

首先备份原有Linux Centos 7的源/etc/yum.repos.d/CentOS-Base.repo

mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

某些Centos镜像安装后可能没有wget,可以尝试curl 进行操作,如下

curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

转载请注明:清风博客 » Linux Centos 7更换国内源

]]>
https://www.skyfinder.cc/2020/02/27/linux-centos-7-update-yum/feed/ 0
hyper-v虚拟机安装Linux Centos 7 网络配置 https://www.skyfinder.cc/2020/02/26/hyper-v-linux-centos-7-network-setting/ https://www.skyfinder.cc/2020/02/26/hyper-v-linux-centos-7-network-setting/#respond Wed, 26 Feb 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=2510 hyper-v虚拟机安装了centos7之后并不能上网,有些测试就无法继续进行,接下来就需要进行一些配置。

新建虚拟交换机

下图紧接着2、3、4步。

设置名称并设置连接类型。

设置网络适配器。

启动虚拟机系统Centos并登录, 进入到network-scripts目录 。

cd /etc/sysconfig/network-scripts
vi ifcfg-eth0

ONBOOT=no改为 ONBOOT=yes保存后重启网络。

systemctl restart network

转载请注明:清风博客 » hyper-v虚拟机安装Linux Centos 7 网络配置

]]>
https://www.skyfinder.cc/2020/02/26/hyper-v-linux-centos-7-network-setting/feed/ 0
ScreenToGif一款实用的屏幕录制动态gif生成工具 https://www.skyfinder.cc/2020/02/25/screentogif-gif-generate/ https://www.skyfinder.cc/2020/02/25/screentogif-gif-generate/#respond Tue, 25 Feb 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=2499 ScreenToGif工具介绍

ScreenToGif 是一款录制屏幕、摄像头、画板于一身的 GIF 制作软件(Screen, webcam and sketchboard recorder with an integrated editor.)。

该工具允许您记录屏幕的选定区域,网络摄像头的实时动态或草图面板上的实时图形。之后,您可以编辑动画并将其另存为gif,apng,视频,psd或png图像 。

项目地址

screentogif项目地址screentogif项目GitHub开源

转载请注明:清风博客 » ScreenToGif一款实用的屏幕录制动态gif生成工具

]]>
https://www.skyfinder.cc/2020/02/25/screentogif-gif-generate/feed/ 0
Linux中退出vi编辑模式 https://www.skyfinder.cc/2020/02/24/linuxexitvi/ https://www.skyfinder.cc/2020/02/24/linuxexitvi/#respond Mon, 24 Feb 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=2486

点击ESC进入“正常模式”,然后输入“:”,进入“命令模式”。此时屏幕的下方会出现一个冒号,你可以输入以下命令,并按“ENTER”执行:

  • :q 退出(:quit的缩写)
  • :q! 退出且不保存(:quit!的缩写)
  • :w 保存文件但不退出vi
  • :w file 将修改另外保存到file中,不退出vi
  • :w! 强制保存,不退出vi
  • :wq 保存并退出
  • :wq! 保存并退出即使文件没有写入权限(强制保存退出)
  • :x 保存并退出(类似:wq,但是只有在有更改的情况下才保存)
  • :exit 保存并退出(和:x相同)
  • :qa 退出所有(:quitall的缩写)
  • :cq 退出且不保存(即便有错误)

转载请注明:清风博客 » Linux中退出vi编辑模式

]]>
https://www.skyfinder.cc/2020/02/24/linuxexitvi/feed/ 0
下载Linux CentOS系统镜像 https://www.skyfinder.cc/2020/02/23/downlinux-centos-system-image/ https://www.skyfinder.cc/2020/02/23/downlinux-centos-system-image/#respond Sun, 23 Feb 2020 13:00:00 +0000 https://www.skyfinder.cc/?p=2462 在学习或者工作当中,很大机率用到CentOS系统。在此之前使用centos基本上都是阿里、腾讯云的虚拟机,并没有下载镜像到本地进行安装部署。由于某些需求,需要下载centos系统镜像,之后要在虚拟机上进行安装测试一些内容,所以就找了下镜像。

CentOS

CentOS(Community Enterprise Operating System,中文意思是社区企业操作系统)是Linux发行版之一,它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定性的服务器以CentOS替代商业版的Red Hat Enterprise Linux使用。两者的不同,在于CentOS完全开源。

官网下载

Centos官网地址

官方网站下载的确可行,但不建议在官方网站进行下载,因为下载速度的确太慢了,速度简直无法忍受。

国内镜像网站下载

163镜像站点阿里云镜像站点

这里使用163的镜像站点,首先打开镜像站点并选择Centos

这里下载Centos7的最新版本7.7.1908

Centos版本区别

  • CentOS-7-DVD版本:DVD是标准安装盘,一般下载这个就可以了。
  • CentOS-7-NetInstall版本:网络安装镜像。
  • CentOS-7-Everything版本:对完整版安装盘的软件进行补充,集成所有软件。
  • CentOS-7-GnomeLive版本:GNOME桌面版。
  • CentOS-7-KdeLive版本:KDE桌面版。
  • CentOS-7-Minimal版本:最小安装盘,只有必要的软件,自带的软件最少
  • CentOS-7.0-livecd版本:光盘上运行的系统,类拟于winpe

本次测试使用的就是Centos-7-x86_64-Minimal-1908.iso

历史版本下载

centos历史版本下载

转载请注明:清风博客 » 下载Linux CentOS系统镜像

]]>
https://www.skyfinder.cc/2020/02/23/downlinux-centos-system-image/feed/ 0
七步诗-曹植 https://www.skyfinder.cc/2020/02/17/qibushicaozhi/ https://www.skyfinder.cc/2020/02/17/qibushicaozhi/#respond Mon, 17 Feb 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=2394

老师给小孩留了作业,背诵曹植的七步诗,索性就整理了一下,整理后得知其版本存在不少。自己上学那会学的四句版的,至于哪一个版本是真的也不是自己可以探究的,整理也算温习一下吧!

《七步诗》是三国时期魏国诗人曹植的一首诗。这首诗用同根而生的萁和豆来比喻同父共母的兄弟,用萁煎其豆来比喻同胞骨肉的哥哥曹丕残害弟弟,表达了对曹丕的强烈不满,生动形象、深入浅出地反映了封建统治集团内部的残酷斗争和诗人自身处境艰难,沉郁愤激的思想感情。

作品原文

版本一

七步诗


煮豆持作羹,漉豉以为汁。
萁在釜下燃,豆在釜中泣。
本自同根生,相煎何太急?

版本二

七步诗


煮豆燃豆萁,豆在釜中泣。
本是同根生,相煎何太急?

版本三

七步诗


煮豆持作羹,漉菽以为汁。
萁在釜下燃,豆在釜中泣。
本自同根生,相煎何太急?

版本四

七步诗


煮豆然豆萁,漉豉以为汁。
萁在釜下然,豆在釜中泣。
本是同根生,相煎何太急!

白话译文

煮豆来做豆羹,过滤的豆子做成汁。豆杆在锅下燃烧,豆子在锅里哭泣。豆杆和豆子本是从同一条根上生长出来的,为什么要相互煎熬逼迫得那么狠呢?

创作背景

黄初元年(220年)正月,六十六岁的曹操病死,曹丕由世子荣升魏王;同年十月,汉献帝被迫禅让帝位,曹丕上位,称帝为魏文帝。由于争封太子这段经历让曹丕无法释怀,在他称帝后,他仍对曹植耿耿于怀。他担心这个有学识又有政治志向的弟弟会威胁自己的皇位,就想着法子要除掉他。曹植知道哥哥存心陷害自己,可自己无法开脱,只好在极度悲愤中七步之内应声成诗。

作者简介

曹植(192—232),字子建,沛国谯郡(今安徽毫州人)。三国时期的文学家。他是曹操的第四子,曹丕的同母弟,封陈王。因富于才学,早年曾受曹操宠爱,一度欲立为太子。及曹丕、曹龊为帝,备受猜忌,郁郁而死。

他是建安文学的杰出代表,现存诗九十多首,绝大部分是五言诗。曹植的诗歌善用比兴,辞采华茂,比较全面地代表了建安文学的成就和特色,对五言诗的发展有着重要的影响。

七步诗音频

朗诵

儿歌

转载请注明:清风博客 » 七步诗-曹植

]]>
https://www.skyfinder.cc/2020/02/17/qibushicaozhi/feed/ 0
使用C#通过NTP同步本地Windows系统时间 https://www.skyfinder.cc/2020/02/08/usecsharpntpsyncwindowsdatetime/ https://www.skyfinder.cc/2020/02/08/usecsharpntpsyncwindowsdatetime/#respond Sat, 08 Feb 2020 05:50:10 +0000 https://www.skyfinder.cc/?p=2342 每年春节买票都成为相当重要的事情,快人一步基本能尽可能的抢占先机。使用抢票软件尽可能的减少手工操作,从而提高抢票的成功机率,由于时间误差也可会丧失先机,所以同步系统时间也是重要一步。为了可以自动的同步本地时间,所以就使用C#实现一个时间同步小工具。

只针对Windows系统的时间同步且使用抢票平台的不在此列。

using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WindowsDateTimeSynchronization
{

    public class DateTimeSynchronization
    {
        [StructLayout(LayoutKind.Sequential)]
        private struct Systemtime
        {
            public short year;
            public short month;
            public short dayOfWeek;
            public short day;
            public short hour;
            public short minute;
            public short second;
            public short milliseconds;
        }

        [DllImport("kernel32.dll")]
        private static extern bool SetLocalTime(ref Systemtime time);

        private static uint swapEndian(ulong x)
        {
            return (uint)(((x & 0x000000ff) << 24) +
            ((x & 0x0000ff00) << 8) +
            ((x & 0x00ff0000) >> 8) +
            ((x & 0xff000000) >> 24));
        }

        /// <summary>
        /// 设置系统时间
        /// </summary>
        /// <param name="dt">需要设置的时间</param>
        /// <returns>返回系统时间设置状态,true为成功,false为失败</returns>
        private static bool SetLocalDateTime(DateTime dt)
        {
            Systemtime st;
            st.year = (short)dt.Year;
            st.month = (short)dt.Month;
            st.dayOfWeek = (short)dt.DayOfWeek;
            st.day = (short)dt.Day;
            st.hour = (short)dt.Hour;
            st.minute = (short)dt.Minute;
            st.second = (short)dt.Second;
            st.milliseconds = (short)dt.Millisecond;
            bool rt = SetLocalTime(ref st);
            return rt;
        }
        private static IPAddress iPAddress = null;
        public static bool Synchronization(string host,out DateTime syncDateTime,out string message)
        {
            syncDateTime = DateTime.Now;
            try
            {
                message = "";
                if (iPAddress == null)
                {
                    var iphostinfo = Dns.GetHostEntry(host);
                    var ntpServer = iphostinfo.AddressList[0];
                    iPAddress = ntpServer;
                }
                //NTP消息大小摘要是16字节 (RFC 2030)
                byte[] ntpData = new byte[48];
                //设置跳跃指示器、版本号和模式值
                ntpData[0] = 0x1B; // LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
                IPAddress ip = iPAddress;
                // NTP服务给UDP分配的端口号是123
                IPEndPoint ipEndPoint = new IPEndPoint(ip, 123);
                // 使用UTP进行通讯
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                DateTime dtStart = DateTime.Now;
                socket.Connect(ipEndPoint);
                socket.ReceiveTimeout = 3000;
                socket.Send(ntpData);
                socket.Receive(ntpData);
                socket?.Close();
                socket?.Dispose();
                DateTime dtEnd = DateTime.Now;
                //传输时间戳字段偏移量,以64位时间戳格式,应答离开客户端服务器的时间
                const byte serverReplyTime = 40;
                // 获得秒的部分
                ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
                //获取秒的部分
                ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
                //由big-endian 到 little-endian的转换
                intPart = swapEndian(intPart);
                fractPart = swapEndian(fractPart);
                ulong milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000UL);
                // UTC时间
                DateTime webTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
                //webTime = webTime.Subtract(-(dtEnd - dtStart));
                //本地时间
                DateTime dt = webTime.ToLocalTime();
                bool isSuccess = SetLocalDateTime(dt);
                syncDateTime = dt;

            }
            catch (Exception ex)
            {
                message = ex.Message;
                return false;
            }
            return true;

        }
    }

    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("ntp时间同步");
            DateTime dt = DateTime.Now;
            Console.WriteLine($"现在本地时间:{dt.ToString("yyyy-MM-dd HH:mm:ss")}");
            string errorMessage = "";
            DateTimeSynchronization.Synchronization("ntp.aliyun.com",out dt,out errorMessage);
            if (string.IsNullOrWhiteSpace(errorMessage))
            {
                Console.WriteLine($"同步时间:{dt.ToString("yyyy-MM-dd HH:mm:ss")}");
            }
            Console.Read();
        }


    }
}


示例下载

通过NTP服务器同步Windows系统时间

转载请注明:清风博客 » 使用C#通过NTP同步本地Windows系统时间

]]>
https://www.skyfinder.cc/2020/02/08/usecsharpntpsyncwindowsdatetime/feed/ 0
基于Redis的缓存系统 https://www.skyfinder.cc/2020/01/16/rediscache/ https://www.skyfinder.cc/2020/01/16/rediscache/#respond Thu, 16 Jan 2020 02:00:00 +0000 https://www.skyfinder.cc/?p=2312

简介

缓存的工作机制是先从缓存中读取数据,如果没有,再从慢速设备上读取实际数据并同步到缓存。计算机系统里天然就存在多级缓存系统,这是由于不同的硬件设备的访问速度以及容量大小不一致引起的一个选择。比如,CPU到L1/L2/L3到内存到磁盘的访问方式就是一个典型的多级缓存的例子。当CPU需要数据的时候,它首先到L1里找,如果没有找到,则查找L2/L3,如果还是没有找到,则再到内存里找,如果还没有,再到磁盘里查找。不同层级的缓存的访问速度和容量大小各不相同,简要对比如下所示:

名称 访问速度 通常容量大小
L1 1.3纳秒 12组每组32KB数据加32KB代码
L2 3.92纳秒 32组每组256KB
L3 11.11纳秒 30MB
DDR4 内存 100纳秒 8GB,16GB,32GB,64GB,128GB
NVMe SSD磁盘 120000纳秒 1TB, 2TB
SATA SSD磁盘 400000纳秒 1TB,2TB
机械磁盘 6毫秒 1TB,2TB

缓存命中率

缓存命中率是从缓存中读取数据的次数与总读取次数的比率,命中率越高越好。这是一个非常重要的监控指标,它能反映缓存系统是否工作良好。

缓存回收策略

  1. 基于存储空间
    基于存储空间的回收策略是指缓存设置了最大的存储空间,比如设500MB,当达到存储空间上限时,按照一定的回收算法移除旧数据。
  2. 基于容量大小
    基于容量大小的回收策略是指缓存设置了最大的数据条目数大小,当缓存的条目超过最大值后,按照一定的回收算法移除旧数据。
  3. 基于时间
    有两种典型的衡量时间的方式,如下:
    TTL(Time To Live)即存活期,意思是缓存数据从创建开始直到到期的一个时间段(不管在这个时间内有没有被访问,缓存数据都将过期)。
    TTI(Time To Idle)即空闲期,意思是缓存数据多久没被访问后移除缓存的时间。

缓存回收算法

使用基于存储空间和基于容量大小的缓存方式需要借助一定的回收算法策略去移除旧数据,常见的缓存回收算法有以下三种:

  1. FIFO(First In First Out)即先进先出算法,意思是先放入缓存的数据会被先移除。
  2. LRU(Least Recently Used)即最近最少使用算法,意思是使用时间距离现在最久的那个缓存数据会被移除。
  3. LFU(Least Frequently Used)即最不常用算法,意思是一定时间段内使用次数最少的那个缓存数据会被移除。

在实践中,使用LRU算法的缓存居多。

缓存的类型

按照缓存的可访问范围划分缓存数据的类型,系统内具有以下两类缓存:

  1. 全局共享缓存,系统内所有微服务应用均能访问的缓存数据。
  2. 本地专属缓存,只能被各个微服务应用自己访问的缓存数据。

缓存更新策略

系统采用先更新数据库,成功后,再让缓存失效的更新策略。采用这个策略,而不是采用“先删除缓存,再更新数据库”的策略,是为了避免并发操作下引发的访问脏数据的问题。即,当有两个并发操作,一个是更新操作,另一个是查询操作,当更新操作删除缓存后,查询操作没有命中缓存,它去将旧数据读取出来并放到缓存中去,然后更新操作更新了数据库。于是,在缓存中的数据还是 旧 的数据,导致缓存中的数据是脏的,而且还一直这样脏下去。

你可能已经注意到了,这里只是让缓存失效,并没有更新缓存,为什么不是写完数据库后更新缓存?这个选择主要是怕两个并发的写操作导致脏数据。这个策略有没有并发的问题?答案是有的。只是出现的概率比较低。比如,一个是读操作,但是没有命中缓存,然后就到数据库中取出数据,这时,来了一个写操作,写完数据库后,让缓存失效之后,之前的读操作再将旧的数据写入缓存,于是,造成了脏数据。说这个情况的出现概率比较小,是因为,它需要同时满足以下条件:需要发生在读缓存时缓存失效,并且并发着有一个写操作。而且读操作必须在写操作前进入数据库操作,且又要晚于写操作更新缓存。对一个数据库的操作来说,写操作会比读操作慢得多,而且还要锁表,要满足前述条件概率并不大。

缓存系统需要注意的场景

  1. 缓存穿透
    缓存穿透是指查询的数据在数据库里是不存,那么在缓存中自然也没有,所以,在缓存中查不到就会回到数据库中做查询,如果此类并发请求很多,那么对数据库压力势必很大,很容易跑满数据库连接,进而使得系统性能急剧下降。
  2. 缓存击穿
    缓存击穿是指对于某些热点的数据设置了过期时间,在缓存到期失效后,大量的并发请求会直接回数据库查询,进而引起很大的数据库访问压力。
  3. 缓存雪崩
    缓存雪崩只指缓存不可用或者大量缓存数据由于超时时间相同在同一时间段失效,使得大量并发请求回数据库查询,数据库压力过大引起系统雪崩。

转载请注明:清风博客 » 基于Redis的缓存系统

]]>
https://www.skyfinder.cc/2020/01/16/rediscache/feed/ 0
ASP.NET Core 配置跨域(CORS) https://www.skyfinder.cc/2020/01/13/aspnetcorecors/ https://www.skyfinder.cc/2020/01/13/aspnetcorecors/#respond Mon, 13 Jan 2020 01:00:00 +0000 https://www.skyfinder.cc/?p=2235 由于项目中需要实时消息,所以就使用了ASP.NET(Core) SignalR实时通讯库。因为业务服务与通讯服务是独立的,所以涉及到跨域的问题, 浏览器抛出的异常非常明显,这个是明显跨域相关内容。 报错信息如下:

Access to XMLHttpRequest at ‘http://192.168.2.13:5005/api/v1/commommessage/messageHub/negotiate’ from origin ‘http://127.0.0.1:5500’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

CORS(跨域资源共享)是一种W3C标准,允许服务器放宽同源策略。使用CORS,服务器可以在显式允许某些跨域请求时拒绝其他跨域请求。CORS是相比其他跨域技术(比如JSONP)更安全、更灵活。

ASP.NET Core跨域问题需要再 StartUp.cs 文件中进行相关配置。

ConfigureServices方法增加内容

        services.AddCors(options => options.AddPolicy("CorsPolicy",
            builder =>
            {
                builder.AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowAnyOrigin()
                    .AllowCredentials();
            }));

完整的ConfigureServices方法示例如下:


        public IServiceProvider ConfigureServices(IServiceCollection services)
        {

            services.AddCors(options => options.AddPolicy("CorsPolicy",
                builder =>
                {
                    builder.AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowAnyOrigin()
                        .AllowCredentials();
                }));

            services.AddMvc(options => { options.Filters.Add(); })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                //全局配置Json序列化处理
                .AddJsonOptions(options =>
                {
                    options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                })
                .AddFluentValidation();

            services.AddSignalR();

            return services.AutofacServiceProvider();
        }

在Configure方法中添加

app.UseCors("CorsPolicy");

完整Configure方法示例:


        public void Configure(IApplicationBuilder app, IHostingEnvironment env,
                              ILoggerFactory loggerFactory,
                              IOptions config)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            if (env.IsProduction())
            {
                //注册服务到consul
                app.UseConsul();

                using (HttpClient client = new HttpClient())
                {
                    StringContent content = new StringContent(JsonConvert.SerializeObject(config.Value.RegisterParams));
                    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    HttpResponseMessage message = client.PostAsync(config.Value.Server.Address, content).Result;
                };
            }
            app.UseCors("CorsPolicy");
            loggerFactory.AddNLog();
            env.ConfigureNLog("nlog.config");//读取Nlog配置文件
            app.UseSignalR(routes =>
            {
                routes.MapHub("/api/v1/examinations/messageHub");
            });
            app.UseMvc();
        }
特别注意:app.UseCors()必须放在app.UseMvc()之前。

本以为这就算完了,但是万万没想到啊,依然没有什么用。浏览器控制台错误依然存在,.net core也提示了相关警告信息,差点就忘了现在使用.net core 版本和以前不一样了。

The CORS protocol does not allow specifying a wildcard (any) origin and credentials at the same time. Configure the policy by listing individual origins if credentials needs to be supported.

目前使用的是ASP.NET CORE 2.1, 其Cors组件已经升级,出于安全考虑必须明确要允许的内容。 这是安全的一部分,你不能这样做。 如果要允许凭据,则Access-Control-Allow-Origin不能使用*。 您必须指定确切的协议+域+端口。

这个问题其实也很好解决,只需要给予一个可信列表即可。修改内容如下:


        services.AddCors(options => options.AddPolicy("CorsPolicy",
            builder =>
            {
                builder.WithOrigins(new string[] { "http://127.0.0.1:5500" })
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials();
            }));

如果真的就不想做任何限制,其实也是有办法的。只需要将AllowAnyOrigin替换为SetIsOriginAllowed(_ => true)就可以解决。


       services.AddCors(options => options.AddPolicy("CorsPolicy",
            builder =>
            {
                builder.AllowAnyMethod()
                    .SetIsOriginAllowed(_ => true)
                    .AllowAnyHeader()
                    .AllowCredentials();
            }));

除了前面的两个方法以外,其实还可以自定义中间件。添加Cors处理类。如下:


    public class CorsMiddleware
    {
        private readonly RequestDelegate next;

        public CorsMiddleware(RequestDelegate next)
        {
            this.next = next;
        }
        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
            {
                context.Response.Headers.Add("Access-Control-Allow-Origin", context.Request.Headers["Origin"]);
                context.Response.Headers.Add("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH");
                context.Response.Headers.Add("Access-Control-Allow-Headers", context.Request.Headers["Access-Control-Request-Headers"]);
                context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");

                if (context.Request.Method.Equals("OPTIONS"))
                {
                    context.Response.StatusCode = StatusCodes.Status200OK;
                    return;
                }
            }

            await next(context);
        }
    }

Configure方法中添加如下内容即可。

app.UseMiddleware<CorsMiddleware>();

转载请注明:清风博客 » ASP.NET Core 配置跨域(CORS)

]]>
https://www.skyfinder.cc/2020/01/13/aspnetcorecors/feed/ 0
数据库管理工具Navicat Premium 15 https://www.skyfinder.cc/2020/01/12/database-navicat-premium15/ https://www.skyfinder.cc/2020/01/12/database-navicat-premium15/#comments Sat, 11 Jan 2020 17:00:00 +0000 https://www.skyfinder.cc/?p=2293 Navicat premium 是一款数据库管理工具。将此工具连接数据库,你可以从中看到各种数据库的详细信息。包括报错,等等。当然,你也可以通过他,登陆数据库,进行各种操作。Navicat Premium是一个可多重连线资料库的管理工具,它可以让你以单一程序同时连线到 MySQL、SQLite、Oracle 及 PostgreSQL 资料库,让管理不同类型的数据库管理更加方便。

Navicat Premium结合了其他Navicat成员的功能。有了这种集成链接到不同数据库能力,Navicat Premium支持在 MySQL、SQLite、Oracle 及 PostgreSQL 之间数据传输。它支持大部分的 MySQL、SQLite、Oracle 及 PostgreSQL 功能,包括存储过程、事件、触发器、函数等。

Navicat Premium下载

Navicat Premium 15官方下载Navicat Premium 15百度网盘:wpcp

Navicat Premium补丁下载

Navicat Premium 补丁Navicat-Keygen-Patch-v5.6.0-DFoX
为了防止搜索引擎扫描到补丁,压缩文件设置了解压密码:www.skyfinder.cc

使用方法

卸载掉早期版本,卸载干净,然后安装最新版navicat。
  • 安装Navicat Premium
  • 将补丁复制到安装目录下并运行补丁点击patch
  • 运行navicat并弹出注册界面
  • 如果没有弹出注册界面手动在菜单打开:帮助->注册
  • 点击 补丁程序的generate按钮同时注册码会自动写到navicat
  • 点击navicat注册界面的激活按钮,提示手动激活
  • 点击手动激活之后将得到的RequestCode复制到注册机
  • 点击补丁程序左下方的Generate按钮,生成ActivationCode
  • 复制粘贴到navicat的激活码框并完成激活

转载请注明:清风博客 » 数据库管理工具Navicat Premium 15

]]>
https://www.skyfinder.cc/2020/01/12/database-navicat-premium15/feed/ 9
Newtonsoft.Json序列化对象时循环引用异常处理 https://www.skyfinder.cc/2020/01/11/newtonsoftjsonreferenceloophandling/ https://www.skyfinder.cc/2020/01/11/newtonsoftjsonreferenceloophandling/#respond Sat, 11 Jan 2020 04:18:19 +0000 https://www.skyfinder.cc/?p=2256 因某些需求,需要将指定的对象序列化放到缓存中,在使用Newtonsoft.Json序列化时候报错,异常信息清晰明显就是循环引用问题。具体错误如下:

详细异常如下:

fail: System.Exception[-2146233088]
Self referencing loop detected for property ‘Ancestor’ with type ”. Path ‘Descendants[0]’. Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property ‘Ancestor’ with type ‘*’. Path ‘Descendants[0]’.
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value, Type type, JsonSerializer jsonSerializer)
at System.Threading.Tasks.ValueTask`1.get_Result()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()

解决方法

在序列化或者反序列化指定JsonSerializerSettings即可解决:

  var setting = new JsonSerializerSettings();
  setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
  var json = JsonConvert.SerializeObject(data, setting)

如果想要循环引用的数据得以保留,以便后面反序列化时能还原数据,所以将循环引用设置为序列化 ,如下方式:

var setting = new JsonSerializerSettings();
setting.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
setting.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
var json = JsonConvert.SerializeObject(data, setting);

转载请注明:清风博客 » Newtonsoft.Json序列化对象时循环引用异常处理

]]>
https://www.skyfinder.cc/2020/01/11/newtonsoftjsonreferenceloophandling/feed/ 0
Windows 7 SP1安装.net core2.1无法安装问题 https://www.skyfinder.cc/2020/01/04/windows7-sp1-install-netcore21-error/ https://www.skyfinder.cc/2020/01/04/windows7-sp1-install-netcore21-error/#respond Fri, 03 Jan 2020 17:06:14 +0000 https://www.skyfinder.cc/?p=2219 因某些情况需要在测试人员机器上安装.net core 2.1,系统为Windows 7 SP1。安装.net core2.1,出现 sfx x64.cab has an invalid digital signature错误,安装不成功。错误信息如下:

A file that is required cannot be installed becquse the cabinet file
C:\ProgramData\Package Cache\{3551F085-7544-3527-84BA-9706CB1379A1}v2.1.14.0\sfx x64.cab
has an invalid digital signature. This may indicate that the cabinet file is
corrupt.

根据错误信息得知应该是证书相关问题,也没有详细探查原因。有可能安装程序访问微软相关证书出了问题,又或者网络链接不通的问题吧。不管如何,装个证书吧!

下载证书文件

MicrosoftRootCertificateAuthority2011

证书安装

  • 开始→运行→MMC
  • 文件→添加删除管理单元 (Ctrl+M)
  • 证书→计算机账户(其他的都保持默认,其他下一步)
  • 展开证书→受信任的根证书颁发机构→证书
  • 右击展开菜单,所有任务→导入
  • 选择下载好的cer证书文件,然后一直下一步就好了

完成以上操作后重新安装,net core2.1顺利安装成功。

转载请注明:清风博客 » Windows 7 SP1安装.net core2.1无法安装问题

]]>
https://www.skyfinder.cc/2020/01/04/windows7-sp1-install-netcore21-error/feed/ 0
docker环境下使用EPPlus 导出Excel报错问题 https://www.skyfinder.cc/2019/12/31/dockerepplusexportexceleror/ https://www.skyfinder.cc/2019/12/31/dockerepplusexportexceleror/#respond Tue, 31 Dec 2019 02:32:29 +0000 https://www.skyfinder.cc/?p=2133 网站内容在Windows环境下并没有出现任何问题,但是在Linux 系统Centos的Docker环境下就出现了相关错误。这让人一脸蒙逼啊, 未能加载libdl库。使用了EPPlus处理Excel,其内部设置了字体大小以及颜色之类的东西,使用了‘ System.Drawing.Font ’的相关内容。由于Linux系统中Docker环境下缺少相关库,故而出现异常。具体错误请看以下内容。

报错内容:

fail: System.Exception[-2146233036]
The type initializer for ‘Gdip’ threw an exception.
System.TypeInitializationException: The type initializer for ‘Gdip’ threw an exception. —> System.DllNotFoundException: Unable to load shared library ‘libdl’ or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: liblibdl: cannot open shared object file: No such file or directory
at Interop.Libdl.dlopen(String fileName, Int32 flag)
at System.Drawing.SafeNativeMethods.Gdip.LoadNativeLibrary()
at System.Drawing.SafeNativeMethods.Gdip..cctor()
— End of inner exception stack trace —
at System.Drawing.SafeNativeMethods.Gdip.GdipGetGenericFontFamilySansSerif(IntPtr& fontfamily)
at System.Drawing.FontFamily.GetGdipGenericSansSerif()
at System.Drawing.FontFamily.get_GenericSansSerif()
at System.Drawing.Font.CreateFont(String familyName, Single emSize, FontStyle style, GraphicsUnit unit, Byte charSet, Boolean isVertical)
at OfficeOpenXml.ExcelRangeBase.AutoFitColumns(Double MinimumWidth, Double MaximumWidth)
at ExcelCake.Intrusive.ExportExtension.FillExcelWorksheet[T](ExcelWorksheet sheet, IEnumerable1 list, ExportExcelSetting exportSetting) at ExcelCake.Intrusive.ExportExtension.ExportMultiToBytes(IDictionary2 dic)
at ExcelCake.Intrusive.ExportExtension.ExportToExcelBytes[T](IEnumerable`1 list, String sheetName)
at PhoenixQuestion.Controllers.QuestionController.ExportQuestions() in /src/services/PhoenixQuestion/Controllers/QuestionController.cs:line 166
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()

其实,解决办法也非常简单,只需要在Dockerfile中执行相关安装相关库的命令即可,当然在安装前要更新源。在Dockerfile中新增如下内容:

RUN echo "deb http://mirrors.aliyun.com/debian/ stretch main non-free contrib" > /etc/apt/sources.list
RUN echo "deb-src http://mirrors.aliyun.com/debian/ stretch main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian-security stretch/updates main" >> /etc/apt/sources.list
RUN echo "deb-src http://mirrors.aliyun.com/debian-security stretch/updates main" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb-src http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb-src http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib" >> /etc/apt/sources.list

RUN apt-get clean

RUN apt-get update \
    && apt-get install -y --allow-unauthenticated \
       libc6-dev \
       libgdiplus \
       libx11-dev \
    && rm -rf /var/lib/apt/lists/*

新增相关安装库的命令后完整的Dockerfile内容如下:

FROM microsoft/dotnet:2.1-sdk AS build
COPY ./common/PhoenixCommon /src/common/PhoenixCommon
COPY ./services/PhoenixQuestion /src/services/PhoenixQuestion
WORKDIR /src/services/PhoenixQuestion
RUN dotnet restore PhoenixQuestion.csproj --configfile "nuget.config"
RUN dotnet build PhoenixQuestion.csproj -c Release -o /app

FROM build AS publish
RUN dotnet publish PhoenixQuestion.csproj -c Release -o /app

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80

FROM base AS final
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app
COPY --from=publish /app .

RUN echo "deb http://mirrors.aliyun.com/debian/ stretch main non-free contrib" > /etc/apt/sources.list
RUN echo "deb-src http://mirrors.aliyun.com/debian/ stretch main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian-security stretch/updates main" >> /etc/apt/sources.list
RUN echo "deb-src http://mirrors.aliyun.com/debian-security stretch/updates main" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb-src http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib" >> /etc/apt/sources.list
RUN echo "deb-src http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib" >> /etc/apt/sources.list

RUN apt-get clean

RUN apt-get update \
    && apt-get install -y --allow-unauthenticated \
       libc6-dev \
       libgdiplus \
       libx11-dev \
    && rm -rf /var/lib/apt/lists/*


ENTRYPOINT ["dotnet", "PhoenixQuestion.dll"]

重新更新后,报错问题解决。当然也看了其他的相关解决方案,但是很遗憾没有解决问题。如下:

https://github.com/VahidN/EPPlus.Core/issues/40

https://q.cnblogs.com/q/109061/

https://www.cnblogs.com/sunnytrudeau/p/9384620.html

转载请注明:清风博客 » docker环境下使用EPPlus 导出Excel报错问题

]]>
https://www.skyfinder.cc/2019/12/31/dockerepplusexportexceleror/feed/ 0
使用Windows API向指定窗口发送模拟键盘消息 https://www.skyfinder.cc/2019/12/30/windows-api-keybord-event/ https://www.skyfinder.cc/2019/12/30/windows-api-keybord-event/#respond Sun, 29 Dec 2019 16:55:53 +0000 https://www.skyfinder.cc/?p=2182 上周五在QQ群遇到群友提问的一个问题。问题是这样的:文字识别之后,当点击Excel单元格识别内容自动出现当前单元格中。我提供相关实现思路,使用相关Windows API来实现操作,其中基本思路就是:获取当前鼠标位置=>获取当前位置窗口句柄=>获得当前句柄类=>模拟键盘消息。但遗憾的是他一直没有搞定还一直问,无奈我就直接给他了简单的示例代码。其中使用的Windows API 接口为以下几个:

GetCursorPos

WindowFromPoint

GetClassName

keybd_event


using MouseKeyboardActivityMonitor;
using MouseKeyboardActivityMonitor.WinApi;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WinApi;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {

        MouseHookListener mh;
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            //安装鼠标钩子
            mh = new MouseHookListener(new GlobalHooker());
            mh.Enabled = true;
            mh.MouseDoubleClick += mh_MouseMoveEvent;
            this.textBox1.Text = "Windows API实现键盘粘贴事件";
        }

        void mh_MouseMoveEvent(object sender, MouseEventArgs e)
        {
            try
            {
                Point p = new Point();
                WindowsAPI.GetCursorPos(ref p);
                IntPtr houseWindow = WindowsAPI.WindowFromPoint(p);
                if (houseWindow == IntPtr.Zero)
                {
                    return;
                }
                StringBuilder sb = new StringBuilder();
                WindowsAPI.GetClassName(houseWindow, sb, 255);
                if (sb.Length == 0)
                {
                    return;
                }
                if (!sb.ToString().ToLower().Contains("excel"))
                {
                    return;
                }
                Clipboard.SetText(string.IsNullOrWhiteSpace(this.textBox1.Text)?"Windows Api": this.textBox1.Text);
                System.Threading.Thread.Sleep(100);
                WindowsAPI.keybd_event((byte)Keys.ControlKey, 0, 0, 0);//按下
                WindowsAPI.keybd_event((byte)Keys.V, 0, 0, 0);
                WindowsAPI.keybd_event((byte)Keys.ControlKey, 0, 0x2, 0);//松开
                WindowsAPI.keybd_event((byte)Keys.V, 0, 0x2, 0);

            }
            catch (Exception ex)
            {
                this.textBox1.Text = ex.Message;
                GC.Collect();
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            mh.Enabled = false;
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }
    }
}


示例下载

示例下载

转载请注明:清风博客 » 使用Windows API向指定窗口发送模拟键盘消息

]]>
https://www.skyfinder.cc/2019/12/30/windows-api-keybord-event/feed/ 0
Visual Studio (VS)2017/2019安装Spy++工具 https://www.skyfinder.cc/2019/12/29/visual-studio-2017-2019-spy-plus-plus/ https://www.skyfinder.cc/2019/12/29/visual-studio-2017-2019-spy-plus-plus/#respond Sun, 29 Dec 2019 02:31:25 +0000 https://www.skyfinder.cc/?p=2168 最近因为某些原因需要用到spy++工具, 在Visual Studio中找不到Spy++工具,在系统中也没有找到。经过了解需要重新下载Spy++工具.在Visual Studio通过以下进行安装。

工具=>获取工具和功能=》单个组件=》Visual Studio C++核心功能

然后,勾选《 Visual Studio C++核心功能 》后修改完成,工具Spy++就此安装完成。如下图:

转载请注明:清风博客 » Visual Studio (VS)2017/2019安装Spy++工具

]]>
https://www.skyfinder.cc/2019/12/29/visual-studio-2017-2019-spy-plus-plus/feed/ 0
关于2019年春节买票的一些建议 https://www.skyfinder.cc/2019/12/23/about2019buyticketspropose/ https://www.skyfinder.cc/2019/12/23/about2019buyticketspropose/#respond Mon, 23 Dec 2019 04:00:00 +0000 https://www.skyfinder.cc/?p=2146

关于网上买火车票已经有很多年了,我个人是2012年开始互联网抢票的,那个时候都是八仙过海,各显神通啊。有一个抢票软件,那就是无往不利。鄙人也得到一款抢票利器,每年回家买票都未曾失望,无论是自己有或者为亲朋好友代买都未曾落空。但本人在买票这方面从来没有使用任何手段进行谋利。我使用的抢票软件名称是《12306订票助手.net》,是网名为鱼的大神之作,此人曾在猎豹负责浏览器抢票插件事宜。我个人2012年到2018年均是使用他的软件,其他乱七八糟的抢票软件从来没有用过。2019年这位大神也很忙,更没有太多时间用到软件更新上了,至于以后是否更新就不太清楚了。

12306在2018年上线了候补票的功能,这一年还只是部分线路可以使用,应该是为了测试吧,这个时候抢票软件刷票捡漏还是有用武之地的。2019年这个候补票的功能已经全线路都可以使用,这个功能全线路使用后各个抢票软件刷票捡漏基本无望,而能够快人一步的就是提交候补订单的速度和支付后补订单的速度了,不过大部分的抢票软件还没有及时的做到这一步。更重要是12306在高峰期加入的拖动验证码,属于阿里云的人机校验风控系统,不要对此类拖动验证码的自动破解抱有多大期望,当然不是不可能破解,就看哪些大神去研究吧。今年或者以后就是抢预售票以及后补票了吧!

所以就2019年买火车票给出以下建议:

  • 预售期的票(指买的**点起售这样的票),务必用官方手机APP+官网购买,因为今年12306经常会在高峰期改系统(变动的非常频繁),依赖第三方软件可能会给你带来无法预测的风险 。
  • 尽量多备方案(飞机、汽车、火车等),能跨站的尽量跨站(比如出发或到达是过路站),限售可能比你想得要严重!尤其是如果你从头到尾连有票的字样都没看到,那就果断跨站!这个是限售!!!不是卖光了!!
  • 预售没买到的,切记立刻提交候补!等到候补都补不上就来不及了!!提交后补订单不耽误继续刷票,不过如果不是预售,捡漏刷票也刷不到。因为保留放票以及其他退票都会优先12306官方候补功能。

我个人今年买的到的所有票(包括代买的)都是使用提交候补订单这种方式,以最快的方式提交候补订单,以最快的方式付款,剩下的就是等待。一般一到两天都会买到票。在2019年之前就需要一直守在电脑旁,那可是真累啊,碰到周末一天都出不去 。今年到好了很多,提交了后补订单,剩下该干嘛干嘛!!无论是往年还是今年,买票我也是尽心尽力啦,不管是自己买又或者帮亲朋好友代买。12306每年都会有很多意想不到的变更,至于将来如何,未来再看吧!!!

转载请注明:清风博客 » 关于2019年春节买票的一些建议

]]>
https://www.skyfinder.cc/2019/12/23/about2019buyticketspropose/feed/ 0
菊花 https://www.skyfinder.cc/2019/12/20/chrysanthemums/ https://www.skyfinder.cc/2019/12/20/chrysanthemums/#respond Fri, 20 Dec 2019 01:00:00 +0000 https://www.skyfinder.cc/?p=2089 菊花(学名:Dendranthema morifolium(Ramat. )Tzvel.):在植物分类学中是菊科、菊属的多年生宿根草本植物。按栽培形式分为多头菊、独本菊、大丽菊、悬崖菊、艺菊、案头菊等栽培类型;有按花瓣的外观形态分为园抱、退抱、反抱、乱抱、露心抱、飞午抱等栽培类型。不同类型里的菊花又命名各种各样的品种名称。

菊花是中国十大名花之三,花中四君子(梅兰竹菊)之一,也是世界四大切花(菊花、月季、康乃馨、唐菖蒲)之一,产量居首。因菊花具有清寒傲雪的品格,才有陶渊明的“采菊东篱下,悠然见南山”的名句。中国人有重阳节赏菊和饮菊花酒的习俗。唐·孟浩然《过故人庄》:“待到重阳日,还来就菊花。”在古神话传说中菊花还被赋予了吉祥、长寿的含义。

菊花是经长期人工选择培育的名贵观赏花卉,公元八世纪前后,作为观赏的菊花由中国传至日本。17世纪末叶荷兰商人将中国菊花引入欧洲,18世纪传入法国,19世纪中期引入北美。此后中国菊花遍及全球。

菊花是非常常见的一种花了,不但有观赏价值,有些品种具备药用价值。在十一月的某一天看到朋友圈的动态,描述关于菊花展的相关信息以及菊花等配图,所以再看到相关信息的第二天就去了菊花展的公园,看到相关品种菊花忍不住使用手机拍几张照片留念。在游览菊花展期间看到了一个小动物,一个蜥蜴(树蜥)。第一次见到实物!!!下面一些关于在菊花展拍摄的几张照片:

转载请注明:清风博客 » 菊花

]]>
https://www.skyfinder.cc/2019/12/20/chrysanthemums/feed/ 0
使用Quartz.NET实现定时(计划)任务 https://www.skyfinder.cc/2019/12/16/quartz-net-execute-task/ https://www.skyfinder.cc/2019/12/16/quartz-net-execute-task/#respond Mon, 16 Dec 2019 01:03:00 +0000 https://www.skyfinder.cc/?p=2006 Quartz.NET

Quartz.NET是一个强大、开源、轻量的作业调度框架,是 OpenSymphony 的 Quartz API 的.NET移植,用C#改写,可用于winform和asp.net应用中。它灵活而不复杂。你能够用它来为执行一个作业而创建简单的或复杂的作业调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等。

官网:http://www.quartz-scheduler.net/

源码:https://github.com/quartznet/quartznet

示例:http://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html

其实Quartz是一个完全由java编写的开源作业调度框架,Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。而Quartz.Net与NPOI一样是一个DoNet平台下的对应版本。如果您使用Java直接访问这里就好了http://www.quartz-scheduler.org/

搭建Quartz定时任务

安装

新建一个Quartz.NET.Apply项目, 使用Quartz.net之前,我们需要引入Nuget包,在Nuget包管理器中搜索Quartz,点击就可以安装了,当然也可以在包控制台里输入:

Install-Package Quartz

Quartz.NET现在已经支持.NET CORE项目。

实现IJob


    public class ConsoleWriteJobShowDatetime : IJob
    {
        public Task Execute(IJobExecutionContext context)
        {
            Console.WriteLine($"任务执行时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
            return Task.CompletedTask;
        }
    }

Execute就是我们要执行任务入口,此方法会根据相关配置执行一次或者多次。

任务触发器


    public class QuartzRunJob
    {
        public static async Task RunJob()
        {
            ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
            IScheduler scheduler = await schedulerFactory.GetScheduler();

            DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now, 1);

            IJobDetail job = JobBuilder.Create()
                             .WithIdentity("ConsoleWriteJobShowDatetime","job")
                             .Build();

            ITrigger trigger = TriggerBuilder.Create()
                                       .StartAt(startTime)
                                       .WithIdentity("ConsoleWriteJobShowDatetime", "job")
                                       .WithSimpleSchedule(x=>x.WithIntervalInSeconds(1).RepeatForever())
                                       .Build();

            await scheduler.ScheduleJob(job, trigger);
            await scheduler.Start();
        }
    }

运行


 using Quartz.Impl;
using System;
using System.Threading.Tasks;

namespace Quartz.NET.Apply
{
    class Program
    {
        static void Main(string[] args)
        {
            Task job= QuartzRunJob.RunJob();
            job.Wait();
            Console.Read();
        }
    }
}


我们可以封装一个通用的方法,实现Ijob后就可以直接调用公共方法,使简单的定时任务更加方面快捷。内容如下:


           public static async Task StartAsync(TimeSpan ts, string jobName, string triggerName, string groupName) where T : IJob
        {
            DateTimeOffset runTime = DateBuilder.EvenSecondDate(DateTime.Now);
            IJobDetail job = JobBuilder.Create().WithIdentity(jobName, groupName).Build();
            ITrigger trigger = TriggerBuilder.Create().WithIdentity(triggerName, groupName).StartAt(runTime).WithSimpleSchedule(x => x.WithInterval(ts).RepeatForever()).Build();

            ISchedulerFactory factory = new StdSchedulerFactory();
            IScheduler scheduler = await factory.GetScheduler();
            await scheduler.ScheduleJob(job, trigger);
            await scheduler.Start();
        }

        public static async Task StartAsync(string cronExp, string jobName, string triggerName, string groupName) where T : IJob
        {
            DateTimeOffset runTime = DateBuilder.EvenSecondDate(DateTime.Now);
            IJobDetail job = JobBuilder.Create().WithIdentity(jobName, groupName).Build();
            ITrigger trigger = TriggerBuilder.Create().WithIdentity(triggerName, groupName).WithCronSchedule(cronExp).StartAt(runTime).Build();

            ISchedulerFactory factory = new StdSchedulerFactory();
            IScheduler scheduler = await factory.GetScheduler();
            await scheduler.ScheduleJob(job, trigger);
            await scheduler.Start();
        }
    }

简单调用如下:


using Quartz.Impl;
using System;
using System.Threading.Tasks;

namespace Quartz.NET.Apply
{
    class Program
    {
        static void Main(string[] args)
        {
            Task job= QuartzRunJob.RunJob();
            Task job1=QuartzHelpers.StartAsync(new TimeSpan(0,0,1),"job1", "triggerName1", "groupName");
            Task job2 = QuartzHelpers.StartAsync("0/1 * * * * ? ", "job2", "triggerName2", "groupName1");
            Console.Read();
        }
    }
}

以上代码出现的“0/1 * * * * ?”为Cron表达式。

Cron表达式

关于Quart.net说是用的Cron表达式的说明,请参考这篇内容:Quartz.net的Cron表达式

下载

示例下载

转载请注明:清风博客 » 使用Quartz.NET实现定时(计划)任务

]]>
https://www.skyfinder.cc/2019/12/16/quartz-net-execute-task/feed/ 0
杜鹃花 https://www.skyfinder.cc/2019/12/15/%e6%9d%9c%e9%b9%83%e8%8a%b1/ https://www.skyfinder.cc/2019/12/15/%e6%9d%9c%e9%b9%83%e8%8a%b1/#respond Sun, 15 Dec 2019 05:34:23 +0000 https://www.skyfinder.cc/?p=2054 杜鹃(学名:Rhododendron simsii Planch.):又名映山红、山石榴,为常绿或平常绿灌木。相传,古有杜鹃鸟,日夜哀鸣而咯血,染红遍山的花朵,因而得名。杜鹃花一般春季开花,每簇花2-6朵,花冠漏斗形,有红、淡红、杏红、雪青、白色等,花色繁茂艳丽。生于海拔500-1200(-2500)米的山地疏灌丛或松林下,为中国中南及西南典型的酸性土指示植物。

该物种全株供药用:有行气活血、补虚,治疗内伤咳嗽,肾虚耳聋,月经不调,风湿等疾病。又因花冠鲜红色,为著名的花卉植物,具有较高的观赏价值,在世界各公园中均有栽培。中国江西、安徽、贵州以杜鹃花为省花,定为市花的城市多达七八个。1985年5月杜鹃花被评为中国十大名花之六。

杜鹃花也是杜鹃属(Rhododendron)约960种植物的通称。以上内容来自百度百科

其实关于杜鹃花我知道并不多,我虽然知道有这种花,但是它什么样子却不曾知晓。如果想了解更多关于杜鹃花的话,可以使用百度找到更多的信息。

前几月某一天遇到了一年一度的杜鹃花展,索性就去看了一下。没想到杜鹃花展至今在这个城市已经举办了10多届了,至今才才去转转。说实在的,杜鹃花真的很漂亮,看到各个品种才发现以前也曾见过某些品种,但未曾知其名而已。虽然自己对摄影并无涉猎,但用手机拍几张简单照片还是可以的。于是便有了这篇内容,以作记录之用。下面就是花展拍到的几张花的照片:

转载请注明:清风博客 » 杜鹃花

]]>
https://www.skyfinder.cc/2019/12/15/%e6%9d%9c%e9%b9%83%e8%8a%b1/feed/ 0
Topshelf构建Windows服务框架 https://www.skyfinder.cc/2019/12/14/topshelf-windows-service/ https://www.skyfinder.cc/2019/12/14/topshelf-windows-service/#respond Sat, 14 Dec 2019 05:36:04 +0000 https://www.skyfinder.cc/?p=2012

Topshelf 

Topshelf是一个使用.NET 构建 Windows 服务的简单服务托管框架 。简化了服务的创建,允许开发人员创建一个简单的控制台应用程序,该应用程序可以使用 Topshelf 作为服务安装。原因很简单:调试控制台应用程序比调试服务容易得多。一旦应用程序经过测试并准备好生产,Topshelf 可以轻松地将应用程序安装为服务。

项目地址

GIT托管Topshelf源码Topshelf官方项目

转载请注明:清风博客 » Topshelf构建Windows服务框架

]]>
https://www.skyfinder.cc/2019/12/14/topshelf-windows-service/feed/ 0
.net core 使用 IHostedService 实现定时执行的任务 https://www.skyfinder.cc/2019/12/07/net-core-ihostedservice-task/ https://www.skyfinder.cc/2019/12/07/net-core-ihostedservice-task/#respond Sat, 07 Dec 2019 00:00:00 +0000 https://www.skyfinder.cc/?p=1968 背景后台任务和计划任务最终可能需要在基于微服务的应用程序或任何类型的应用程序中实现。 使用微服务体系结构的区别在于,可以实现一个微服务进程/容器来托管这些后台任务,以便根据需要对其进行减少/增加,或者甚至可以确保它运行该微服务进程/容器的单个实例。

一般在 .NET Core 中,我们将这些类型的任务称为托管服务 ,因为它们是托管在主机/应用程序/微服务中的服务/逻辑。 请注意,在这种情况下,托管服务仅表示具有后台任务逻辑的类。

前言

从 .net core 2.0 开始,开始引入 IHostedService,可以通过 IHostedService 来实现后台任务,但是只能在 WebHost 的基础上使用。从 .net core 2.1 开始微软引入通用主机(Generic Host),使得我们可以在不使用 Web 的情况下,也可以使用 IHostedService 来实现 定时任务/Windows服务/后台任务,并且引入了一个 BackgroundService 抽象类来更方便的创建后台任务。 基本理念是,可以注册多个后台任务(托管服务),在 Web 主机或主机运行时在后台运行,如下图所示:

ASP.NET Core 2.0 中的 WebHost(实现 IWebHost 的基类)是用于为进程提供 HTTP 服务器功能的基础结构项目,例如,如果正在实现 MVC Web 应用或 Web API 服务。 它提供 ASP.NET Core 中所有新的基础结构优点,使用户能够使用依赖关系注入,在请求管道中插入中间件等,并精确地将这些 IHostedServices 用于后台任务。

.NET Core 2.1 中引入了 Host(实现 IHost 的基类)。 基本上,Host 能让用户拥有与 WebHost(依赖项注入、托管服务等)相似的基础结构,但在这种情况下,只需拥有一个简单轻便的进程作为主机,与 MVC、Web API 或 HTTP 服务器功能无关。

因此,可以选择一个专用主机进程,也可使用 IHost 创建一个来专门处理托管服务,例如仅用于托管 IHostedServices 的微服务,或者可以选择性地扩展现有的 ASP.NET Core WebHost,例如现有的 ASP.NET Core Web API 或 MVC 应用。
每种方法都有优缺点,具体取决于业务和可伸缩性需求。 重要的是,如果后台任务与 HTTP (IWebHost) 无关,则应使用 IHost。

IHostedService 接口

IHostedService 后台任务的执行与应用程序(就此而言,为主机或微服务)的生存期相协调。 当应用程序启动时注册任务,当应用程序关闭时,有机会执行某些正常操作或清理。

始终可以启动后台线程来运行任何任务,而无需使用 IHostedService。 不同之处就在于应用的关闭时间,此时会直接终止线程,而没有机会执行正常的清理操作。

当注册 IHostedService 时,.NET Core 会在应用程序启动和停止期间分别调用 IHostedService 类型的 StartAsync() 和 StopAsync() 方法。 具体而言,即在服务器已启动并已触发 IApplicationLifetime.ApplicationStarted 后调用 start。

在 .NET Core 中定义的 IHostedService 如下所示。


namespace Microsoft.Extensions.Hosting
{
    //
    // 摘要:
    //     Defines methods for objects that are managed by the host.
    public interface IHostedService
    {
        //
        // 摘要:
        //     Triggered when the application host is ready to start the service.
        //
        // 参数:
        //   cancellationToken:
        //     Indicates that the start process has been aborted.
        Task StartAsync(CancellationToken cancellationToken);
        //
        // 摘要:
        //     Triggered when the application host is performing a graceful shutdown.
        //
        // 参数:
        //   cancellationToken:
        //     Indicates that the shutdown process should no longer be graceful.
        Task StopAsync(CancellationToken cancellationToken);
    }
}

如你所想,可以创建 IHostedService 的多个实现,并在 ConfigureService() 方法中将它们注册到 DI 容器中,如前所示。 所有这些托管服务将随应用程序/微服务一起启动和停止。

当主机触发 StopAsync() 方法时,需负责处理服务的停止操作。

使用从 BackgroundService 基类派生的自定义托管服务类来实现 IHostedService

可以从头开始创建自定义托管服务类并实现 IHostedService,因为在使用 .NET Core 2.0 时需执行这些操作。

但是,由于大多数后台任务在取消令牌管理和其他典型操作方面都有类似的需求,因此有一个非常方便且可以从中进行派生的抽象基类,名为 BackgroundService(自 .NET Core 2.1 起提供)。

该类提供设置后台任务所需的主要工作。

下一个代码是在 .NET Core 中实现的抽象 BackgroundService 基类。


// Copyright (c) .NET Foundation. Licensed under the Apache License, Version 2.0.
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
    private Task _executingTask;
    private readonly CancellationTokenSource _stoppingCts =
                                                   new CancellationTokenSource();

    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
        // Store the task we're executing
        _executingTask = ExecuteAsync(_stoppingCts.Token);

        // If the task is completed then return it,
        // this will bubble cancellation and failure to the caller
        if (_executingTask.IsCompleted)
        {
            return _executingTask;
        }

        // Otherwise it's running
        return Task.CompletedTask;
    }

    public virtual async Task StopAsync(CancellationToken cancellationToken)
    {
        // Stop called without start
        if (_executingTask == null)
        {
            return;
        }

        try
        {
            // Signal cancellation to the executing method
            _stoppingCts.Cancel();
        }
        finally
        {
            // Wait until the task completes or the stop token triggers
            await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
                                                          cancellationToken));
        }

    }

    public virtual void Dispose()
    {
        _stoppingCts.Cancel();
    }
}

从上一抽象基类派生时,得益于该继承的实现,用户只需在自定义的托管服务类中实现 ExecuteAsync() 方法 ,使用以上作为基类实现简单定时任务:


class TimedBackgroundService : BackgroundService
    {
        private Timer _timer;
        private int i = 0;

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));           //每5秒开启一个线程
            return Task.CompletedTask;
        }

        private void DoWork(object state)
        {
            i++;
            int name = i;       //i表示这是第几个线程

            for (int j = 0; j < 100; j++)
            {
                Console.WriteLine($"这里是线程{name}:  正在执行j = {j}");
                Task.Delay(TimeSpan.FromSeconds(1)).Wait();        //等待1秒
            }
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            return ExecuteAsync(cancellationToken);
        }

        public override void Dispose()
        {
            base.Dispose();
            _timer?.Dispose();
        }
    }

向 WebHost 或 Host 添加一个或多个 IHostedServices 的方式是,通过 ASP.NET Core WebHost(或 .NET Core 2.1 及更高版本中的 Host)中的 AddHostedService  扩展方法对它们进行注册。 基本上,必须在常见的 Startup 类的 ConfigureServices() 方法中注册托管服务,如以下典型的 ASP.NET WebHost 中的代码所示。


public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddHostedService<TimedBackgroundService>();
}

上图显示多个与 IHostedService 相关的类和接口的类图 。

类图: IWebHost 和 IHost 可以托管许多服务,这些服务从实现 IHostedService 的 BackgroundService 继承。

IHostedService实现一个的后台定时任务

根据所了解的信息,可以基于 IHostedService 实现一个简单的后台定时任务服务

public abstract class ScheduedService : IHostedService, IDisposable
    {
        protected readonly Timer _timer;
        private readonly TimeSpan _period;
        protected readonly ILogger logger;
        protected bool IsDisallowConcurrentExecution = false;

        protected ScheduedService(TimeSpan period)
        {
             logger = LogManager.GetCurrentClassLogger();
            _period = period;
            _timer = new Timer(Execute, null, Timeout.Infinite, 0);
        }

        public void Execute(object state = null)
        {
            if (IsDisallowConcurrentExecution)
            {
               _timer?.Change(Timeout.Infinite, 0);
            }
            try
            {
                ExecuteAsync().Wait();
            }
            catch (Exception ex)
            {
                logger.Error(ex, $"Execute exception:{ex}");
            }
            if (IsDisallowConcurrentExecution)
            {
                _timer?.Change(_period _period);
            }
        }

        protected abstract Task ExecuteAsync();

        public virtual void Dispose()
        {
            _timer?.Dispose();
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            logger.Info("Schedued Service is starting.");
            _timer?.Change(TimeSpan.FromSeconds(RandomHelper.Next(10)), _period);
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            logger.Info("Schedued Service is stopping.");

            _timer?.Change(Timeout.Infinite, 0);

            return Task.CompletedTask;
        }
    }

根据上面抽象类使用Timer实现的后台定时任务类实现一个定时任务:


    public class ProcessExamsDataService : ScheduedService
    {
       
        public ProcessExamsDataService() : base(TimeSpan.FromSeconds(4))
        {
         
            IsDisallowConcurrentExecution = true;
     
        }

        protected override Task ExecuteAsync()
        {
            
            string guid = Guid.NewGuid().ToString("N");
            Console.WriteLine($"定时任务{guid}执行开始:{DateTime.Now.ToLongDateString()} {DateTime.Now.ToLongTimeString()}");
            System.Threading.Thread.Sleep(1000*20);
            Console.WriteLine($"定时任务{guid}执行结束:{DateTime.Now.ToLongDateString()} {DateTime.Now.ToLongTimeString()}");
   
            return Task.FromResult(true);
        }
    }

在程序启动的时候注册服务:

services.AddHostedService<ProcessExamsDataService>();

部署注意事项和要点

请务必注意,部署 ASP.NET Core WebHost 或 .NET Core Host 的方式可能会影响最终解决方案。 例如,如果在 IIS 或常规 Azure 应用服务上部署 WebHost,由于应用池回收,主机可能会被关闭。 但是,如果将主机作为容器部署到 Kubernetes 或 Service Fabric 等业务流程协调程序中,则可以控制主机的实时实例数量。 此外,还可以考虑云中专门针对这些方案的其他方法,例如 Azure Functions。 最后,如果需要服务一直处于运行状态并在 Windows Server 上部署,可以使用 Windows 服务。

但即使对于部署到应用池中的 WebHost,也存在如重新填充或刷新应用程序的内存中缓存这样的情况,这仍然适用。

IHostedService 接口为在 ASP.NET Core Web 应用程序(在 .NET Core 2.0 中)或任何进程/主机(从使用 IHost 的 .NET Core 2.1 开始)中启动后台任务提供了一种便捷方式。 其主要优势在于,当主机本身将要关闭时,可以有机会进行正常取消以清理后台任务的代码。

转载请注明:清风博客 » .net core 使用 IHostedService 实现定时执行的任务

]]>
https://www.skyfinder.cc/2019/12/07/net-core-ihostedservice-task/feed/ 0
WordPresss升级php环境后博客主题Yusi1.0的问题修改 https://www.skyfinder.cc/2019/12/05/wordpresssyusi10error/ https://www.skyfinder.cc/2019/12/05/wordpresssyusi10error/#respond Thu, 05 Dec 2019 02:46:14 +0000 https://www.skyfinder.cc/?p=1961 本博客使用的主题是《 欲思主题 》,个人觉得还是非常不错的。自从按照WordPress官方推荐升级了PHP7.0以后就出现无法使用问题。

页面显示不正常

在主题文件header.php中第43行ereg_replace()函数在php7中不再受支持了,已在PHP5中被弃用了,应该换用preg_replace()函数。然后在preg_replace()中加上分界符/,两边要加。示例如下:


preg_replace("/]*>]*>/", "", wp_nav_menu(array('theme_location' => 'nav', 'echo' => false)));

模板页不能显示的问题

模板页在 /wp-content/themes/yusi1.0/pages 目录下

解决方法:修改该目录下的每一个文件中的ereg_replace()函数,修改方法参照上面。

文章页头部/评论后不显示评论数与评论数量为零

解决方法

将single.php中以下方法: get_comments_number(‘去’,’1′,’%) 替换为: get_comments_number($post)

文章页最新评论的时间显示问题

时间显示问题是比正常时间加8小时, 这是一个时区设置问题 。

解决方法:修改./comments.php文件,把PRC改为CST。

转载请注明:清风博客 » WordPresss升级php环境后博客主题Yusi1.0的问题修改

]]>
https://www.skyfinder.cc/2019/12/05/wordpresssyusi10error/feed/ 0
全能终端软件MobaXterm v12.3 https://www.skyfinder.cc/2019/11/13/mobaxtermv123/ https://www.skyfinder.cc/2019/11/13/mobaxtermv123/#respond Wed, 13 Nov 2019 06:20:32 +0000 https://www.skyfinder.cc/?p=1950 MobaXterm提供了大量为程序员,网站管理员,IT管理员以及几乎所有需要以更简单的方式处理远程作业的用户量身打造的功能。它不仅支持各种连接和Linux命令,还可以像PuTTY一样通过SSH连接Raspberry Pi等开源硬件。

主要功能

  • 支持各种连接SSH,X11,RDP,VNC,FTP,MOSH
  • 支持Unix命令(bash,ls,cat,sed,grep,awk,rsync等)
  • 连接SSH终端后支持SFTP传输文件
  • 各种丰富的插件(git/dig/aria2等)
  • 可运行Windows或软件

下载

MobaXterm v12.3提取码:k8sq
仅供学习使用,商业用途请购买正版

转载请注明:清风博客 » 全能终端软件MobaXterm v12.3

]]>
https://www.skyfinder.cc/2019/11/13/mobaxtermv123/feed/ 0
Redis Desktop Manager https://www.skyfinder.cc/2019/11/06/redis-desktop-manager/ https://www.skyfinder.cc/2019/11/06/redis-desktop-manager/#respond Wed, 06 Nov 2019 04:35:17 +0000 https://www.skyfinder.cc/?p=1939 Redis Desktop Manager

Redis Desktop Manager(又名RDM)—是用于Windows,Linux和MacOS的快速开源Redis数据库管理应用程序。该工具为您提供了易于使用的GUI,以访问您的Redis数据库并执行一些基本操作:以树的形式查看密钥,CRUD密钥,通过Shell执行命令。RDM支持SSL / TLS加密,SSH隧道和云Redis实例,例如:Amazon ElastiCache,Microsoft Azure Redis Cache和Redis Labs。

Redis Desktop Manager 客户端在最初是免费的,可以自由使用。后来作者实施了收费策略,也就是说现在它不免费提供编译版本。但是它是开源的,作为开发者可以自行编译使用,当然大部分人懒得编译,我就是这样的。

redis desktop manager

官方下载

Redis Desktop ManageRedis Desktop Manage

使用官方下载可以使用付费版本以及自行通过github源码进行编译。

免付费/编译下载

Redis Desktop Manager提取码:x729

以上编译版本仅支持Windows平台。

如果资金宽裕,请尽量使用付费版本,以便支持软件更好的发展。

转载请注明:清风博客 » Redis Desktop Manager

]]>
https://www.skyfinder.cc/2019/11/06/redis-desktop-manager/feed/ 0