.Net Core 限制请求大小

方式1:
startup.cs

services.Configure<FormOptions>(options => {
        options.ValueLengthLimit = int.MaxValue;
        options.MultipartBodyLengthLimit = int.MaxValue;
        options.MultipartHeadersLengthLimit = int.MaxValue;
    });

方式2:
program.cs

    // debug时与IIS Express启动模式有冲突
    webBuilder.UseHttpSys(options =>
    {
        options.MaxRequestBodySize = long.MaxValue;
    });
    webBuilder.UseKestrel(options =>
    {
        options.Limits.MaxRequestBodySize = long.MaxValue;
    });

.Net Core Razor Pages 文件上传

表单方式提交单/多文件

public IActionResult OnPost(long id, string subject, List<IFormFile> files)
{
    foreach (var formFile in files)
    {
        if (formFile.Length > 0)
        {
            using (var stream = new FileStream(fileFullPath, FileMode.Create))
            {
                formFile.CopyTo(stream);
            }
        }
    }
}

二进制方式

using (FileStream fs = new FileStream(fileSavePath, FileMode.OpenOrCreate, FileAccess.Write))
{
     MemoryStream ms = new MemoryStream();
     Request.Body.CopyTo(ms);
     ms.Position = 0;
     byte[] buffer1 = new byte[ms.Length];
     ms.Read(buffer1, 0, buffer1.Length);
     ms.Dispose();
     fs.Write(buffer1, 0, buffer1.Length);
}

.Net Core Blazor Server 页面路由

startup.cs中做如下配置

services.AddMvc().AddRazorPagesOptions(options =>
{
      options.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
      options.Conventions.AddPageRoute("/login/login", "/api/login/{id?}");
      options.Conventions.AddPageRoute("/videosms/tpl/edit", "/videosms/tpl/edit/{id?}");
      options.Conventions.AddPageRoute("/videosms/tpl/view", "/videosms/tpl/view/{id?}");
      //options.Conventions.AddPageRoute("/videosms/tpl/add", "/videosms/tpl/add");
})

和默认路由相同的话不要添加, 否则有可能会导致路由匹配冲突.

xps13 9360 3K屏 黑苹果开机第二阶段logo变大修复

3K屏幕开启HiDPI后, 开机第二阶段logo会变得很大,仔细观察了下系统可用分辨率, 发现默认分辨率为1600×900, 应该和这个有关.

重新开启HiDPI
sh -c “$(curl -fsSL https://raw.githubusercontent.com/xzhih/one-key-hidpi/master/hidpi.sh)”
分辨率部分选择(6 自定义
分辨率填写如下: 2048×1152 1920×1080 1600×900 1440×810 1366×768
使默认分辨率为 1920×1080, 第一次重启依然会变大, 以后再开机和重启的时候就变得和第一阶段一样大了.

微信小程序轮播图

wxml:

<view class="swiper-container">
 <swiper autoplay="auto" interval="5000" duration="500" current="{{swiperCurrent}}" bindchange="swiperChange" class="swiper">
 <block wx:for="{{slider}}" wx:key="unique">
  <swiper-item>
  <image src="{{item.picUrl}}" class="img"></image>
  </swiper-item>
 </block>
 </swiper>
 
 <view class="dots">
 <block wx:for="{{slider}}" wx:key="unique">
  <view class="dot{{index == swiperCurrent ? ' active' : ''}}"></view>
 </block>
 </view>
</view>

wxss:

swiper-container{
 position: relative;
}
.swiper-container .swiper{
 height: 300rpx;
}
.swiper-container .swiper .img{
 width: 100%;
 height: 100%;
}
.swiper-container .dots{
 position: absolute;
 left: 0;
 right: 0;
 bottom: 20rpx;
 display: flex;
 justify-content: center;
}
.swiper-container .dots .dot{
 margin: 0 8rpx;
 width: 14rpx;
 height: 14rpx;
 background: #fff;
 border-radius: 8rpx;
 transition: all .6s;
}
.swiper-container .dots .dot.active{
 width: 24rpx;
 background: #f80;
}

js:

Page({
data: {
 slider: [
 {picUrl: '../../images/T003R720x288M000000rVobR3xG73f.jpg'},
 {picUrl: '../../images/T003R720x288M000000j6Tax0WLWhD.jpg'},
 {picUrl: '../../images/T003R720x288M000000a4LLK2VXxvj.jpg'},
 ],
 swiperCurrent: 0,
},
swiperChange: function(e){
 this.setData({
  swiperCurrent: e.detail.current
 })
}
})

c# .Net Core 判断字符串是否为英文(包括符号)

做短信网关程序, 有英文和非英文短信的计费问题. 需要根据短信内容类型来确定条数.
英文短信为140个字符为一条, 非英文内容的则为70个字符为一条.
该方法的原理是根据字符编码规范来检查是否是纯英文字符.
UTF8编码规范中, 中文为3或者4位, ASCII字符为1位, 只需要将内容转换为UTF8码后判断长度是否和原内容一致即可.

public static bool IsEn(string content){
    if(string.IsNullOrWhiteSpace(content))
    {
        return false;
    }
    var bytes = Encoding.UTF8.GetBytes(content);
    bool result = bytes.Length == content.Length;
    return result;
}

示例代码如下

using System;
using System.Diagnostics;
using System.Text;

namespace ConsoleDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] arr = new[] {"张三", "zhangsan", "张三aa", "zhangsan123.//*-" };
            for (int i = 0; i < arr.Length; i++)
            {
                Console.WriteLine($"'{arr[i]}' 为 {(IsEn(arr[i])? "英文" : "非英文")}");
            }

            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < 100000; i++)
            {
                IsEn("zhangsan11111");
            }
            sw.Stop();
            Console.WriteLine($"英文循环10万次用时{sw.ElapsedMilliseconds} 毫秒");

            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for (int i = 0; i < 100000; i++)
            {
                IsEn("张三zhangsan11111");
            }
            sw1.Stop();
            Console.WriteLine($"非英文循环10万次用时{sw1.ElapsedMilliseconds} 毫秒");
        }

        public static bool IsEn(string content)
        {
            if (string.IsNullOrWhiteSpace(content))
            {
                return false;
            }
            var bytes = Encoding.UTF8.GetBytes(content);
            bool result = bytes.Length == content.Length;
            return result;
        }
    }
}

执行结果

'张三' 为 非英文
'zhangsan' 为 英文
'张三aa' 为 非英文
'zhangsan123.//*-' 为 英文
英文循环10万次用时7 毫秒
非英文循环10万次用时7 毫秒

.Net Core 控制台程序读取appsettings.json

安装 nuget 包 Microsoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.FileExtensionsMicrosoft.Extensions.Configuration.Json
在main方法中执行如下代码

var conf = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", true, true)
.Build();
var value = conf.GetSection("key").Value;

为.net core网站添加通用的操作引导指南(IntroJs)

接上级领导命令, 需要为开发的网站添加一个操作引导功能,让用户进入网站后可以大概了解如何操作.

实现该功能使用intro.js插件及asp.net core中组件(由于.net core中 @html.renderaction已经移除)来完成.

点击下载introjs

一. 首先是创建components

1. 在views/shared/components(没有请新建)目录下创建”IntroJs”目录

2. 创建ViewModel实体类

    public class IntroJsViewModel
    {
        /// <summary>
        /// 区域名
        /// </summary>
        public string Area { get; set; }

        /// <summary>
        /// 控制器名
        /// </summary>
        public string Controller { get; set; }

        /// <summary>
        /// 页面名
        /// </summary>
        public string Action { get; set; }

        /// <summary>
        /// 步骤列表
        /// </summary>
        public IntroStep[] Steps { get; set; }
    }

    public class IntroStep
    {
        /// <summary>
        /// 唯一选择器
        /// </summary>
        public string Element { get; set; }

        /// <summary>
        /// 步骤序号 1 ,2 ,3 ,4
        /// </summary>
        public int Step { get; set; }

        /// <summary>
        /// 提示文本, 可以为html
        /// </summary>
        public string Intro { get; set; }

        /// <summary>
        /// 位置, left right top  可为空
        /// </summary>
        public string Position { get; set; }
    }

3. 创建ViewComponent类

    public class IntroJsViewComponent: ViewComponent
    {
        public IntroJsViewComponent()
        {

        }

        public IViewComponentResult Invoke()
        {
            var routes = RouteData.Routers[0];
            var area = RouteData.Values["Area"] as string;
            area = string.IsNullOrWhiteSpace(area) ? "" : area.ToLower();
            var controller = RouteData.Values["Controller"].ToString().ToLower();
            var action = RouteData.Values["Action"].ToString().ToLower();
            StringBuilder sb = new StringBuilder();
            string line = string.Empty;
            string filepath = System.IO.Directory.GetCurrentDirectory() + "/IntroSettings.json";
            if (File.Exists(filepath))
            {
                using (StreamReader sr = new StreamReader(filepath))
                {
                    while ((line = sr.ReadLine()) != null)
                    {
                        sb.Append(line);
                    }
                }
                var stepList = JsonConvert.DeserializeObject<List<IntroJsViewModel>>(sb.ToString());
                var step = stepList.FirstOrDefault(x =>
                    x.Area.ToLower() == area && x.Controller.ToLower() == controller && x.Action.ToLower() == action);
                step = step == null ? new IntroJsViewModel{ Steps = new IntroStep[0]}: step;
                return View(step);
            }
            return View(new IntroJsViewModel { Steps = new IntroStep[0] });
        }
    }

4. 添加默认的Default.cshtml视图文件

文件代码如下:

@using WebProject.Views.Shared.Components.IntroJs
@model IntroJsViewModel
@{

}
<script type="text/javascript" src="~/Scripts/introjs/intro.min.js"></script>
<script>
    var showIntro = true;
    var steps = [];
    $(function () {

        @{
            foreach (var item in Model.Steps)
            {
                <text>steps.push({ element: '@item.Element', intro: '@item.Intro', position: '@item.Position' });</text>
            }
        }
        if (showIntro) {
            introJs().setOptions({
                prevLabel: "上一步",
                nextLabel: "下一步",
                skipLabel: "跳过",
                doneLabel: "完成",
                showProgress: true, //显示进度条
                steps:steps
            }).start();
        }
    });

</script>

二. 在需要添加引导的页面引用该组件

一般在母版页底部进行引用.

@await Component.InvokeAsync("IntroJs")

三. 添加配置文件

在项目根目录添加”IntroSettings.json”配置文件

area和controller及action用来确定页面(可以多个)

steps节点下的element为该页面下的dom选择器,如ID等, 请务必保证唯一,否则将影响效果

step为该提示的步骤, 从数字1开始

intro为引导的文字说明

position为文字说明在该dom元素的哪个方向. left,right,top, bottom

[
  {
    "Area": "FormStat",
    "Controller": "WKEntryYear",
    "Action": "Index",
    "Steps": [
      {
        "Element": "#divContent",
        "Step": 1,
        "Intro": "这里是头部......",
        "Position": ""
      },
      {
        "Element": "#btnSearch",
        "Step": 2,
        "Intro": "搜索内容 ",
        "Position": ""
      }
    ]
  }
]

 

五. 效果图

c# asp.net ip黑名单

短信验证码接口被恶意请求,写了一个简单的黑名单规则.
使用静态数组的形式实现,优点为不占用数据库资源且速度更快效率更高. 缺点为数据无持久化,网站重启后黑名单就清空了.
效果为: 如果指定时间内请求次数大于最大请求数并且发送的手机号码大于等于指定号码数量,则加入黑名单,时长为 {BlockTime}
根据如下属性进行配置后,
IsInBlackList方法为判断IP是否在黑名单内,返回bool
RecordRequest方法记录IP和手机号(可以根据功能自己修改具体功能),如满足列入黑名单条件,则自动列入黑名单, 返回bool. 如满足拉黑规则,则返回true,否则返回false

    public class IpBlock
    {

        /// <summary>
        /// 统计时间单位(秒)
        /// </summary>
        private const int Seconds = 60*50;//50分钟

        /// <summary>
        /// 单位时间内请求超出指定次数,则加入黑名单
        /// </summary>
        private const int RequestCount = 3;

        /// <summary>
        /// 单位时间内请求的手机号码数
        /// </summary>
        private const int RequestPhoneCount = 3;
        /// <summary>
        /// 黑名单时间 分钟
        /// </summary>
        private const int BlockTime = 60*24*7; //7天

        /// <summary>
        /// IP黑名单
        /// </summary>
        private static List<BlockedIp> BlackList;

        /// <summary>
        /// 请求详情
        /// </summary>
        private static List<IpRequestModel> RequestList;

        static IpBlock()
        {
            BlackList = new List<BlockedIp>();
            RequestList = new List<IpRequestModel>();
        }


        /// <summary>
        /// IP地址是否在黑名单中
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool IsInBlackList(string ip)
        {
            UpdateBlackList();
            return BlackList.FirstOrDefault(x => x.Ip.Equals(ip)) != null;
        }

        /// <summary>
        /// 记录请求信息并将符合的IP列入黑名单
        /// </summary>
        /// <param name="ip"></param>
        public static bool RecordRequest(string ip, string phone)
        {
            UpdateRequestList();
            RequestList.Add(new IpRequestModel
            {
                Ip = ip,
                RequestTime = DateTime.Now,
                Phone = phone
            });
            var requestRecord = RequestList.Where(x => x.Ip.Equals(ip));
            var count = requestRecord.Count();
            var phoneCount = requestRecord.Select(x => x.Phone).Distinct().Count();
            if (count >= RequestCount && phoneCount >= RequestPhoneCount)
            {
                AddToBlackList(ip);
                return true;
            }
            return false;
        }





        /// <summary>
        /// 更新黑名单
        /// </summary>
        private static void UpdateBlackList()
        {
            var expireList = BlackList.Where(x => x.ExpireTime < DateTime.Now).ToList();
            foreach (var item in expireList)
            {
                BlackList.Remove(item);
            }
        }

        /// <summary>
        /// 将IP列入黑名单
        /// </summary>
        /// <param name="ip"></param>
        private static void AddToBlackList(string ip)
        {
            var item = BlackList.FirstOrDefault(x => x.Ip.Equals(ip));
            if (item != null)
            {
                item.ExpireTime = DateTime.Now.AddMinutes(BlockTime);
            }
            else
            {
                BlackList.Add(new BlockedIp
                {
                    ExpireTime = DateTime.Now.AddMinutes(BlockTime),
                    Ip = ip
                });
            }
        }


        /// <summary>
        /// 更新请求信息
        /// </summary>
        private static void UpdateRequestList()
        {
            var expireList = RequestList.Where(x => x.RequestTime < DateTime.Now.AddSeconds(0-Seconds)).ToList();
            foreach (var item in expireList)
            {
                RequestList.Remove(item);
            }

        }

    }

    public class BlockedIp
    {
        /// <summary>
        /// IP地址
        /// </summary>
        public string Ip { get; set; }

        /// <summary>
        /// 过期时间
        /// </summary>
        public DateTime ExpireTime { get; set; }
    }

    public class IpRequestModel
    {
        /// <summary>
        /// IP地址
        /// </summary>
        public string Ip { get; set; }

        /// <summary>
        /// 请求时间
        /// </summary>
        public DateTime RequestTime { get; set; }

        /// <summary>
        /// 手机号
        /// </summary>
        public string Phone { get; set; }

    }

效果:

......
2018-08-31 10:47:51.007 INFO ASP.mobilergister_aspx: 发送验证码短信 时间:2018/8/31 10:47:51 IP地址:223.68.67.198 手机号码:177****8475
2018-08-31 10:50:55.412 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:50:55 IP地址:220.190.28.133
2018-08-31 10:50:58.302 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:50:58 IP地址:60.181.172.196
2018-08-31 10:51:00.474 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:00 IP地址:39.171.235.161
2018-08-31 10:51:14.037 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:14 IP地址:60.181.164.123
2018-08-31 10:51:15.677 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:15 IP地址:182.200.0.14
2018-08-31 10:51:21.037 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:21 IP地址:112.12.136.83
2018-08-31 10:51:23.724 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:23 IP地址:42.234.41.134
2018-08-31 10:51:25.802 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:25 IP地址:60.180.34.139
2018-08-31 10:51:28.443 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:28 IP地址:182.200.179.203
2018-08-31 10:51:31.130 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:31 IP地址:115.223.150.237
2018-08-31 10:51:39.990 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:39 IP地址:113.87.130.72
2018-08-31 10:51:46.771 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:46 IP地址:113.247.23.88
2018-08-31 10:51:47.990 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:47 IP地址:60.180.50.65
2018-08-31 10:51:52.459 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:52 IP地址:182.200.7.6
2018-08-31 10:51:57.506 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:51:57 IP地址:115.223.135.93
2018-08-31 10:52:07.008 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:52:07 IP地址:223.68.67.198
2018-08-31 10:52:08.758 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:52:08 IP地址:60.180.235.58
2018-08-31 10:52:28.555 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:52:28 IP地址:27.18.202.136
2018-08-31 10:52:59.367 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:52:59 IP地址:113.139.240.243
2018-08-31 10:55:06.790 INFO ASP.mobilergister_aspx: 发送验证码短信 时间:2018/8/31 10:55:06 IP地址:125.47.67.224 手机号码:130****1322
2018-08-31 10:55:34.775 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:55:34 IP地址:59.109.117.88
2018-08-31 10:57:40.229 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 10:57:40 IP地址:180.120.160.12
2018-08-31 11:02:21.105 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 11:02:21 IP地址:113.139.242.216
2018-08-31 11:14:03.632 INFO ASP.mobilergister_aspx: 发送验证码短信 时间:2018/8/31 11:14:03 IP地址:1.194.21.226 手机号码:130****2793
2018-08-31 11:27:52.295 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 11:27:52 IP地址:27.17.148.80
2018-08-31 11:31:31.718 INFO ASP.mobilergister_aspx: 发送验证码短信 时间:2018/8/31 11:31:31 IP地址:125.47.55.70 手机号码:130****1323
2018-08-31 11:31:40.968 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 11:31:40 IP地址:182.200.3.11
2018-08-31 11:31:45.843 INFO ASP.mobilergister_aspx: IP加入黑名单 时间:2018/8/31 11:31:45 IP地址:125.47.55.70
......