
简介一款基于 ASP.NET 的 H5 手机端问卷调查平台完整源码面向需要快速搭建在线问卷系统的企业、个人运营者也适合学习 WebForms 开发的程序员。系统实现用户注册登录、个人中心问卷列表、创建编辑删除分享、启用停用以及问卷结果查看与 Excel 导出等完整闭环受访者可通过分享链接直接参与投票移动端页面友好便于现场扫码或社交传播。包内含 1232 个文件压缩包 38.43MB其中 cs 代码为后端业务逻辑aspx 与 ashx 负责页面和接口响应css、js 控制前端交互与样式png、jpg、gif 是界面图片素材另有少量视频、字体等资源目录结构清晰便于定位功能模块。已有 839 人学习适合作为问卷类产品的开发参照或用于毕业设计、接单项目的基础框架能直观理解从问卷发布、数据收集到统计导出的完整实现方式。1. 从一次满意度调研说起aspnet 问卷源码能解决什么要做员工满意度调研客户给的条件是H5 链接直接发到企业微信群里手机打开就能答数据必须留在自己的服务器上最好还能对接组织架构。这套需求放在H5手机端免费问卷调查平台系统aspnet源码这类项目面前几乎就是照着需求画像写的。它不依赖腾讯问卷、金数据这类现成 SaaS而是把整套问卷后台和手机端答卷页面以源码形式交付部署到你自己的 Windows 服务器上数据落在自己的数据库里。免费的意思不是功能少而是你拿到全部代码自己部署、自己维护。代价是安装、安全加固、二次开发都得自己扛。适合三类人小团队想搭内部调研工具外包接单要给客户交付问卷系统运营部门想要一个数据不出门的采集平台。后面我会从源码结构、部署步骤、H5 适配和常见坑四个层面把它讲透。2. 拆解 aspnet 问卷平台源码从问卷编辑到数据报表的完整链路2.1 三层架构与技术选型为什么是 aspnet 而不是 Node/PHP拿到这类 aspnet 免费源码解决方案里项目通常不多。常见组成是一个 MVC 站点管后台管理和 H5 页面一个 Web API 项目接答卷提交和统计接口数据层用 EF6 的 DbContext 或 SqlHelper 直连数据库。前端是 jQuery Bootstrap 3 这类老牌组合手机端能自适应统计页用 ECharts 画饼图和柱状图。技术老不老不重要问卷页面生命周期短这套组合加载够快、兼容性稳微信内置浏览器里几乎不用额外适配。为什么选 aspnet 而不是 Node 或 PHP多数中小企业的服务器是 Windows IIS部署 aspnet 是原生操作客户运维不用接触命令行数据库普遍是 SQL Server和 aspnet 配套最省事后续要对接 OA、HR、ERP.NET 生态的对接成本远低于 Node。PHP 的免费问卷源码也有但老代码居多SQL 注入和文件上传校验经常要自己翻一遍坑比 aspnet 更密。和 aspnet zero 这类商业模板对比差距一眼能看穿zero 带多租户、权限体系、审计日志但那是收费授权免费源码的权限模型通常只有“管理员/普通用户”两个角色异常处理简单没有单元测试。选它等于选了骨架完整但细节自己焊。做内部工具和中小客户交付够用做对外商业 SaaS 就别指望了。接手第一件事也不是看功能而是确认解决方案里有几个项目、目标框架是 4.5 还是 4.6。2.2 核心数据表设计问卷、题型、答卷与答案的关系问卷调查系统的数据模型高度统一不管前端怎么换皮肤后端绕不开下面五张表表名作用关键字段Questionnaire问卷主表Id、Title、Description、Status、StartTime、EndTime、CreatorIdQuestion题目表Id、QuestionnaireId、Type、Title、IsRequired、SequenceQuestionOption选项表Id、QuestionId、OptionText、SequenceAnswer答卷主表Id、QuestionnaireId、UserId、SubmitTime、IpAddressAnswerDetail答卷明细表Id、AnswerId、QuestionId、OptionId、ContentStatus 字段用 int 控制三态0 草稿、1 发布、2 关闭。H5 端访问接口先查 Status不是发布状态直接拒绝答卷。AnswerDetail 设计得比较巧妙选择题存 OptionId填空和评分题存 Content多选时一个选项一行记录。统计的时候直接按 OptionId JOIN 选项表算占比不用去拆逗号拼接的字符串性能和写法都干净得多。这种表结构对扩展题型非常友好。要加一个 NPS 评分题不用改表结构Question.Type 加一个枚举值Content 存 0 到 10 的数字要加矩阵题行列维度用 QuestionOption 区分即可。免费源码常见的做法是先扩展 Type 枚举明细表通用性足够不必为了单类题型加表。2.3 从创建问卷到生成分享链接请求链路里的三个关键动作整条链路由三个动作组成后台创建问卷写入题库发布时生成 H5 链接H5 页提交答卷。创建问卷最核心的是事务题目和选项必须和问卷主表同时落库否则编辑一半报错留下一张只含标题的废问卷。下面这段代码是典型的 MVC 写法[HttpPost] public ActionResult Create(string json) { // 前端把问卷标题、起止时间、题目和选项序列化成 JSON 传过来 var input JsonConvert.DeserializeObjectQuestionnaireInput(json); if (input null || string.IsNullOrWhiteSpace(input.Title)) { return Json(new { code 0, msg 问卷标题不能为空 }); } var questionnaire new Questionnaire { Title input.Title, Description input.Description, Status 0, // 0草稿发布后才能被 H5 访问 StartTime input.StartTime, EndTime input.EndTime, CreateTime DateTime.Now }; // 题目和选项在同一事务里写入防止半截数据 using (var tx db.Database.BeginTransaction()) { db.Questionnaires.Add(questionnaire); db.SaveChanges(); foreach (var q in input.Questions) { var question new Question { QuestionnaireId questionnaire.Id, Type q.Type, Title q.Title, Sequence q.Sequence }; db.Questions.Add(question); db.SaveChanges(); foreach (var opt in q.Options) { db.QuestionOptions.Add(new QuestionOption { QuestionId question.Id, OptionText opt.Text, Sequence opt.Sequence }); } } db.SaveChanges(); tx.Commit(); } return Json(new { code 1, id questionnaire.Id, msg 创建成功 }); }代码逻辑不复杂重点是事务边界题目保存后拿自增 Id再写选项的外键。如果源码的数据层是 SqlHelper 而不是 EF把 BeginTransaction 换成 SqlTransaction 包住三条 INSERT 即可。Sequence 字段控制排序编辑页面按 Sequence 升序取题目改顺序就是改这个值。H5 提交答卷的接口思路相反先查问卷状态再写 Answer 主表拿自增 Id最后循环写 AnswerDetail。性能敏感的话用 AddRange 一次性提交而不是每条 SaveChanges。统计页的饼图数据直接用一条 group by 加 count 完成不需要额外存储过程。3. 把 aspnet 问卷源码跑在本机编译、数据库初始化与 IIS 部署3.1 用 Visual Studio 编译源码前先核对五个环境项免费源码拿回来别急着改代码第一步是在本机把它跑起来。我先核对五件事第一解决方案的目标框架版本常见是 .NET Framework 4.5 或 4.6VS2019/2022 没装对应开发包会直接报错去 Visual Studio Installer 里补一下第二NuGet 包还原源码如果没带 packages 目录右键解决方案选“还原 NuGet 程序包”第三SQL Server 版本2008R2 以上都行但如果脚本里用了 IIF 这类新语法最低要 SQL Server 2012第四确认 App_Data 目录存在很多免费源码把数据库文件放在这里第五先用 IIS Express 调试跑通再考虑正式 IIS一次少引入一个变量。提示免费源码最忌讳拿回来就改业务逻辑。第一次编译的唯一目标是让它按原样跑起来改恶从善放到部署成功以后。3.2 初始化数据库执行 SQL 脚本还是附加 MDF源码包常见两种数据库交付形态一种是 .sql 脚本另一种是 .mdf 数据库文件。脚本方式最可控能看到建表顺序和数据初始化过程。用 SSMS 打开脚本对 master 执行或者用命令行 sqlcmd 跑。先建库、建登录名、授权三步分开-- 1. 创建数据库 CREATE DATABASE SurveyDB; GO -- 2. 建登录名密码按自己环境改后面 Web.config 要对应 CREATE LOGIN survey_user WITH PASSWORD Your_Strong_Pass_2024; GO USE SurveyDB; GO -- 3. 给登录名映射到当前库并赋权 CREATE USER survey_user FOR LOGIN survey_user; GO EXEC sp_addrolemember db_owner, survey_user; GO注意三个批次用 GO 分隔顺序不能乱。sp_addrolemember 直接给了 db_owner免费系统图省事正式环境建议最小权限给 db_datareader 和 db_datawriter 够用。密码别用 123456服务器暴露在公网上很容易被扫。如果是 .mdf 文件在 SSMS 里附加或者放进 App_Data 目录让 EF 自动创建。附加后最常见的问题是数据库只读原因是 SQL Server 进程对 mdf 和 ldf 文件没有写权限。解决方法是给数据库文件所在目录加上 SQL Server 服务账户的读写权限改完重启 SQL Server 服务。3.3 修改 Web.config 连接串与三个常用配置项数据库准备好之后修改连接串和站点配置。连接串要和上一步创建的登录名一一对应不然启动报“无法打开数据库”connectionStrings add nameSurveyDb connectionStringServerlocalhost;DatabaseSurveyDB;User Idsurvey_user;PasswordYour_Strong_Pass_2024;Trusted_ConnectionFalse providerNameSystem.Data.SqlClient / /connectionStrings appSettings !-- 问卷 H5 的访问根地址分享链接和二维码都基于它拼接 -- add keySiteUrl valuehttp://demo.example.com / !-- 上传文件保存的物理路径 -- add keyUploadPath valueC:\inetpub\wwwroot\SurveySite\Uploads / !-- 问卷默认过期天数 -- add keyDefaultExpireDays value30 / /appSettings连接串里 Trusted_ConnectionFalse 表示用账号密码登录如果你本机 SQL Server 只开了 Windows 身份验证改成 True 并删掉 User Id 和 Password 两行。SiteUrl 这个配置最坑很多源码默认写 localhost部署后忘了改手机扫出来的分享链接全打不开。UploadPath 对应后续上传题的保存目录要给 IIS 应用程序池身份写权限否则上传功能必挂。DefaultExpireDays 决定问卷默认关闭时间按调研周期调整。3.4 发布到 IIS应用程序池、写入权限与验证闭环本机跑通后发布到正式 IIS。VS 里右键项目选“发布”目标选文件夹输出到站点目录比如 C:\inetpub\wwwroot\survey。IIS 里新建应用程序池.NET CLR 版本选 v4.0托管管道模式选“集成”经典模式下 MVC 路由经常 404这一点很多人翻过车。站点物理路径指向发布目录绑定好域名和端口。接下来给 Uploads 目录加 IIS_IUSRS 写权限SQL Server 如果用的是 Windows 身份验证还要给应用程序池身份授权对应数据库。最后做完整验证闭环浏览器打开后台登录创建一个三题的问卷发布后用手机访问 H5 链接提交一份答卷回到后台统计页确认能查到记录。这个闭环通了部署就算完成后面再折腾二次开发。4. H5 手机端适配与微信兼容让问卷链接不在手机里翻车4.1 viewport 与 rem 适配移动端不缩放的第一道门槛手机打开问卷如果是一片缩小到看不清的桌面页面基本就是缺 viewport。手机浏览器默认按 980px 宽渲染页面没有 viewport meta文字小到需要双指缩放。问卷页面必须在 head 里加上这个meta nameviewport contentwidthdevice-width, initial-scale1, maximum-scale1, minimum-scale1, viewport-fitcover /widthdevice-width 让布局宽度等于屏幕宽度viewport-fitcover 适配 iPhone 刘海屏和底部横条。我一般会去掉 user-scalableno不要完全禁用缩放可访问性更好也能避免部分 iOS 版本对禁用缩放的奇怪表现。布局上免费源码常见的适配方案是 rem脚本动态设置根字号(function (doc, win) { var docEl doc.documentElement, resizeEvt orientationchange in window ? orientationchange : resize, recalc function () { var clientWidth docEl.clientWidth; if (!clientWidth) return; // 750 是设计稿宽度按你的设计稿改 docEl.style.fontSize (clientWidth / 750) * 100 px; }; if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); doc.addEventListener(DOMContentLoaded, recalc, false); })(document, window);根字号等于屏宽除以 750 再乘 100这样设计稿里 1px 对应 0.01rem还原最方便。如果源码用的是 Bootstrap 栅格而不是 rem也可以不换两种方案都能做移动端适配但不要混用否则字号会被双重缩放。设计稿宽度参数要跟 UI 实际稿子一致拿 375 宽的稿子按 750 算所有字号会大一倍。4.2 微信内置浏览器的三个高频问题input 放大、重复刷新与 fixed 掉底微信内置浏览器占了问卷流量的绝对大头这里的问题也最集中。第一个高频问题iOS 微信里点输入框页面自动放大。原因是 iOS Safari 对字号小于 16px 的表单控件会强制聚焦放大这是系统的可访问性设计躲不掉。解法是给表单元素统一指定字号input, textarea, select { font-size: 16px; /* iOS 微信里小于 16px 会聚焦放大必须顶到 16px */ }副作用是表单字体比正文大一圈视觉上略微突兀但换来的是不被用户骂“一点输入就乱跳”。如果你用 rem 控制全局字号注意别在 reset 里把 input 字号又盖回去。第二个问题是 iOS 微信里 H5 偶尔重复刷新页面闪白一下。常见原因是 JSSDK 注入时机和页面渲染逻辑打架或者前端用了 location.reload 轮询。分享配置那类代码里取当前页面地址时要用 location.href.split(#)[0] 截断否则 hash 变化会触发重复刷新。前端如果用 uniapp 打包 H5重新加载页面用 uni.reLaunch 而不是 location.reload效果可控得多。第三个问题是 fixed 定位的底部提交按钮iOS 键盘弹起时按钮会飘到键盘上方挡住内容。免费源码里最常见的就是这个布局。解法是底部操作栏不用 fixed改用 flex 布局放在页面流里如果一定要 fixed监听 focusin 和 focusout 事件键盘弹出时把按钮挪到不可见区域收起时再恢复。问卷这种长表单页面滚动到底部再提交本身更符合手机操作习惯。4.3 问卷带图片上传题的 H5 写法FormData 上传而不是 blob 下载不少问卷会加一题“请上传相关截图”很多人问 H5 的 blob 文件能上传吗答案是能但要注意移动端的兼容行为。H5 里正确的做法是 input file 拿到 File 对象用 FormData POST 到后端接口返回 URL 存进隐藏域等用户点提交时随问卷一起入库var fileInput document.getElementById(uploadInput); var hiddenUrl document.getElementById(answerFileUrl); fileInput.addEventListener(change, function () { var file this.files[0]; if (!file) return; var fd new FormData(); fd.append(file, file); fetch(/api/survey/upload, { method: POST, body: fd }).then(function (res) { return res.json(); }) .then(function (data) { if (data.code 1) { // 上传成功把 URL 存进隐藏域随问卷一起提交 hiddenUrl.value data.url; } else { alert(data.msg); } }); });fetch 跨域时会遇到同源策略所以部署架构上尽量让 H5 页面和 Web API 同域省掉跨域配置。后端接收时用 HttpPostedFileBase存到 UploadPath 配置的目录返回相对路径。校验必做两件事file.size 限制在几 MB 内file.type 限制图片格式否则微信里可以直接传一个 200MB 的视频上来把服务器磁盘打满。iOS 上另一个与 blob 相关的坑是下载行为问卷系统导出报表时如果前端用 a 标签加 blob 方式触发下载iOS 上经常变成“打开一个新页面预览文件”而不是下载。正确姿势是后端生成文件后返回 URL前端用 window.open 或者后端在响应头里指定 Content-Disposition: attachment把下载交给系统处理。5. aspnet 问卷源码部署避坑5 个翻车现场与排查顺序免费源码拿回来后环境各不相同坑是排着队来的。下面 5 个是 Windows 服务器上跑问卷系统最高频的翻车现场按出现频率排你遇到的基本都在里面。5.1 后台正常手机访问问卷链接 404现象电脑上打开后台一切正常手机微信里点问卷链接报 404换浏览器也一样。原因两个来源最常见。一是 IIS 应用程序池的托管管道模式选成了“经典”MVC 路由根本没进 aspnet 的管道二是 Web.config 里的 SiteUrl 还是 localhost 或内网 IP生成的分享链接手机根本够不着。解决先把应用程序池改成“集成”模式回收站点再试。如果还是 404改 SiteUrl 为正式域名后重新发布再重建问卷或把已有问卷的状态切一下草稿再发布让链接重新生成一遍。IIS 在这种时候像个黑匣子但九成是这两种情况再不行去 IIS 请求日志确认请求是否走到了 aspnet。5.2 附加数据库后登录失败文件只读与登录模式现象源码包是 .mdf附加到 SQL Server 后后台登录提示“用户 sa 登录失败”或“无法打开数据库文件只读”。原因连接串写死了 SQL 账号密码但你本机 SQL Server 可能只开了 Windows 身份验证模式文件只读则是 SQL Server 进程对 mdf 和 ldf 没有写权限。解决打开 SQL Server Management Studio实例右键属性安全性里改成“SQL Server 和 Windows 身份验证模式”重启服务。连接串不想改的话这一步就能解决登录失败。文件只读则要给数据库文件所在目录加 SQL Server 服务账户的读写权限。改完这两处后台登录一般就通了。5.3 微信里快速点两下后台出现重复答卷现象同事在微信里提交问卷网络卡一下他多点了一次提交统计里出现两条时间戳几乎一样的答卷。原因前端按钮没有防重后端也没有幂等控制。两次请求都通过了校验各写了一条 Answer 和若干 AnswerDetail。解决前端提交按钮置灰加 loading这只是用户体验层面的止血。后端防重入才是关键给 Answer 表建组合唯一约束并在写入前查重var exists db.Answers.Any(a a.QuestionnaireId input.QuestionnaireId a.DeviceToken input.DeviceToken); if (exists) { return Json(new { code 0, msg 您已经提交过这份问卷 }); }DeviceToken 在前端生成并存在 localStorage每次答卷带上来。这个方案只能挡同一设备的重复提交挡不了恶意刷单。如果问卷涉及积分或现金奖励再用 Redis 计数器或图形验证码单靠数据库防重入不够。5.4 导出 Excel 报“检索 COM 类工厂失败”现象本机调试导出报表正常发布到服务器后一点导出就报错日志里是“检索 COM 类工厂失败”。原因源码导出功能用了 Excel COM 组件也就是 Microsoft.Office.Interop服务器没装 OfficeIIS 进程在系统账户下也调不到 DCOM。这是免费 aspnet 源码特别喜欢踩的雷本机装了 Office 所以没事服务器上必炸。解决把导出实现重写成 NPOI纯托管库不依赖 Office。改动量不大Workbook 换成 XSSFWorkbook单元格写入逻辑基本平移行高样式需要适配一下。这是免费源码里最值得优先改的地方COM 方案在服务器上没有后悔药迟炸不如早炸。5.5 H5 单独部署后提交问卷报 Network Error现象后台在 IIS 默认站点H5 页面单独放在另一个端口或域名。页面加载正常点提交就报 Network Error 或 Failed to fetch。原因浏览器同源策略H5 页面和 Web API 不在同一个源接口响应没有 CORS 头。免费源码默认不处理跨域本机调试时 IIS Express 端口一致所以没暴露部署分离后立刻现形。用 uniapp 打包 H5 放静态服务器、后端留在 Windows 的架构也会撞上同一个问题。解决在后端 Web.config 的 system.webServer 节点里加 CORS 响应头httpProtocol customHeaders add nameAccess-Control-Allow-Origin valuehttps://h5.example.com / add nameAccess-Control-Allow-Methods valueGET,POST,OPTIONS / add nameAccess-Control-Allow-Headers valueContent-Type / /customHeaders /httpProtocolvalue 写你实际放行的 H5 域名不要写星号。带 Cookie 的请求还要补 Access-Control-Allow-Credentials 并设为 true。更省事的方案是把 H5 静态文件也放到同一个站点下完全避免跨域。我一般优先同域部署跨域配置留着给那些实在没法合并的架构。6. 把问卷 H5 接进企业微信免登录与分享卡片改造6.1 企业微信 OAuth 免登录员工打开即答企业内部问卷最烦的就是登录。接企业微信 OAuth 后员工在企业微信的客服消息或应用入口点开链接自动识别身份问卷里直接带上部门和姓名完全不用输入账号。核心流程三步前端检测未登录就跳转企业微信授权地址企业微信回调带 code后端拿 code 换 userid然后以该身份允许答卷。public ActionResult OAuthCallback(string code, string state) { if (string.IsNullOrEmpty(code)) { return RedirectToAction(Index, Survey, new { msg 授权失败 }); } // 用 code 换 useridaccess_token 需要提前获取并缓存 var token GetAccessToken(corpId, corpSecret); var url https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token token code code; var userid GetUserIdFromApi(url); // 简易会话这里用 Session 记录身份正式环境建议换 JWT Session[UserId] userid; return RedirectToAction(Fill, Survey, new { id state }); }state 参数携带问卷 Id回调后直接带到填写页。corpId 和 corpSecret 放进 Web.config不要写死在代码里。GetAccessToken 必须做缓存企业微信的 access_token 有效期 7200 秒频繁请求会被限流这个缓存没有的话用户一多就间歇性报错。redirect_uri 要 URLEncode域名还得在企业微信后台配置成可信域名否则回调直接打不开。6.2 JS-SDK 分享卡片问卷进群不再是裸链接默认分享到微信群的问卷链接只有标题和摘要图片经常抓错。用 JS-SDK 可以自定义分享卡片的标题、描述和缩略图。后端需要先取 jsapi_ticket再按参数生成签名前端注入 wx.config参数取值说明timestamp当前秒级时间戳nonceStr随机字符串signaturesha1 签名输出url当前页面完整地址必须用 location.href.split(#)[0]签名用的 url 是最容易翻车的地方用了带 hash 的完整地址会导致签名校验失败。后端拿到 jsapi_ticket 后同样缓存 7200 秒。配置完成后问卷链接在群里看起来才像一个正式应用卡片而不是一串裸 URL。做了几年这类免费源码的落地改造我养成了一个习惯任何问卷系统拿到手第一件事不是看功能列表而是先跑通“后台建卷、手机答卷、后台出报表”的最小闭环。免费源码最大的不确定性不在功能而在你永远不知道哪一段代码是从哪个项目里拷过来的改之前先把数据库脚本备份下来这是最便宜的后悔药。把防重入、跨域、企业微信免登录这三件事补上之后这套 aspnet 问卷系统对付内部调研和中小客户交付已经够用。希望帮到你。本文还有配套的精品资源点击获取