博客 (168)

[
  {
    "outputFileName": "wwwroot/js/Admin/Blog/List.js",
    "inputFiles": [
      "Areas/Admin/Views/Blog/List.cshtml.js"
    ]
  }
]

JS 源文件在视图目录,独立于 .cshtml 文件,又折叠于 .cshtml 文件。

输出目录在 wwwroot 中,若文件名不以“.min.js”结尾,那么会自动生成“.js”和“.min.js”两个文件,分别在开发模式和生产模式的视图中引用。

缺点:只更改 JS 内容,执行“生成解决方案”项目不会重新编译更新 wwwroot 中的 .js 和 .min.js 文件,这时使用“重新生成解决方案”可以解决这个问题。

xoyozo 3 年前
2,485

您需要将 IWebHostEnvironment 注入到类中才能访问属性值 ApplicationBasePath:阅读有关依赖关系注入的信息。成功注入依赖项后,wwwroot 路径应该可供您使用。例如:

private readonly IWebHostEnvironment _appEnvironment;

public ProductsController(IWebHostEnvironment appEnvironment)
{
   _appEnvironment = appEnvironment;
}

用法:

 [HttpGet]
 public IEnumerable<string> Get()
 {
    FolderScanner scanner = new FolderScanner(_appEnvironment.WebRootPath);
    return scanner.scan();
 }

编辑:在 ASP.NET 的更高版本中,IHostingEnvironment 已被替换为 IWebHostEnvironment

O
转自 Oluwafemi 3 年前
3,378
public static class EntityFrameworkCoreExtension
{
    private static DbCommand CreateCommand(DatabaseFacade facade, string sql, out DbConnection connection, params object[] parameters)
    {
        var conn = facade.GetDbConnection();
        connection = conn;
        conn.Open();
        var cmd = conn.CreateCommand();
        cmd.CommandText = sql;
        cmd.Parameters.AddRange(parameters);
        return cmd;
    }

    public static DataTable SqlQuery(this DatabaseFacade facade, string sql, params object[] parameters)
    {
        var command = CreateCommand(facade, sql, out DbConnection conn, parameters);
        var reader = command.ExecuteReader();
        var dt = new DataTable();
        dt.Load(reader);
        reader.Close();
        conn.Close();
        return dt;
    }

    public static List<T> SqlQuery<T>(this DatabaseFacade facade, string sql, params object[] parameters) where T : class, new()
    {
        var dt = SqlQuery(facade, sql, parameters);
        return dt.ToList<T>();
    }

    public static List<T> ToList<T>(this DataTable dt) where T : class, new()
    {
        var propertyInfos = typeof(T).GetProperties();
        var list = new List<T>();
        foreach (DataRow row in dt.Rows)
        {
            var t = new T();
            foreach (PropertyInfo p in propertyInfos)
            {
                if (dt.Columns.IndexOf(p.Name) != -1 && row[p.Name] != DBNull.Value)
                {
                    p.SetValue(t, row[p.Name], null);
                }
            }
            list.Add(t);
        }
        return list;
    }
}

调用示例:

var data = db.Database.SqlQuery<List<string>>("SELECT 'title' FROM `table` WHERE `id` = {0};", id);


转自 我的个去 3 年前
2,091
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace xxx.xxx.xxx.Controllers
{
    public class DiscuzTinyintViewerController : Controller
    {
        public IActionResult Index()
        {
            using var context = new Data.xxx.xxxContext();

            var conn = context.Database.GetDbConnection();
            conn.Open();
            using var cmd = conn.CreateCommand();
            cmd.CommandText = "SELECT `TABLE_NAME` FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE();";
            Dictionary<string, List<FieldType>?> tables = new();

            using var r = cmd.ExecuteReader();
            while (r.Read())
            {
                tables.Add((string)r["TABLE_NAME"], null);
            }
            conn.Close();

            foreach (var table in tables)
            {
                var conn2 = context.Database.GetDbConnection();
                conn2.Open();
                using var cmd2 = conn2.CreateCommand();
                cmd2.CommandText = "DESCRIBE " + table.Key;
                using var r2 = cmd2.ExecuteReader();
                List<FieldType> fields = new();
                while (r2.Read())
                {
                    if (((string)r2[1]).Contains("tinyint(1)"))
                    {
                        fields.Add(new()
                        {
                            Field = (string)r2[0],
                            Type = (string)r2[1],
                            Null = (string)r2[2],
                        });
                    }
                }
                conn2.Close();
                tables[table.Key] = fields;
            }

            foreach (var table in tables)
            {
                foreach (var f in table.Value)
                {
                    var conn3 = context.Database.GetDbConnection();
                    conn3.Open();
                    using var cmd3 = conn3.CreateCommand();
                    cmd3.CommandText = $"SELECT {f.Field} as F, COUNT({f.Field}) as C FROM {table.Key} GROUP BY {f.Field}";
                    using var r3 = cmd3.ExecuteReader();
                    List<FieldType.ValueCount> vs = new();
                    while (r3.Read())
                    {
                        vs.Add(new() { Value = Convert.ToString(r3["F"]), Count = Convert.ToInt32(r3["C"]) });
                    }
                    conn3.Close();
                    f.groupedValuesCount = vs;
                }
            }

            return Json(tables.Where(c => c.Value != null && c.Value.Count > 0));
        }

        private class FieldType
        {
            public string Field { get; set; }
            public string Type { get; set; }
            public string Null { get; set; }
            public List<ValueCount> groupedValuesCount { get; set; }
            public class ValueCount
            {
                public string Value { get; set; }
                public int Count { get; set; }
            }
            public string RecommendedType
            {
                get
                {
                    if (groupedValuesCount == null || groupedValuesCount.Count < 2)
                    {
                        return "无建议";
                    }
                    else if (groupedValuesCount.Count == 2 && groupedValuesCount.Any(c => c.Value == "0") && groupedValuesCount.Any(c => c.Value == "1"))
                    {
                        return "bool" + (Null == "YES" ? "?" : "");
                    }
                    else
                    {
                        return "sbyte" + (Null == "YES" ? "?" : "");
                    }
                }
            }
        }
    }
}
[{
	"key": "pre_forum_post",
	"value": [{
		"field": "first",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "0",
			"count": 1395501
		}, {
			"value": "1",
			"count": 179216
		}],
		"recommendedType": "bool"
	}, {
		"field": "invisible",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "-5",
			"count": 9457
		}, {
			"value": "-3",
			"count": 1412
		}, {
			"value": "-2",
			"count": 1122
		}, {
			"value": "-1",
			"count": 402415
		}, {
			"value": "0",
			"count": 1160308
		}, {
			"value": "1",
			"count": 3
		}],
		"recommendedType": "sbyte"
	}, {
		"field": "anonymous",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "0",
			"count": 1574690
		}, {
			"value": "1",
			"count": 27
		}],
		"recommendedType": "bool"
	}, {
		"field": "usesig",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "0",
			"count": 162487
		}, {
			"value": "1",
			"count": 1412230
		}],
		"recommendedType": "bool"
	}, {
		"field": "htmlon",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "0",
			"count": 1574622
		}, {
			"value": "1",
			"count": 95
		}],
		"recommendedType": "bool"
	}, {
		"field": "bbcodeoff",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "-1",
			"count": 935448
		}, {
			"value": "0",
			"count": 639229
		}, {
			"value": "1",
			"count": 40
		}],
		"recommendedType": "sbyte"
	}, {
		"field": "smileyoff",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "-1",
			"count": 1359482
		}, {
			"value": "0",
			"count": 215186
		}, {
			"value": "1",
			"count": 49
		}],
		"recommendedType": "sbyte"
	}, {
		"field": "parseurloff",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "0",
			"count": 1572844
		}, {
			"value": "1",
			"count": 1873
		}],
		"recommendedType": "bool"
	}, {
		"field": "attachment",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "0",
			"count": 1535635
		}, {
			"value": "1",
			"count": 2485
		}, {
			"value": "2",
			"count": 36597
		}],
		"recommendedType": "sbyte"
	}, {
		"field": "comment",
		"type": "tinyint(1)",
		"null": "NO",
		"groupedValuesCount": [{
			"value": "0",
			"count": 1569146
		}, {
			"value": "1",
			"count": 5571
		}],
		"recommendedType": "bool"
	}]
}]


xoyozo 3 年前
1,667

安装 Windows 11 的外星人笔记本电脑,当关闭盖子,或按下电源键,或直接在系统里点击“睡眠”按钮均不能使系统正常睡眠,可能的原因如下:

  • 正在运行 Alienware Mobile Connect

  • 迅雷的“离线模式”开启


注意:当接通电源的电脑关闭盖子,系统会执行睡眠,但当拔下电源线时,又会自动唤醒,可谓奇葩。这一点经过外星人官方确认,外星人机子都是这样的。


另外,当正在睡眠的笔记本电脑插上电源,或打开盖子,或按下电源键,均会唤醒。


因此,正确的睡眠步骤:关闭阻止睡眠的程序,断开电源,关闭盖子。

xoyozo 3 年前
4,115

SshNet 向一个已存在的文件 WriteAllText 的时候,是在原内容的基础上从第一个字节依次覆盖新内容。

因此,如果新内容的长度小于原内容,则最终的文件内容将是新内容与结尾部分原内容的结合。

若新内容的长度大于等于原内容,则不存在问题。

例:原文件内容:"abc",WriteAllText 的内容为:“de”,那么最终的文件内容是:“dec”。

xoyozo 3 年前
1,490

本文记录于 2021 年 9 月。



升级前期望(最新正式版)最终选择
操作系统CentOS 6.5Alibaba Cloud Linux 3Alibaba Cloud Linux 3
管理面板lnmp宝塔面板 Linux 版 7.7.0宝塔面板 Linux 版 7.7.0
Web 服务nginx 1.6nginx 1.21nginx 1.21
脚本语言PHP 5.6PHP 8.0PHP 7.4
数据库
RDS MySQL 5.6RDS MySQL 8.0RDS MySQL 5.6
论坛程序
Discuz! X3.2 GBKDiscuz! X3.5 UTF-8(即将发布)Discuz! X3.4 GBK


版本选择原因:

  • Alibaba Cloud Linux 完全兼容 CentOS,相比于 CentOS 较短的生命周期,Alibaba Cloud Linux 3 将于 2029 年 4 月 30 日结束生命周期。

  • Discuz! X3.4 不支持 PHP 8.0,安装时即报错,打开页面时一片空白。

  • MySQL 8.0 和阿里云 RDS 的 MySQL 7.5 不支持 MyISAM,而数据表 pre_common_member_grouppm 和 pre_forum_post 使用联合主键且自动递增字段不是第一主键,使用 InnoDB 引擎创建表时会报“1075 - Incorrect table definition; there can be only one auto column and it must be defined as a key”错误,而擅自更改主键次序会影响业务逻辑。因此,在必须选择阿里云 RDS 的情况下,只能选择 MySQL 5.6。(2023年8月注:查看如何更改为 InnoDB

  • Discuz! X3.5 正式版尚未发布(截止发稿),即便发布,插件也可能不能得到及时更新。相比之下,X3.4 首个版本发布距今已有 4 年,相关第三方插件已经非常成熟。


完整升级步骤:

  1. 备份原网站程序、RDS 数据库;

  2. 购买新的 ECS、RDS,挂载磁盘,安装云监控;

  3. 迁移(或还原)数据库到新的 RDS;

  4. 安装宝塔面板并配置;

  5. 安装 nginx 及 PHP;

  6. 创建网站、配置 SSL、伪静态、防盗链、可写目录禁执行等(.conf);

  7. 配置 hosts;

  8. 上传原网站程序到新的站点目录下;

  9. Discuz! X 升级文档升级 X3.2 至 X3.4;详情见下文 ↓;

  10. 配置 OSS、Redis、更新缓存等;

  11. 测试论坛基本功能是否正常;检查附件是否正常显示;全面检查控制台配置;

  12. 逐个开启插件并检查兼容性;

  13. 按二开备忘录逐个按需进行二开;

  14. 逐个修改调用论坛接口的项目及直接调用论坛数据库的项目;

  15. 调试 MAGAPP 接口;

  16. 尝试强制 https 访问;

  17. 将以上所有修改后的程序保留备份;发布升级公告并关闭论坛;重复以上步骤;修改域名解析;开启论坛;

  18. 配置 IP 封禁、定时器、日志、自动备份、配置其它 ECS 的 hosts 等;

  19. 查看搜索引擎中收录的地址,是否有无法访问的情况;

  20. 尝试将历史遗留的本地附件全部转移到 OSS;

  21. 这篇文章,可能有其它需要配置的地方。


Discuz! X 升级步骤及注意点:

  • 升级前务必先修改 ./config/ 目录下的数据库/缓存连接信息,以防出现新站连接老库的情况;

  • 官方文档进行升级;

  • 【问题】运行到 ./install/update.php?step=data&op=notification 时白屏。

    【排查】尝试切换到 PHP 5.6 后成功(但该版本过于陈旧不能使用);尝试升级 CPU 和内存 PHP 7.4 上升级仍不成功。

    【原因】DB::result_first() 方法不对 SQL 语句追加“limit 1”,而是 SELECT 所有记录后在 PHP 端取第一条数据;

    【解决】打开文件 update.php,查找 elseif($_GET['op'] == 'notification'),该节点的功能是在表 home_notification 中查找 category <= 0 的数据并修复它,如果数据库中所有 category 都大于 0,直接注释其内部 if 代码段继续升级即可(或改为 if(false && ...))。

  • 【问题】发布主题遇到错误:(1062) Duplicate entry '*' for key 'pid'

    【原因】forum_post 中的 pid 不是自动增长的,而是由表 forum_post_tableid 中自动增长的 pid 生成的。如果生成的 pid 值已在 forum_post 表中存在,则会出现此错误。

    【解决】迁移数据库时应关闭论坛,以防止 forum_post 表有新数据插入。

  • 【问题】打开帖子页面 ./thread-***-1-1.html 显示 404 Not Found,而 ./forum.php?mod=viewthread&tid=*** 可以正常打开

    【原因】未配置伪静态(可在宝塔面板中选择)

  • 【问题】打开 UCenter 时报错:UCenter info: MySQL Query Error SQL:SELECT value FROM [Table]vars WHERE name='noteexists'

    【解决】打开文件 ./uc_server/data/config.inc.php 配置数据库连接

  • 【问题】打开登录 UCenter 后一片空白

    【解决】将目录 ./uc_server/data/ 设为可写

  • 需要将原来安装的插件文件移回 ./source/plugin/ 目录,并设置可写;

  • 界面-表情管理,界面-编辑器设置-Discuz!代码


后续 Discuz! X3.4 R 小版本升级注意事项:

  1. 确认插件是否支持新版本(如短信通)

  2. 先创建一个新网站测试二开代码

  3. 保留 /config/、/data/、/uc_client/data/、/uc_server/data/、/source/plugin/,其它移入 old

  4. 上传文件

  5. 移回其它需要的文件,如:

  6. -- 勋章/loading/logo/nv 等:/static/image/common/

  7. -- 表情:/static/image/smiley/

  8. -- 水印:/static/image/common/watermark.*

  9. -- 风格:/template/default/style/t2/nv.png 等

  10. -- 默认头像:/uc_server/images/noavatar_***.gif

  11. -- 根目录 favicon.ico 等

  12. -- 及其它非 DZ 文件

  13. 再次检查可写目录的写入权限和禁止运行 PHP 效果。

xoyozo 3 年前
4,134

m① R②

x① R②

① 表示屏幕尺寸,一般有 15、17 等

② 表示第几代,对应 CPU 和显卡的不同,数字越大越新

相同 ① 与 ② 的情况下仍有细分款式,对应内存、硬盘、屏幕分辨率刷新率等不同

x 系列是全新的系列,是 m 系列的更新款(m 系列不再更新),相比 m 系列提升了散热性能

屏幕尺寸型号处理器显卡发布时间
14.0 英寸x14 R112 代 i730 系2022年1月
15.6 英寸m15 R410 代 i7/i930 系
m15 R5锐龙 R7-5800H30 系
m15 R611 代 i730 系
m15 R712 代 i730 系2022年2月
x15 R111 代 i7/i930 系
x15 R212 代 i930 系2022年2月
16.0 英寸
m1613 代 i7/i9
40 系2023年2月
x1613 代 HK
40 系
2023年2月
17.3 英寸
m17 R310 代 i7
20 系

m17 R410 代 i730 系
m17 R5
锐龙 R7/R930 系2022年3月
x17 R111 代 i7/i930 系

x17 R212 代 i9K30 系
2022年2月
18英寸m1813 代 i940 系
2023年2月

x15 是板载内存,x17 是卡槽内存

x 系列屏幕有 1K165Hz / 1K360Hz / 2K240Hz(15寸独有)/ 4K120Hz(17寸独有)

x 系列有 2 个 M.2 硬盘位,没有 2.5 寸硬盘位


Area-51m R(数字):可拆 CPU

Area-51m R2:10 代 i7,20 系显卡


以上规则整理于 2021 年 7 月,随着时间的推移,以上信息将逐渐失效。


xoyozo 3 年前
16,867

本文写于 2021 年 7 月。

WebBrowser 不能改用 Chrome 内核。

在 .NET Frameworks 和 .NET Core 年代,常用的第三方组件有:WebKit.NET、CefSharp 等。

而并未找到适用于 .NET 5 的成熟的 Chromium 内核的浏览器组件。

不过还是推荐一款微软官方出品的 WebView2,需要安装 Microsoft Edge Canary 才能正常运行。


xoyozo 3 年前
2,325

错误Web 部署任务失败。 (无法为指定目录执行操作(“创建文件”)。如果服务器果管理员没有为你使用的用户凭据授予执行此操作的权限,则会发生这种情况。

  在以下位置了解更多信息: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_INSUFFICIENT_ACCESS_TO_SITE_FOLDER。  在以下位置了解更多信息: https://go.microsoft.com/fwlink/?LinkId=221672#ERROR_INSUFFICIENT_ACCESS_TO_SITE_FOLDER。)

解决方法:设置该文件或网站目录的 LOCAL SERVICE 用户完全控制权限。

xoyozo 3 年前
1,958