
简介基于C#与SQL Server的学生信息管理系统完整源码包采用经典三层架构UI层、业务逻辑层、数据访问层前端综合运用BootStrap、Vue与AjaxPro技术覆盖登录认证、班级管理、专业管理、学生信息维护及学籍状态管理等典型业务面向需要完成课程设计或毕业设计的.NET方向学习者也适合作为企业开发入门参考。压缩包共457个文件整体约11.59MB其中172个.cs源码文件、9个.aspx页面、12个.csproj工程文件清晰构成项目主干配套dll、resx、config等支撑运行与资源本地化js/css/png/jpg等前端素材用于界面展示另含数据库备份及SQL脚本可快速还原数据库并启动项目。资源组织规范、目录层次完整便于按模块研读。目前该资源已有93人学习下载对于想深入理解三层架构思想、掌握ASP.NET Web Forms与前端组件协作方式的开发者而言是一份难得的完整工程示例。1. 学生信息管理系统一个 C# 老项目为什么到现在还有参考价值如果你正在找一个能直接改的 C# 项目源代码而不是那种只讲语法和单页 Demo 的教程这个学生信息管理系统值得花时间拆一遍。它走的是老牌的 ASP.NET WebForm 路线数据层落在 SQLServer 上中间套着经典的 UI、BLL、DAL 三层架构前端同时用 BootStrap 做布局、Vue 做局部渲染异步更新则靠 AjaxPro 把前端方法和后端 C# 方法直接打通。这套组合看起来有点混搭但在真实的企业内网系统、高校毕业设计和中小型管理软件里非常常见业务逻辑不复杂但要求你能快速改出增删改查、条件查询、分页、权限这些功能。适合正在学 .NET 的初学者、需要短期交付管理系统的开发者以及还在接手 WebForm 老项目、每天跟 .aspx 页面打交道的维护者。源码包已经放在了文末建议先下载到本地下面每一步我都对着实际代码讲你照着改就能用。2. 三层架构与 AjaxPro先搞懂这套组合拳再动手改代码老项目最怕一上来就翻页面先把骨架看懂后面改哪里都是顺理成章的事。这个学生信息管理系统的代码结构是按标准的 ASP.NET WebForms 三层拆的。2.1 三层架构在 WebForm 项目里的真实划分UI、BLL、DAL 各管什么很多人学三层架构只记了概念真打开项目就懵。这个项目的分层非常直观UI 层是 Web 项目根目录下的 .aspx 页面和它们的 .aspx.cs 后台类负责接收用户输入、显示数据、调用业务层BLL 层放的是业务逻辑比如计算学生总评成绩、判断学号是否重复、校验删除前有没有关联成绩DAL 层只做一件事——和 SQLServer 打交道写 SQL、执行命令、返回 DataTable 或实体集合。此外项目里通常还会有一个 Model 或 Common 类库用来放学生、班级、成绩这些实体类和公共工具。理解这个分层的关键是看引用关系UI 引用 BLLBLL 引用 DALUI 不直接引用 DAL。如果你打开代码发现某页面的后台代码里直接 new 了一个 SqlConnection那就是架构被破坏了。为什么老项目坚持这么拆最直接的原因是可换性和可读性。数据库从 SQLServer 换到 MySQL只需要重写 DAL 层BLL 和 UI 基本不动业务规则变了只改 BLLUI 想从 WebForm 换成 MVC只要 BLL 接口稳定后面一大堆页面可以分批替换。这个项目的 BLL 方法命名也很有代表性比如 AddStudent、UpdateStudent、DeleteStudent、GetStudentPageList每个方法对应一个事务单元。举个例子public class StudentManager { private readonly StudentDAL dal new StudentDAL(); public bool AddStudent(StudentModel student) { if (string.IsNullOrEmpty(student.StudentNo)) throw new Exception(学号不能为空); if (dal.Exists(student.StudentNo)) throw new Exception(学号已存在); return dal.Insert(student) 0; } }代码里先做业务校验再调 DAL 方法。这个思路新手一定要跟着写把校验放在 BLL不是放在页面贴代码里。否则同样的校验在添加页面写一遍、编辑页面又写一遍后期改规则能改到你怀疑人生。2.2 AjaxPro让前端直接调用后端方法的老牌利器AjaxPro 是很多年前流行的 ASP.NET AJAX 库原理是注册一下类型然后前端 JavaScript 就能直接调用后端 C# 公有方法返回值会自动序列化成 JSON 传到浏览器。这个项目用它来处理学号唯一性校验、级联下拉框、异步删除这些操作。用起来非常简单但有几个关键点不标出来必踩坑。第一步在页面的 Page_Load 里注册类型protected void Page_Load(object sender, EventArgs e) { AjaxPro.Utility.RegisterTypeForAjax(typeof(StudentPage)); }第二步给需要被前端调用的方法打上标记注意方法必须是 public且返回类型不能是 DataTable 这类复杂对象最好返回字符串或简单实体[AjaxPro.AjaxMethod] public static string GetClassByDepartmentId(string departmentId) { ClassManager manager new ClassManager(); ListClassModel list manager.GetClassesByDepartment(departmentId); System.Web.Script.Serialization.JavaScriptSerializer serializer new System.Web.Script.Serialization.JavaScriptSerializer(); return serializer.Serialize(list); }第三步前端用 AjaxPro 生成的对象调用不需要自己写 XMLHttpRequestAjaxPro.StudentPage.GetClassByDepartmentId(pid, function (result) { if (result.error) { alert(result.error.Message); return; } var classes JSON.parse(result.value); // 交给 Vue 或 DOM 更新下拉框 });这里的回调函数必须只接收一个 result 参数result.value 是后端方法返回值。我见过很多新手在这里写第二个参数当返回值结果拿到的是 undefined。另外 AjaxPro 的方式是 WebForm 时代的东西如果你用的是较新框架版本引用的 AjaxPro.dll 要注意和 .NET Framework 版本匹配否则回调不执行。2.3 数据访问层SQLServer 连接与参数化查询的写法DAL 层最重要的是不要拼字符串SQLServer 注入的坑大多数是拼接 SQL 拼出来的。这个项目的通用数据访问类会提供 ExecuteQuery、ExecuteNonQuery 等方法用 SqlParameter 把值传进去。我建议你拿到资源后直接搜索 SqlHelper找到后检查它是不是用了参数化。典型写法public DataTable GetStudentsByClass(string className) { string sql SELECT StudentNo, StudentName, Sex, BirthDate FROM Student WHERE ClassName ClassName; SqlParameter[] parameters { new SqlParameter(ClassName, SqlDbType.NVarChar, 50) { Value className } }; return SqlHelper.ExecuteDataTable(sql, parameters); }这里注意两点一是 SQLServer 连接字符串放在 web.config 里不要写死在类中connectionStrings add nameSchoolDB connectionStringData Source.;Initial CatalogSchoolDB;Integrated SecurityTrue providerNameSystem.Data.SqlClient / /connectionStrings二是在 SQLServer 里处理数字转换、字符串拼接时也可以用参数化。比如热词里很多人搜sqlserver 字符串转数字这类需求在查询学生成绩排名时常见你可以在 SQL 里写WHERE CAST(Score AS INT) 60但如果 Score 字段里混了非数字CAST 会直接报错SQLServer 2012 以上的 TRY_CAST 能返回 NULL 而不是报错老项目代码里一般不会主动用你接手时可以顺手优化。3. 把项目跑起来从 SQLServer 还原到 IIS 部署的完整步骤光看代码没意义先把项目跑通再动手改。这一章是给第一次接触这个项目的人准备的环境搭配和操作顺序都讲清楚。3.1 环境准备版本搭配与安装顺序这个项目是基于 .NET Framework 4.0 或更高版本写的 WebForm 应用IDE 用 Visual Studio 2015 以上都能打开SQLServer 用 2008 R2、2012、2014、2016 都行推荐 SQLServer 2016 或 2019主要区别在兼容性和安装便利性。操作系统建议 Windows 10/11 专业版或 Windows Server。安装顺序有讲究先装 SQLServer再装 Visual Studio最后配置 IIS。如果你先装了 VS 再装 SQLServerVS 里的 SQL Server 工具连接时会提示版本不一致。很多人在sqlserver安装教程里踩过一个典型的坑SQLServer 2016/2017/2019 安装完成后服务起不来报无法找到数据库引擎启动句柄。这个大概率是安装时服务账户配置有问题或者本机已有 SQLServer 实例冲突。解决思路是重新打开 SQLServer 配置管理器把 SQL Server 服务改为 LocalSystem 或 Network Service手动启动如果还不行检查安装日志里有没有权限问题。3.2 数据库还原与连接字符串配置拿到资源后数据库文件一般两种形式一种是 .bak 备份文件另一种是 .sql 脚本。用 .bak 还原最简单打开 SQLServer Management Studio右键数据库→还原数据库源设备选择 .bak 文件目标数据库名建议和项目里面写的一致一般是 SchoolDB 或 StudentDB。如果项目里只给了 .sql 脚本就新建数据库后执行脚本注意脚本开头可能有 USE 语句执行前先确认当前库。还原完成后打开项目的 web.config把 connectionStrings 里的 Data Source 和 Initial Catalog 改成你本机的实际情况。我一般会顺手把连接字符串放在一个单独的节点里方便后面部署时替换connectionStrings add nameSchoolDB connectionStringData Sourcelocalhost\\SQLEXPRESS;Initial CatalogSchoolDB;Integrated SecurityTrue providerNameSystem.Data.SqlClient / /connectionStringsIntegrated SecurityTrue 表示用 Windows 登录验证好处是本机调试不用管密码但部署到服务器后如果应用池身份没有权限会报用户登录失败。那时可以改成 SQL 账号登录更可控add nameSchoolDB connectionStringData Source服务器IP;Initial CatalogSchoolDB;User IDsa;Password你的密码 providerNameSystem.Data.SqlClient /改完连接字符串先编译一遍项目F5 跑起来看看登录页是否正常跳转。如果报找不到指定的模块或者 JSON 序列化错误优先检查 dll 是否齐全。3.3 编译与部署到 IIS开发环境跑通了下一步是部署到 IIS 给同事或客户用。在 Visual Studio 里右键项目选择发布目标选文件夹输出到一个本地目录。然后打开 IIS 管理器新建应用程序池.NET CLR 版本选择 v4.0托管管道模式选经典。这里有个老坑WebForm 项目如果套了母版页或者用了 AjaxPro在集成模式下可能出问题经典模式兼容性更好。网站物理路径指向发布目录绑定端口号比如 8080。应用池如果用的是 ApplicationPoolIdentity要给网站目录设置 IIS_IUSRS 用户的可读权限。如果你用的是 SQL 账号连接数据库应用池身份就不影响数据库访问如果是 Integrated SecurityTrue则应用池身份必须有访问 SQLServer 的权限。4. 前端改造BootStrap 布局 Vue 局部刷新别把老项目做成古董这个项目前端用了 BootStrap 做响应式布局又引入 Vue 做局部数据绑定。熟悉了这套组合你可以在不推翻 WebForm 的前提下把页面做得像现代应用。4.1 BootStrap 在 WebForm 里的引入方式BootStrap 的使用没有秘密关键在文件引用路径。老项目很多页面是用母版页 Site.master 包着的在母版页 head 里统一引入 bootstarp.css、jquery.js、bootstrap.js。如果部署在虚拟目录路径很容易出问题href/css/bootstrap.min.css会从网站根目录找虚拟目录下去找就 404hrefcss/bootstrap.min.css则根据当前页面相对位置找深浅层级不同也容易翻车。我一般用带完整虚拟目录名的绝对路径比如先在前台代码里写死虚拟目录名或者用% ResolveUrl(~/css/bootstrap.min.css) %。还有一个小细节BootStrap 的组件依赖 jQuery而 WebForm 本身也会自动生成一些脚本。如果你发现页面上的下拉框、弹窗没样式或点击没反应大概率是 jQuery 被引用了两次版本还不一致。全局只保留一个 jQuery建议 BootStrap 3 用 jQuery 1.12不要混用 BootStrap 4 jQuery 2 的组合。4.2 Vue 接管列表搜索和分页与 AjaxPro 共存的正确姿势Vue 在 WebForm 里不能拿根节点包住整个页面因为 WebForm 是form runatserver整个页面生命周期和控件回发都依赖这个 formVue 进去了容易打架。正确做法是只让 Vue 管理一个具体的容器比如学生列表的div idapp数据通过 AjaxPro 从前端获取。看下面这个实际项目里的写法var vm new Vue({ el: #app, data: { studentList: [], keyword: , pageIndex: 1, pageSize: 10, totalCount: 0 }, methods: { loadStudents: function () { var self this; AjaxPro.StudentPage.GetStudentPage(this.keyword, this.pageIndex, this.pageSize, function (result) { var data JSON.parse(result.value); self.studentList data.rows; self.totalCount data.total; }); } }, mounted: function () { this.loadStudents(); } });这里有几个细节要注意。第一个回调函数里不要直接用this给 Vue 赋值回调作用域已经变了先把外层var self this存好。第二个Vue 实例必须在 DOM 渲染完后创建所以这段脚本要放在页面底部或者用 window.onload。第三后端方法返回的是 JSON 字符串前端要JSON.parse一次很多人直接拿字符串当数组用结果 Vue 渲染出来是空。第四WebForm 的控件 ID 在服务端会被改写如果 Vue 的 el 选择的是服务端控件的 ID要用ClientIDModeStatic固定 ID否则找不到容器。4.3 表单校验与弹窗的常见写法学生信息管理系统的添加和编辑弹窗一般用 BootStrap 的 Modal 组件打开里面放表单字段提交前做前端校验校验通过后再调 AjaxPro 方法存库。BootStrap 3 的弹窗结构固定记得把点击按钮的>button typebutton classbtn btn-primary>link href% ResolveUrl(~/css/bootstrap.min.css) % relstylesheet /每次发布如果改虚拟目录名这个路径会自动跟着变。同样的道理页面里的图片、JS 文件都要用这种相对根目录的写法别写相对当前页面的短路径。5.4 Vue 插值表达式原样显示现象页面源码里写{{ student.StudentName }}浏览器直接显示这串字符Vue 没有生效。原因Vue 实例创建时对应的 DOM 元素还没加载或者 el 选择器选到的容器和实际页面结构不一致另外如果页面有多个 Vue 实例el 选择器冲突也会导致后续实例失效。解决将脚本放在/body之前如果用母版页确保母版页内容占位符里能正常输出这个脚本el 选择器用 id 时检查这个 id 在页面里是否唯一。调试时在 Vue 实例构造前加一行console.log(document.getElementById(app))能拿到节点就说明时序 OK。还有个非常容易忽略的点WebForm 会给服务端控件的 id 加上前缀比如ContentPlaceHolder1_txtStudentNo。如果你用 Vue 的 el 去匹配一个runatserver的 div它的 id 已经被改掉了。所以容器要么用纯 HTML 标签要么明确加ClientIDModeStatic不要赌默认行为。5.5 AjaxPro 返回中文变成乱码或问号现象下拉框里班级名称显示成???, 保存中文姓名到数据库后在页面上正常但通过 AjaxPro 返回的 JSON 全是问号。原因AjaxPro 默认序列化时没有按 UTF-8 编码或者 web.config 里globalization requestEncodingutf-8 responseEncodingutf-8 /没配。解决在 web.config 的 system.web 节点下加上globalization requestEncodingutf-8 responseEncodingutf-8 fileEncodingutf-8 /然后在后端方法里不要返回 DataTable转成 JSON 字符串时用System.Web.Script.Serialization.JavaScriptSerializer它默认就是处理 Unicode 的。改完清浏览器缓存再试。这个坑常见于项目从 GB2312 编码迁移到 UTF-8 后AjaxPro 的 dll 还按老编码处理所以 web.config 里的编码设置要放在最早执行。6. 进一步改造把学生成绩导出 Excel 并在操作后写审计日志项目能跑能增删改查已经满足大部分中小型场景了。但你如果要拿去做毕业设计或者给企业正式用最好再补两个功能数据导出和操作留痕。这两个都不需要动架构直接在现有三层上扩展正好验证这套架构是否真的方便扩展。6.1 用轻量方式导出成绩到 Excel第一个是导出成绩到 Excel不引第三方库用最简单的 HTML 表格文件下发兼容性很好也适合老项目[AjaxPro.AjaxMethod] public static string ExportScores(string className) { DataTable table new ScoreDAL().GetScoresByClass(className); StringBuilder sb new StringBuilder(); sb.Append(table border1); sb.Append(trth学号/thth姓名/thth成绩/th/tr); foreach (DataRow row in table.Rows) { sb.AppendFormat(trtd{0}/tdtd{1}/tdtd{2}/td/tr, row[StudentNo], row[StudentName], row[Score]); } sb.Append(/table); return System.Web.HttpUtility.JavaScriptStringEncode(sb.ToString()); }前端拿到返回的 HTML 后用一个隐藏 iframe 触发下载也可以直接把它写到当前页面里的一个新窗口。注意需要给返回内容加上\ufeffBOM否则 Excel 打开中文会乱码。我一般会在前端处理时加decodeURIComponent来还原。这个实现很轻不依赖 NPOI 等库适合给老系统快速补一个导出按钮。6.2 在业务层写审计日志第二个是写操作审计日志。在你关心的业务方法入口记一条日志比如谁在什么时间删除了学号public bool DeleteStudent(int studentId, string operatorName) { bool result new StudentDAL().Delete(studentId); if (result) { string content string.Format({0} 删除学生ID:{1}, operatorName, studentId); new LogDAL().Write(DeleteStudent, content); } return result; }日志表可以简单建三列操作时间、操作类型、操作内容。更进一步可以记用户 IP、浏览器 UA但学生管理系统用不到那么重。经过这样的扩展你就能体会到这篇资源里三层架构带来的安全感加功能时 UI 调 BLLBLL 调 DAL谁都不用越层。我在这类老项目上翻过最大的车就是直接改 DAL 层拼 SQL结果线上出现注入漏洞从那以后我每次拿到新代码都强制走一遍编译、数据库备份、最小改动验证的流程再大的功能也先拆成 BLL 层能测试的方法。希望这篇笔记帮到你也祝你把项目跑通后能举一反三改成你自己想要的东西。本文还有配套的精品资源点击获取