简介:星期八在线考试系统是一套基于.NET8构建的开源、免费、跨平台企业级在线考试软件,面向高校、职业院校、党政机关培训中心及大型国企内部教育平台的技术选型与二次开发人员,用于解决多架构、多数据库环境下的考试组织与教学管理需求。资源包共2000个文件,约39.99MB,以376个cs源码、741个js脚本、167个css样式、481个png与80个gif界面素材为主,另含54个html页面、14个docx说明文档及sln、csproj工程文件,覆盖用户管理、题库、试卷生成、自动阅卷、成绩分析等完整模块。系统原生支持x64、x86、Arm64架构的Windows与Linux,兼容人大金仓、达梦、OceanBase及MySQL、SQL Server、PostgreSQL、SQLite等数据库,并集成JWT认证、RBAC+ABAC权限、防切屏与随机乱序等安全机制。目前已有68人学习下载,适合研究企业级.NET8分层架构、信创数据库适配与高并发考试场景的开发者参考借鉴。
1. 企业级在线考试软件:为什么 .NET 8 加国产数据库适配值得投入
去年帮一家三千人规模的制造企业做内部认证系统选型,信息中心负责人提了三个硬条件:必须能跑在已有的麒麟 Linux 和 Windows 混合环境上,必须适配他们刚采购的人大金仓数据库,必须支持车间里那批老旧的 x86 瘦客户端和新配的 Arm64 终端。当时市面上能同时满足这三条的在线考试软件,要么是 SaaS 按人头收费,要么是 Java 技术栈但数据库适配层写得极重,改造成本高得离谱。后来找到一套基于 .NET 8 开发的开源企业级在线考试软件,部署验证下来,x64、x86、Arm64 三种芯片架构的 Windows 和 Linux 都能跑,人大金仓、达梦、OceanBase 的适配也有现成方案,这才把项目推下去。这篇文章就把这套方案从选型理由到落地部署、从参数配置到踩坑排查,完整讲一遍。如果你也在找能自主可控、跨平台、支持国产数据库的考试系统,下面的内容应该能帮你省掉至少两周的试错时间。
2. 拆解 .NET 8 在线考试软件的技术底座:跨平台与国产数据库适配怎么选
2.1 为什么 .NET 8 是这类企业级考试软件的合适底座
在线考试软件的核心诉求其实就三条:并发稳、部署轻、维护省。.NET 8 在这三点上都有针对性改进。原生 AOT 编译能把启动时间压到毫秒级,对于考试这种集中开考、瞬间并发的场景,冷启动慢一秒都可能让几百个考生卡在登录页。跨平台方面,.NET 8 对 Linux 的 ARM64 支持已经进入官方长期支持通道,不是社区维护的边角料,这意味着在国产化终端上跑起来不用自己打补丁。
另一个容易被忽略的点是内存占用。同样支撑 500 人同时在线考试,Java 方案堆内存通常要配到 2GB 以上,.NET 8 在 Server GC 模式下 1GB 左右就能稳住。对于车间、教室这种边缘部署环境,服务器配置往往不高,省下来的内存就是实打实的硬件成本。
选型时我一般会看三个指标:目标框架是否 LTS、运行时是否提供自包含部署、数据库驱动是否支持国产库。.NET 8 是 LTS 版本,自包含部署可以把运行时打包进发布目录,目标机器不需要预装 .NET,国产数据库驱动方面,人大金仓和达梦都提供了 .NET Core 版本的官方驱动,OceanBase 也有 MySQL 兼容模式可以走。
2.2 跨平台部署的三种芯片架构怎么选发布方式
这套软件支持 x64、x86、Arm64 三种架构,但不是说随便打个包就能全平台跑。实际部署时要根据目标环境选对应的运行时标识符(RID)。下面这张表是我整理的各架构适用场景和发布命令对照。
| 芯片架构 | 操作系统 | 典型场景 | 发布 RID | 发布方式 |
|---|---|---|---|---|
| x64 | Windows Server | 中心机房 | win-x64 | 自包含 |
| x64 | Linux (麒麟/统信) | 中心机房 | linux-x64 | 自包含 |
| x86 | Windows | 老旧瘦客户端 | win-x86 | 框架依赖 |
| Arm64 | Linux (麒麟/统信) | 国产终端 | linux-arm64 | 自包含 |
| Arm64 | Windows | 部分国产 PC | win-arm64 | 自包含 |
发布命令以 linux-arm64 为例:
# 在项目根目录执行,-r 指定目标运行时,--self-contained 打包运行时 dotnet publish ./ExamSystem.Web/ExamSystem.Web.csproj \ -c Release \ -r linux-arm64 \ --self-contained true \ -p:PublishSingleFile=true \ -p:PublishTrimmed=false \ -o ./publish/linux-arm64这里PublishTrimmed建议设为 false。裁剪虽然能减小体积,但考试系统里用到的反射和动态加载比较多,裁剪后容易出现运行时找不到类型的玄学问题。PublishSingleFile把多个 DLL 合并成一个可执行文件,部署时拷贝一个文件加配置目录就行,适合现场实施人员操作。
2.3 人大金仓、达梦、OceanBase 的适配层怎么配
国产数据库适配是这套软件比较实在的地方。它没有把 SQL 写死在代码里,而是通过 EF Core 的 Provider 机制做了一层抽象。配置方式是在appsettings.json里指定数据库类型和连接串:
{ "Database": { "Type": "Kingbase", "ConnectionString": "Server=192.168.1.100;Port=54321;Database=examdb;User Id=system;Password=yourpassword;" } }Type字段可选值包括Kingbase、DM、OceanBase、SqlServer、MySql、PostgreSQL。切换数据库只需要改这个字段和连接串,不需要重新编译。人大金仓走的是 PostgreSQL 兼容协议,达梦有专门的 EF Core Provider,OceanBase 建议用 MySQL 模式连接。
注意:人大金仓的默认端口是 54321,不是 PostgreSQL 的 5432,连接串里别写错。达梦的 EF Core Provider 需要单独引入
Dm.EntityFrameworkCore包,版本要和 .NET 8 对齐。
数据库初始化脚本在Scripts目录下按数据库类型分文件夹存放,首次部署时执行对应目录下的建表脚本即可。如果遇到大小写敏感问题,人大金仓和达梦默认都是大写标识符,建表时建议统一用双引号包裹表名,或者在连接串里加CaseSensitive=false。
3. 从零部署一套 .NET 8 在线考试系统:环境准备与最小跑通路径
3.1 开发环境与运行时依赖清单
在动手之前,先把环境清单过一遍。这套系统对开发机的要求不高,但有几个依赖项容易漏。
开发环境需要 .NET 8 SDK,版本号建议 8.0.400 以上,低版本在发布 Arm64 自包含包时可能报缺少运行时包。数据库方面,本地开发可以用 Docker 跑一个 PostgreSQL 做临时验证,生产环境再切国产库。前端部分如果是前后端分离的版本,还需要 Node.js 18 以上。
运行时依赖分两种情况。自包含发布不需要目标机器装 .NET,但需要系统有对应的 C 运行库。Linux 上主要是libicu和libssl,麒麟 V10 和统信 UOS 默认都有,最小化安装的 CentOS 需要手动补。Windows 上 x86 版本如果走框架依赖发布,目标机器要装 .NET 8 Desktop Runtime。
检查命令:
# Linux 上确认 libicu 版本,.NET 8 要求 60 以上 ldconfig -p | grep libicu # 确认 openssl 版本 openssl version如果libicu版本低于 60,考试系统里的日期格式化和字符串比较会出问题,表现是考生交卷时间显示乱码或者排序错乱。解决办法是升级系统包或者设置环境变量DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1绕过 ICU,但这样会丢失部分国际化功能,只建议在实在无法升级的旧系统上用。
3.2 数据库初始化与连接串配置的四个关键参数
数据库初始化分两步:建库和建表。以人大金仓为例,先用管理员账号建一个空库,然后执行建表脚本。
# 连接人大金仓并创建数据库 ksql -U system -W yourpassword -h 192.168.1.100 -p 54321 -c "CREATE DATABASE examdb;" # 执行建表脚本 ksql -U system -W yourpassword -h 192.168.1.100 -p 54321 -d examdb -f ./Scripts/Kingbase/init.sql连接串里有四个参数直接影响考试系统的稳定性,我逐个说明。
Pooling=true必须开,考试开考瞬间会有大量连接请求,不开连接池的话数据库直接被打满。MinimumPoolSize建议设成 10,MaximumPoolSize设成 200,具体数值根据数据库服务器配置调整。Timeout=30是连接超时秒数,考试场景下建议设 30 到 60 之间,太短容易在数据库负载高时误报连接失败。CommandTimeout=120是命令执行超时,交卷时批量写入答案可能耗时较长,设太短会导致交卷失败。
{ "Database": { "Type": "Kingbase", "ConnectionString": "Server=192.168.1.100;Port=54321;Database=examdb;User Id=system;Password=yourpassword;Pooling=true;MinimumPoolSize=10;MaximumPoolSize=200;Timeout=30;CommandTimeout=120;" } }提示:达梦数据库的连接串参数名和人大金仓略有不同,
Pooling对应Pooling,但MinimumPoolSize要写成Min Pool Size,中间有空格。OceanBase 走 MySQL 模式时参数名和 MySQL 一致。
3.3 最小跑通验证:启动服务并完成一次模拟考试
环境配好后,用下面的命令启动服务:
# 进入发布目录 cd ./publish/linux-arm64 # 设置监听端口和数据库配置路径 export ASPNETCORE_URLS="http://0.0.0.0:5000" export ASPNETCORE_ENVIRONMENT="Production" # 启动服务 ./ExamSystem.Web启动后浏览器访问http://服务器IP:5000,默认管理员账号在appsettings.json的Admin节点下,首次登录后强制改密码。验证流程走一遍:创建考试、添加试题、导入考生、发布考试、考生登录答题、交卷、查看成绩。这七步走通,说明数据库读写、文件存储、会话管理都没问题。
如果启动时报数据库连接失败,先看日志目录下的logs/exam-*.log,里面会打印具体的连接错误码。人大金仓常见的错误码28P01是密码错误,3D000是数据库不存在。达梦的-70028是用户名密码错,-70019是表空间不足。
4. 考试系统高并发场景的参数调优与避坑记录
4.1 开考瞬间并发上不去?先查这三个配置
考试系统最典型的压力场景就是集中开考。五百人同时点进考试页面,如果配置没调好,表现是登录转圈、试题加载慢、甚至部分考生直接白屏。我遇到过三次类似问题,最后定位到的原因分别是连接池耗尽、会话状态存储瓶颈、静态资源重复加载。
连接池的问题在 3.2 节已经说了,这里补充一个细节:MaximumPoolSize不是越大越好。人大金仓单实例默认最大连接数是 100,你设 200 反而会导致部分连接被拒绝。正确做法是先查数据库的max_connections参数,应用侧设成它的 80% 左右。
会话状态默认存在内存里,单机部署没问题,但如果做了负载均衡,考生请求打到不同节点就会丢会话。解决办法是切到 Redis 或者数据库存储。配置方式:
{ "Session": { "Provider": "Redis", "RedisConnection": "192.168.1.101:6379,password=yourpassword,defaultDatabase=1" } }静态资源方面,考试页面的 JS 和 CSS 建议开启响应压缩和缓存。在Program.cs里加两行:
// 开启响应压缩 builder.Services.AddResponseCompression(options => options.EnableForHttps = true); // 开启静态文件缓存 app.UseStaticFiles(new StaticFileOptions { OnPrepareResponse = ctx => { ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=86400"); } });max-age=86400表示缓存一天,考试期间考生重复访问同一页面时直接从本地缓存加载,减少服务器压力。
4.2 国产数据库适配的五个血泪坑
这一节是我在人大金仓、达梦、OceanBase 上实际踩过的坑,每条按现象、原因、解决写。
坑一:自增主键不生效。现象是插入试题时主键冲突。原因是人大金仓默认用序列,但建表脚本里如果写了SERIAL类型,在部分版本上不会自动创建序列。解决是手动建序列并设置默认值:CREATE SEQUENCE exam_seq START 1; ALTER TABLE exam ALTER COLUMN id SET DEFAULT nextval('exam_seq');
坑二:分页查询结果错乱。现象是试题列表翻页时出现重复或遗漏。原因是达梦的LIMIT OFFSET语法和 PostgreSQL 不同,EF Core 生成的 SQL 在达梦上执行时 OFFSET 被忽略。解决是在 EF Core 里显式指定UseDm()并升级到 8.0 以上的 Provider 版本,或者在查询里用ROW_NUMBER()改写。
坑三:OceanBase 连接超时。现象是服务启动正常,但运行一段时间后报连接超时。原因是 OceanBase 的 MySQL 模式默认空闲连接回收时间较短,连接池里的连接被服务端断开了但客户端不知道。解决是在连接串里加ConnectionLifeTime=300,让连接池主动回收超过 5 分钟的连接。
坑四:中文排序不对。现象是考生姓名按拼音排序时顺序混乱。原因是人大金仓默认的排序规则是C,不识别中文拼音。解决是建库时指定ENCODING='UTF8' LC_COLLATE='zh_CN.UTF-8',或者查询时用ORDER BY CONVERT(name USING gbk)。
坑五:批量插入性能差。现象是导入五百个考生耗时超过三分钟。原因是 EF Core 默认逐条插入。解决是用AddRange加SaveChanges批量提交,或者直接用SqlBulkCopy的国产库对应实现。人大金仓可以用COPY命令,达梦用dmfldr工具。
4.3 考试过程中断网、断电的恢复策略
考试系统最怕的是考生答到一半断网或者断电。这套软件在客户端做了本地暂存,答题记录每隔 30 秒写一次localStorage,网络恢复后自动同步。服务端方面,交卷动作是事务性的,答案写入和状态更新在同一个事务里,不会出现答案写了一半状态没改的情况。
但有一个场景需要额外注意:考生点击交卷后、服务端返回成功前断网。这时候客户端会显示交卷失败,但服务端可能已经写入成功。解决办法是在交卷接口里加幂等设计,用考生 ID 加考试 ID 作为唯一键,重复交卷请求直接返回上次结果。
-- 交卷记录表加唯一约束 ALTER TABLE exam_submission ADD CONSTRAINT uk_exam_user UNIQUE (exam_id, user_id);这样即使考生重复提交,数据库层面也会拦住,不会产生两条交卷记录。
5. 进阶技巧:用健康检查与灰度发布把考试系统运维做扎实
5.1 给考试系统加健康检查端点
考试系统上线后,运维最需要的是一个能快速判断服务是否正常的接口。.NET 8 内置了健康检查中间件,加几行代码就能用。
// Program.cs 里注册健康检查 builder.Services.AddHealthChecks() .AddDbContextCheck<ExamDbContext>("database") .AddCheck("self", () => HealthCheckResult.Healthy()); // 映射端点 app.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = async (context, report) => { context.Response.ContentType = "application/json"; var result = new { status = report.Status.ToString(), checks = report.Entries.Select(e => new { name = e.Key, status = e.Value.Status.ToString(), duration = e.Value.Duration.TotalMilliseconds }) }; await context.Response.WriteAsJsonAsync(result); } });访问/health返回 JSON,status为Healthy表示数据库连接正常。如果数据库挂了,database这项会变成Unhealthy,运维可以直接配监控告警。AddDbContextCheck会执行一条轻量查询验证数据库连通性,不会对考试业务造成压力。
5.2 灰度发布:先让一个考场用上新版本
考试系统更新不能一刀切,万一新版本有 bug,全部考场同时翻车就是事故。灰度发布的思路是先让一个考场切到新版本,观察半小时没问题再全量。
具体做法是在负载均衡器上按考生来源 IP 或者考场 ID 做分流。如果用的是 Nginx,可以按请求头里的考场标识转发:
upstream exam_new { server 192.168.1.10:5000; } upstream exam_old { server 192.168.1.11:5000; } server { listen 80; location / { if ($http_x_exam_room = "room_001") { proxy_pass http://exam_new; } proxy_pass http://exam_old; } }考场 001 的客户端请求会带上X-Exam-Room: room_001请求头,Nginx 把它转发到新版本节点,其他考场继续走旧版本。观察新版本节点的日志和数据库慢查询,确认没有异常后再把exam_old也升级。
5.3 我踩过的发布翻车教训
有一次给客户升级版本,我图省事直接全量替换了发布目录,结果新版本的一个数据库迁移脚本在人大金仓上执行失败,导致整个考试系统起不来。当时离正式考试只剩两个小时,最后是靠备份的旧版本目录紧急回滚才没出大事。从那以后我养成了一个习惯:每次发布前先把旧版本目录整个复制一份到backup文件夹,命名带上时间戳,回滚时直接改软链接指向旧目录,十秒内完成切换。
另一个习惯是数据库迁移脚本先在测试库跑一遍,确认没有语法兼容问题再上生产。人大金仓和达梦对ALTER TABLE的支持和 PostgreSQL 有细微差别,比如达梦不支持ALTER COLUMN TYPE直接改类型,要先加新列再导数据。这些细节在测试库跑一次就能发现,比在生产上翻车强得多。
这套基于 .NET 8 的在线考试软件,从跨平台部署到国产数据库适配,再到高并发调优和灰度发布,整体落地路径是清晰的。如果你正在做类似选型,建议先用一台 Arm64 的麒麟机器加人大金仓跑通最小验证,确认芯片架构和数据库兼容性没问题,再往生产环境推。希望帮到你。
本文还有配套的精品资源,点击获取