客户端:Failed to connect to host.
服务端:无任何日志
原因:可能是域名、IP 或端口有误,或端口未开放。
客户端/服务端:530 Login incorrect.
原因:用户名或密码错误。
客户端/服务端:503 Use AUTH first.
原因:服务端开启了 FTPS 协议(FTP over TLS),且禁止了 FTP 协议(plain FTP)。
解决方法:不建议服务端恢复不安全的 FTP 协议,客户端应配置 client.Config 的 EncryptionMode、DataConnectionEncryption、SslProtocols、ValidateCertificate 等参数。
客户端/服务端:530 This server does not allow plain FTP. You have to use FTP over TLS.
原因:服务端启用了 FTPS。
解决方法:给 client.Config.EncryptionMode 正确的赋值(FtpEncryptionMode.Explicit 或 FtpEncryptionMode.Auto)。
服务端:[Error] TLS session of data connection not resumed.
原因:证书版本有误。
解决方法:给 client.Config.SslProtocols 赋值正确的 TLS 版本。
服务端:521 PROT P required
原因:服务端开启了“Require TLS session resumption on data connection when using PROT P”
解决方法:client.Config.DataConnectionEncryption = true;
客户端/服务端:450 TLS session of data connection has not resumed or the session does not match the control connection
原因:TLS 与控制连接不匹配,即服务端开启了“Require TLS session resumption on data connection when using PROT P”
解决方法:我暂时还不知道原因,临时关闭了“Require TLS session resumption on data connection when using PROT P”(不建议)。该问题出现在 FileZilla Server 0.x 版本,在 1.x 版本中没有该配置选项。

解析域名、挂载磁盘(若有另购)、修改实例名称、配置安全组、设置快照策略、安装云监控插件并在应用分组添加服务器
远程连接进入 ECS(若解析未生效可以先用 IP)
开启 Windows 防火墙(使用推荐设置)
Windows 更新
安装 IIS:服务器管理器-添加角色和功能-勾选“Web 服务器(IIS)”包括管理工具
建议勾选:
默认已勾选项
按需安装 IP 和域限制
跟踪(即“失败请求跟踪”)
请求监视器、日志记录工具、
按需安装 ASP
按需安装 ASP.NET 4.8(会同时勾选 .NET Extensibility 4.8、ISAPI 扩展、ISAPI 筛选器)
应用程序初始化(建议安装)
管理服务(用于 Web 部署)
细节:设置任务栏;设置桌面图标;个性化-颜色-勾选“标题栏和窗口边框”;设置输入法;
下载 URL 重写(文件名:rewrite_amd64_zh-CN.msi)
下载 MySQL Connector/NET(文件名:mysql-connector-net-8.0.19.msi)
下载 ASP.NET Core 运行时 Hosting Bundle(文件名:dotnet-hosting-*.*.*-win.exe)
下载 .NET 桌面运行时 Windows x64(文件名:windowsdesktop-runtime-*.*.*-win-x64.exe)
下载 Web Deploy(文件名:WebDeploy_amd64_zh-CN.msi)
服务:设置“ASP.NET State Service”自动启动
IIS 日志:路径(如 D:\wwwlogs),每小时(统一设置一个全局的就行了,不需要设置每个网站),按需勾选“使用本地时间进行文件命名和滚动更新”
IIS 导入证书:个人、允许导出证书。参
设置权限:设置网站所在分区(如 D 盘),安全,添加 IIS_IUSRS,全部拒绝(防止跨站)
添加用户:为每个网站创建用户(既能防止跨站,又能跟踪进程),密码不能改、不过期,仅隶属于 IIS_IUSRS,并添加到每个网站的根目录
创建网站:设置访问物理路径的用户;设置应用程序池的“标识”用户;编辑绑定:勾选需要服务器名称指示;检查域名是否绑全;设置写入目录;
重复上面两步
检查所有网站用户是否仅隶属于 IIS_IUSRS(在“组”页面双击 Users 和 IIS_IUSRS 查看成员)
在应用程序池列表页面检查 CLR 版本、管托管道模式和标识;在网站列表页面检查绑定和路径
设置“IP 地址和域限制”
废弃旧服时再次检查:IIS 中各功能设置、hosts、安装的应用程序、启动项、服务、防火墙等
解析各网站域名
>> 关于域名解析
因各地域名解析生效时间不可控,一般国内域名 1 天内,国际域名 2 天内。
若网站数据库在 RDS、上传文件在 OSS,则解析 48 小时后直接停止原网站即可;(比较理想的)
文件上传到 ECS 的可使用 FTP 等工具定时同步文件,或直接停止原网站。(网友会遇到新文章中图片无法显示等问题)
还有一种方法是新网站提前解析一个备用域名,确保完全生效后再修改正式域名的解析,原网站无条件跳转到备用域名,如果数据库中有保存完整网址路径的,关闭原网站并解绑备用域名之后,进行批量替换。(缺点是可能会影响在搜索引擎的网站权重)
部分有定时器的网站要注意,如果两个网站的定时器都正常开启会导致意外的,需要停止其中一个网站的定时器。
当然每种方法都有优缺点,选择可以接受且方便的一种即可。

方法一:
在 DbContext.cs 文件中找到 OnConfiguring 方法,添加代码:
#if DEBUG
optionsBuilder.EnableSensitiveDataLogging();
optionsBuilder.LogTo(Console.WriteLine); // 输出日志到控制台
//optionsBuilder.LogTo(message => Debug.WriteLine(message)); // 输出日志到“输出”窗口
#endif
搞定。
若原来是 => 形式的,改为 { } 形式写法即可。
方法二:使用 Logging
打开 DbContext 文件,添加
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Debug;
将
optionsBuilder.UseMySql
替换为
optionsBuilder.UseLoggerFactory(MyLoggerFactory).UseMySql
添加方法
public static readonly LoggerFactory MyLoggerFactory = new LoggerFactory(new[] {
new DebugLoggerProvider()
});
即可在“输出”窗口看到生成的 SQL 语句了。

无法完成向远程代理 URL 发送请求。基础连接已经关闭:发送时发生错误。
解决办法:
IIS中“管理服务”的SSL证书过期了,停止,选择新证书,应用,启动。
如果证书名称都相同(例如“alias”),可以先选中一个启动,在 VS Web 部署的设置中验证连接,弹出“证书错误”,点击“查看详细信息”,检查“颁发给”中的域名是否正确,正确的话安装证书。

LigerShark.WebOptimizer.Core | BuildBundlerMinifier | |
特点 | 在运行时捆绑和缩小 CSS 和 JavaScript 文件 具有完整的服务器端和客户端缓存,以确保高性能 可禁用缩小 支持使用通配模式 标记帮助程序与缓存破坏 支持内联 支持 SCSS | 将 CSS、JavaScript 或 HTML 文件捆绑到单个输出文件中 保存源文件会自动触发重新捆绑 支持通配模式 支持 CI 方案的 MSBuild 支持 缩小单个或捆绑的 CSS、JavaScript 和 HTML 文件 每种语言的缩小选项是可定制的 打开生成的文件时显示水印 任务运行程序资源管理器集成 命令行支持 快捷更新解决方案中所有捆绑包 禁止生成输出文件 转换为 Gulp |
注入(Program.cs) | services.AddWebOptimizer(); app.UseWebOptimizer(); | |
指定捆绑的项目 | 在运行时自动缩小 css 和 js,也可以在 AddWebOptimizer 中自定义。默认情况下,生成的文件不会保存到磁盘,而是保存在缓存中。 | 手动编辑 bundleconfig.json 文件来指定需要合并和缩小的文件 |
功能配置 |
| 在 bundleconfig.json 捆绑时设置
|
热重载(在开发模式中保存文件自动更新浏览器效果) | VS 安装扩展,方法:菜单 - 扩展 - 管理扩展 - 联机 搜索“Bundler & Minifier” | |
其它资料 | ASP.NET 官方文档 |

以 ASP.NET 6 返回 BadRequestObjectResult 为例。
public IActionResult Post()
{
return BadRequest("友好的错误提示语");
}
axios
请求示例:
axios.post(url, {})
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.log(error.response.data);
});
error 对象:
{
"message": "Request failed with status code 400",
"name": "AxiosError",
"code": "ERR_BAD_REQUEST",
"status": 400,
"response": {
"data": "友好的错误提示语",
"status": 400
}
}
jQuery
请求示例:
$.ajax 对象形式
$.ajax({
url: url,
type: 'POST',
data: {},
success: function (data) {
console.log(data)
},
error: function (jqXHR) {
console.log(jqXHR.responseText)
},
complete: function () {
},
});
$.ajax 事件处理形式(Event Handlers)jQuery 3+
$.ajax({
url: url,
type: 'POST',
data: {},
})
.done(function (data) {
console.log(data)
})
.fail(function (jqXHR) {
console.log(jqXHR.responseText)
})
.always(function () {
});
$.get / $.post / $.delete
$.post(url, {}, function (data) {
console.log(data)
})
.done(function (data) {
console.log(data)
})
.fail(function (jqXHR) {
console.log(jqXHR.responseText)
})
.always(function () {
});
jqXHR 对象:
{
"readyState": 4,
"responseText": "友好的错误提示语",
"status": 400,
"statusText": "error"
}

System.ComponentModel.Win32Exception: 拒绝访问。
[ExternalException (0x80004005): 无法执行程序。所执行的命令为 "\bin\roslyn\csc.exe" /shared /keepalive:"10" /noconfig /fullpaths @"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\8c8f68eb\880f02b5\alczcu1a.cmdline"。]
解决方法:
web 部署发布时勾选“在发布期间预编译”
在“配置”中,去掉“允许更新预编辑站点”前的勾,勾选“不合并。为每个页面和控件创建单独的程序集”

本文使用 ASP.NET 6 版本 Senparc.Weixin.Sample.MP 示例项目改造。
第一步 注册多公众号
方法一:打开 appsettings.json 文件,在 SenparcWeixinSetting 节点内添加数组节点 Items,该对象类型同 SenparcWeixinSetting。
//Senparc.Weixin SDK 设置
"SenparcWeixinSetting": {
"IsDebug": true,
"Token": "",
"EncodingAESKey": "",
"WeixinAppId": "",
"WeixinAppSecret": "",
"Items": [
{
"IsDebug": true,
"Token": "a",
"EncodingAESKey": "a",
"WeixinAppId": "a",
"WeixinAppSecret": "a"
},
{
"IsDebug": true,
"Token": "b",
"EncodingAESKey": "b",
"WeixinAppId": "b",
"WeixinAppSecret": "b"
}
]
}
方法二:修改 Program.cs 文件,在 UseSenparcWeixin 方法中注册多个公众号信息。
var registerService = app.UseSenparcWeixin(app.Environment,
null /* 不为 null 则覆盖 appsettings 中的 SenparcSetting 配置*/,
null /* 不为 null 则覆盖 appsettings 中的 SenparcWeixinSetting 配置*/,
register => { /* CO2NET 全局配置 */ },
(register, weixinSetting) =>
{
//注册公众号信息(可以执行多次,注册多个公众号)
//register.RegisterMpAccount(weixinSetting, "【盛派网络小助手】公众号");
foreach (var mp in 从数据库或配置文件中获取的公众号列表)
{
register.RegisterMpAccount(new SenparcWeixinSetting
{
//IsDebug = true,
WeixinAppId = mp.AppId,
WeixinAppSecret = mp.AppSecret,
Token = mp.Token,
EncodingAESKey = mp.EncodingAeskey,
}, mp.Name);
}
});
完成后,我们可以从 Config.SenparcWeixinSetting.Items 获取这些信息。
第二步 接入验证与消息处理
打开 WeixinController 控制器,将构造函数改写为:
public WeixinController(IHttpContextAccessor httpContextAccessor)
{
AppId = httpContextAccessor.HttpContext!.Request.Query["appId"];
var MpSetting = Services.MPService.MpSettingByAppId(AppId);
Token = MpSetting.Token;
EncodingAESKey = MpSetting.EncodingAESKey;
}
示例中 Services.MPService.MpSettingByAppId() 方法实现从 Config.SenparcWeixinSetting.Items 返回指定 appId 的公众号信息。
为使 IHttpContextAccessor 注入生效,打开 Program.cs,在行
builder.Services.AddControllersWithViews();
下方插入
builder.Services.AddHttpContextAccessor();
这样,我们就可以在构造函数中直接获取地址栏中的 appId 参数,找到对应的公众号进行消息处理。
第三步 消息自动回复中的 AppId
打开 CustomMessageHandler.cs,将
private string appId = Config.SenparcWeixinSetting.MpSetting.WeixinAppId;
private string appSecret = Config.SenparcWeixinSetting.MpSetting.WeixinAppSecret;
替换为:
private string appId = null!;
private string appSecret = null!;
并在构造函数中插入
appId = postModel.AppId;
appSecret = Services.MPService.MpSettingByAppId(postModel.AppId).WeixinAppSecret;
这样,本页中使用的 appId / appSecret 会从 postModel 中获取,而非默认公众号。postModel 已在 WeixinController 中赋值当前的 appId。
改造后,我们可以在 OnTextRequestAsync() 等处理消息的方法中可以判断 appId 来处理不同的消息。
第四步 其它功能和接口
其它功能和接口均可用指定的 AppId 和对应的 AppSecret 进行调用。
