博客 (258)

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 4 年前
2,701

System.NotSupportedException: Serialization and deserialization of 'System.DateOnly' instances are not supported.

The unsupported member type is located on type 'System.Nullable`1[System.DateOnly]'.

解决方法:

https://www.nuget.org/packages/DateOnlyTimeOnly.AspNet/

builder.Services
    .AddControllers(options => options.UseDateOnlyTimeOnlyStringConverters())
    .AddJsonOptions(options => options.UseDateOnlyTimeOnlyStringConverters());


M
转自 Maksym Koshovyi 4 年前
7,362

POST

axios.post('AjaxCases', {
    following: true,
    success: null,
    page: 1,
}).then(function (response) {
    console.log(response.data)
}).catch(function (error) {
    console.log(error.response.data);
});
[HttpPost]
public IActionResult AjaxCases([FromBody] AjaxCasesRequestModel req)
{
    bool? following = req.following;
    bool? success = req.success;
    int page = req.page;
}

GET

axios.get('AjaxCase', {
    params: {
        int: 123,
    }
}).then(function (response) {
    console.log(response.data)
}).catch(function (error) {
    console.log(error.response.data);
});
[HttpGet]
public IActionResult AjaxCases([FromQuery] int id)
{
}

DELETE

格式与 GET 类似


* 若服务端获取参数值为 null,可能的情况如下:

  • 请检查相关枚举类型是否已设置 [JsonConverter] 属性,参:C# 枚举(enum)用法笔记,且传入的值不能为空字符串,可以传入 null 值,并将服务端 enum 类型改为可空。可以以 string 方式接收参数后再进行转换。

  • 模型中属性名称不能重复(大小写不同也不行)。

  • 布尔型属性值必须传递布尔型值,即在 JS 中,字符串 "true" 应 JSON.parse("true") 为 true 后再回传给服务端,vue 绑定方式参此文


参考:jQuery 请求 .NET Core / .NET 5 / .NET 6

xoyozo 4 年前
4,064

前提:

  • 监控摄像头有推流功能

  • 抖音有直播权限(粉丝数超过 1000)

  • 一个已备案的域名


流媒体服务器抖音直播流程.png

名词解释:

推流地址:由阿里云生成的接收摄像头视频流推送的地址。

播流地址:由阿里云生成可用于终端播放的视频流地址。


各环节功能解释:

摄像头:负责采集视频信息,并推送到阿里云。

阿里云视频直播服务:接收视频推流并分发到用户端(收费)。

OBS 软件:负责将视频流转化为可供直播伴侣调用的视频源。

直播伴侣:将视频源分发到短视频终端用户。


第一步:配置阿里云视频直播服务

1.1 在阿里云控制台中开通视频直播,在域名管理中添加域名。

image.png

这里需要添加两个域名,一个是推流域名,一个是播流域名。顾名思义,“推流”指从摄像头将流推送到阿里云,“播流”是用户播放视频流。

以添加域名推流域名“rtmp.xoyozo.net”和播流域名“live.xoyozo.net”为例:

image.png

然后按列表中的 CNAME 地址对域名作解析即可。

解析生效后,点击任意一个域名进行配置,将推流域名和播流域名相互绑定。成功后,可以在推流域名中的播流信息中看到播流域名,在播流域名的推流信息中也能看到推流域名。

1.2 生成推流地址/播流地址

在工具箱中点击地址生成器。

image.png

选择推流域名和播流域名,AppName 和 StreamName 任意填写,生成成功后获取以下地址:

image.png

注:鉴权串是按照鉴权规则生成的串,默认有效期 30 分钟,超出时间即中断推流。可以在域名管理中修改该值,或直接关闭 URL 鉴权。


第二步:在摄像机控制面板中配置推流域名

该步骤因摄像机的品牌和型号不同而有所差异。本文以 IP CAMERA 为例。

首先使用 IP 搜索工具在局域网上搜索摄像机,找到摄像机的 IP 地址。

image.png

在浏览器上打开,输入用户名和密码进入管理面板。

image.png

在“参数设置”-“网络设置”- RTMP Publish 中,将推流地址填入到“预定网址”中,点击“应用”。

image.png

刷新后查看“直播状态”和“直播网址”是否已生效。

若配置成功,可将播流地址在视频播放器中打开观看,或直接在 iPhone 或安卓手机中打开播流地址。


第三步:使用 OBS Studio 将直播流信号转换为虚拟摄像头信号

因抖音直播伴侣无法使用播流地址作为视频源进行直播输出,故使用 OBS 将播流信号转化为虚拟的本机摄像头信号源供直播伴侣调用。

下载安装 OBS Studio,添加一个“场景”:

image.png

然后添加一个“媒体源”:

image.png

去掉“本地文件”前面的勾,将播流地址填到“输入”框中:

image.png

确定后即可预览到直播内容:

image.png

拖动视频区域可调整输出范围。

点击“启动虚拟摄像机”。

提示:OBS 创建的虚拟摄像机默认会从物理麦克风和桌面系统音频拾音,请按需在“混音器”中配置。


第四步:OBS 使用 VLC 视频源(此步可略过)

若 OBS 直接添加媒体源不稳定,可以使用 VLC 视频源。

下载安装 VLC 播放器

在 OBS Studio 中添加来源,选择“VLC 视频源”:

image.png

点击“播放列表”右侧的“+”,选择“添加路径 /URL”:

image.png

填写播流地址并确定。


第五步:配置抖音直播伴侣使用 OBS 的虚拟摄像机信号源

下载安装抖音直播伴侣,在任意场景中添加素材,选择“摄像头”:

image.png

摄像头选择“OBS Virtual Camera”:

image.png

点击“开始直播”:

image.png


下一步:如何配置视频号/微博直播的推流直播监控摄像头画面

xoyozo 5 年前
15,653

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

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

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

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

xoyozo 5 年前
2,347

直接运行项目启动程序(在发布目录中,以项目名称为文件名,扩展名为 .exe 的可执行程序)

启动后可在“Now listening on:”所在行看到访问入口 URL(如图中 http://localhost:5000)。

在同服浏览器中打开该地址,访问到报错页面,回到该命令行窗口可见“fail”异常的详细信息。

QQ截图20211003173208.png

xoyozo 5 年前
2,681

打开文件 Startup.cs,找到:

app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TodoApi v1"));

将这两行移出 if 外。

xoyozo 5 年前
6,772

如果你的视图页面(.cshtml)是由另一个视图页面复制而来的,就有可能出现开发调试时正常,发布到服务器后打开报 500 错误。

解决方法是:新建一个 .cshtml 页面,将代码移植到这个文件上,删除原来的页面,更改刚创建的文件名。

你也可以直接修改项目文件将视图页面重新包含到项目中。

xoyozo 5 年前
2,826