简介这套基于ASP.NET的B/S模式项目管理系统采用C#语言开发并搭配Access数据库适合正在学习web开发或需要完成课程设计、毕业设计的读者。系统完整实现了管理员、员工、网管三种角色权限管理员可维护员工、项目、日志及历史项目员工可注册并参与项目、提交日志和回复建议网管则可管理用户资料并执行数据库备份与还原。资源包内共297个文件约5.09MB主要包含cs源码、aspx页面、dll库、css样式及mdb数据库文件目录结构清晰便于定位与调试。目前已有505人学习下载对于希望深入理解ASP.NET权限设计、数据库交互及项目分层结构的开发者来说这套可运行源码具备很强的实践参考价值可直接在VS2010中打开部署并围绕角色功能继续扩展二次开发。1. 内部项目管理系统为什么我还在用 ASP.NET SQL Server 的 Web 结构一个公司内部要上项目管理系统预算不高、时间又紧需求无非是记录项目、拆分任务、跟踪进度。我一般直接推荐 ASP.NET VS SQL Server C# 的 Web 结构组合开发工具用 VS 就够了数据库用 SQL Server 维护成本低部署到一台 Windows Server 的 IIS 上就能跑一个人从建表到上线两三天能出第一个可用版本。这套方案不追新框架但胜在资料多、接手快、坑基本都有前人踩过。我按实际交付过的内部系统写法把从 SQL Server 表结构、VS 建项目、GridView 绑定数据到上线前排查的完整流程走一遍适合做企业内部工具和中小团队管理系统的 .NET 开发者直接照着改。2. SQL Server 表结构先行三张核心表决定这个系统能撑多大先动数据库再动 VS。项目管理系统的核心数据关系很直白一个项目下面挂多条任务一条任务有一个负责人负责人来自用户表。很多翻车现场都是上来就写页面写到一半发现缺字段、状态值对不上回头改表连带改页面和 C# 代码返工成本最高。我的习惯是先花半小时把三张表建好字段语义固定下来后面 GridView 绑定和 C# 逻辑都是顺着表走的。2.1 项目表、任务表、用户表最小可用的建表脚本三张表足够跑通第一个版本Project 存项目主信息Task 存项目下的任务User 存登录名和显示名。下面是 SQL Server 里直接可执行的建表脚本-- 项目表一条项目记录对应一个内部项目 CREATE TABLE dbo.Project ( ProjectId INT IDENTITY(1,1) PRIMARY KEY, ProjectNo NVARCHAR(20) NOT NULL, ProjectName NVARCHAR(100) NOT NULL, ManagerId INT NULL, StartDate DATETIME NULL, EndDate DATETIME NULL, Status INT NOT NULL DEFAULT 0, Priority INT NOT NULL DEFAULT 1, CreatedTime DATETIME NOT NULL DEFAULT GETDATE() ); -- 任务表一个项目下挂多条任务ProjectId 做外键 CREATE TABLE dbo.Task ( TaskId INT IDENTITY(1,1) PRIMARY KEY, ProjectId INT NOT NULL FOREIGN KEY REFERENCES dbo.Project(ProjectId), TaskName NVARCHAR(200) NOT NULL, AssigneeId INT NULL, DueDate DATETIME NULL, Progress INT NOT NULL DEFAULT 0, Status INT NOT NULL DEFAULT 0 ); -- 用户表User 是保留字建表必须加中括号 CREATE TABLE dbo.[User] ( UserId INT IDENTITY(1,1) PRIMARY KEY, LoginName NVARCHAR(50) NOT NULL, DisplayName NVARCHAR(50) NOT NULL, DeptName NVARCHAR(50) NULL, IsActive BIT NOT NULL DEFAULT 1 );几个容易忽略的细节。主键用 INT IDENTITY 而不是 GUID内部系统单表数据量到不了需要 GUID 的量级INT 主键在 GridView 分页排序和 Join 时效率高写起来也短。所有名称字段用 NVARCHAR项目名、任务名里有中文也有特殊字符NVARCHAR 按 Unicode 存储不会因为排序规则不同出现乱码。User 表名带中括号是因为 USER 在 SQL Server 里是保留关键字这个坑我见过不止一次。Status 字段统一用 INT 而不是 VARCHAR。有人喜欢存进行中这种中文但页面下拉框、C# 枚举、SQL 聚合统计全都得跟着字符串走稍微多一个空格就匹配不上。INT 状态配合代码里的枚举显示文案只在一处维护。任务表的 Progress 建议存 0 到 100 的整数前端进度条直接拿这个值渲染别存百分比字符串后面查询统计会省很多事。2.2 字段类型与状态枚举两个最容易返工的设计点第一点是负责人字段存什么。Project.ManagerId 和 Task.AssigneeId 都存 UserId不要存姓名。内部系统最常遇到的就是组织结构调整人员名字变了如果负责人直接存字符串所有历史数据都得 UPDATE存 UserId 的话只需改 User 表一行页面 Join 出显示名旧数据自动跟着变。Join 的开销在这种数据量下可以忽略。第二点是时间字段。开始、结束时间用 DATETIME 够用但如果你用的是 SQL Server 2016 以上版本我建表时习惯直接写 DATETIME2精度到微秒默认值和比较行为更符合直觉。前端 GridView 显示时用 DataFormatString{0:yyyy-MM-dd} 格式化不要在 SQL 里转 VARCHAR否则排序会乱。CreatedTime 这种审计字段加上 DEFAULT GETDATE()INSERT 时少写一个参数也防止有人漏填。状态枚举在 C# 侧用一个静态类集中定义避免代码里到处是魔法数字public static class TaskStatus { public const int NotStarted 0; public const int InProgress 1; public const int Completed 2; public const int Suspended 3; }页面、查询、统计都用这组常量以后加状态只改这里和 RowDataBound 里的显示逻辑。字段设计还有个原则能用约束在数据库挡住的脏数据就不要指望页面输入框。比如 Progress 加 CHECK (Progress BETWEEN 0 AND 100)比在 C# 里写一堆校验更保险让 SQL Server 在 INSERT 时直接拒绝非法值省掉一层黑匣子式的排查。2.3 建好表后顺手补两个索引高频查询的索引选择-- 任务按项目查是最频繁的访问路径 CREATE NONCLUSTERED INDEX IX_Task_ProjectId ON dbo.Task(ProjectId); -- 列表页常按状态过滤和统计 CREATE NONCLUSTERED INDEX IX_Task_Status ON dbo.Task(Status);这两个索引覆盖项目管理系统的主要查询项目详情页按 ProjectId 拉任务列表首页按 Status 统计完成率。内部系统别过度索引写多读少的场景下每多一个索引就多一份 INSERT 开销等系统跑起来看实际查询再补都来得及。建表的另一个注意点是控制权限给应用账号只授 db_datareader 和 db_datawriter别用 sa 连 Web 应用否则一旦页面被注入攻击者拿到的就是整个实例的权限。3. 在 VS 里建 ASP.NET Web 项目从模板选择到 GridView 显示第一页数据数据库就位后打开 VS。网上搜 asp.net 入门教程绝大部分还是拿 VS 建一个 Web 项目拖一个 GridView 上去跑通这个路径到今天依然是内部管理系统最快的开发方式。下面按 VS 2019 或 2022 的 Community 版操作安装时勾选ASP.NET 和 Web 开发工作负载SQL Server 用 2019 或 2022 都行连接方式不影响后面的代码。3.1 Web Forms 还是 MVC内部管理系统选型不要纠结VS 新建项目时有两个常见模板ASP.NET Web Forms (.NET Framework) 和 ASP.NET MVC。内部管理系统核心是几十个列表页加编辑页Web Forms 的 GridView、DetailsView 自带绑定、分页、编辑模板写一个列表页只要几十行代码MVC 需要自己配路由、控制器、视图和表单验证代码量大约是 Web Forms 的两到三倍。我一般直接选 Web Forms目标框架 .NET Framework 4.7.2部署到 IIS 时应用程序池选 v4.0 集成模式就能跑。这不是说 MVC 不好而是投入产出比的问题。项目管理系统没有复杂的 REST API 和前端框架需求服务端渲染加 GridView 足够。如果团队后续想让前端用 Vue 或 React 分离开发那是另一个选型故事。选 .NET Framework 4.7.2 还有一个实际好处Windows Server 2012 R2 以上的系统内置支持不用单独装运行时部署服务器时少一个变量。3.2 Web.config 连接字符串SQL Server 认证与端口写法项目建好后第一件事是配置数据库连接。打开 Web.config在 connectionStrings 节点里加一条连接字符串configuration connectionStrings add namePMSConnection connectionStringData Source127.0.0.1,1433;Initial CatalogProjectManageDB;User IDpms_user;Passwordpms_pass;MultipleActiveResultSetsTrue; providerNameSystem.Data.SqlClient / /connectionStrings /configurationData Source 写成 127.0.0.1,1433 而不是 localhost 或机器名是为了避开 SQL Server 命名实例解析的坑。默认实例的端口是 1433显式写端口后C# 连接时直接走 TCP/IP不依赖 SQL Browser 服务。这个细节在新装的 SQL Server 上尤其重要因为默认配置下 TCP/IP 协议常常是禁用状态等部署到服务器再排查就要花半天。连接方式我建议用 SQL Server 认证User ID/Password而不是 Windows 集成认证。内部局域网虽然可以开 Integrated SecurityTrue但同事电脑连服务器时IIS 应用程序池的运行账户如果不是域账户认证就会失败日志还看不明白。SQL 认证只要在 SQL Server 里建一个 pms_user 账号授予 ProjectManageDB 的 db_datareader 和 db_datawriter 权限问题边界清楚好排查。MultipleActiveResultSetsTrue 建议加上一个连接上同时开多个 SqlDataReader 时不会报错GridView 绑定和页面里嵌套查询场景下能少踩一个运行时异常。提示SQL Server 配置管理器里启用 TCP/IP 后必须重启 SQL Server 服务只点启用不重启不生效。3.3 最小可用页面Default.aspx GridView 绑定项目列表配置完连接字符串写第一个页面验证整条链路。在 VS 里添加 Web 窗体命名 Default.aspx拖一个 GridView 到页面% Page LanguageC# AutoEventWireuptrue CodeBehindDefault.aspx.cs InheritsPMS.Web.Default % !DOCTYPE html html head runatserver title项目列表/title /head body form idform1 runatserver asp:GridView IDgvProjects runatserver AutoGenerateColumnsFalse AllowPagingTrue PageSize10 OnPageIndexChanginggvProjects_PageIndexChanging Columns asp:BoundField DataFieldProjectNo HeaderText项目编号 / asp:BoundField DataFieldProjectName HeaderText项目名称 / asp:BoundField DataFieldManagerName HeaderText负责人 / asp:BoundField DataFieldStartDate HeaderText开始日期 DataFormatString{0:yyyy-MM-dd} HtmlEncodeFalse / /Columns /asp:GridView /form /body /html页面后置代码 Default.aspx.csusing System; using System.Data; public partial class Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { // IsPostBack 为 false 才做首次绑定避免每次回发重置列表 if (!IsPostBack) { BindProjects(); } } private void BindProjects() { string sql SELECT p.ProjectId, p.ProjectNo, p.ProjectName, u.DisplayName AS ManagerName, p.StartDate FROM dbo.Project p LEFT JOIN dbo.[User] u ON p.ManagerId u.UserId ORDER BY p.CreatedTime DESC; DataTable dt SqlHelper.ExecuteQuery(sql); gvProjects.DataSource dt; gvProjects.DataBind(); } protected void gvProjects_PageIndexChanging(object sender, GridViewPageEventArgs e) { gvProjects.PageIndex e.NewPageIndex; BindProjects(); } }Page_Load 里的 if (!IsPostBack) 是 Web Forms 的核心习惯。页面每次回发都会执行 Page_Load如果每次都绑定 GridView翻页、删除后数据源被重置用户体验和状态都不对。GridView 的 AllowPaging 和 PageSize 控制每页行数翻页触发 OnPageIndexChanging 事件把 PageIndex 换成目标页再重新绑定。ManagerName 来自 User 表 LEFT JOIN如果某个项目没设负责人左边表字段为 NULLGridView 对应单元格显示为空页面不会崩。如果改成 INNER JOIN没负责人的项目直接消失用户会以为系统丢了数据这种细节在内部系统里很影响信任度。按 F5 启动调试后VS 会拉起 IIS Express浏览器访问 localhost 端口下的 Default.aspx页面从 SQL Server 把项目列表查出来渲染成 HTML浏览器、IIS Express、C# 代码、SQL Server 这四层链路就是标题里 web 结构的完整含义。能看到列表说明连接字符串、表结构和页面绑定都通了后面的增删改查都是在这个骨架上加肉。4. C# 增删改查落地SqlHelper、GridView 行操作与状态显示页面能显示列表只是开始项目管理系统必须能加任务、改状态、删记录。这一章把数据访问层和 GridView 的事件写法定下来后面每个模块都是复制这套模式。4.1 一个够用的 SqlHelper参数化查询与连接释放常见做法是单独建一个 SqlHelper.cs把连接字符串、查询、执行封装成静态方法。内部系统用不着 Entity Framework 的完整能力一个 SqlHelper 加 DataTable 足够应付 GridView 绑定场景也方便新人理解数据是怎么来的。using System; using System.Configuration; using System.Data; using System.Data.SqlClient; public static class SqlHelper { private static readonly string connStr ConfigurationManager.ConnectionStrings[PMSConnection].ConnectionString; public static DataTable ExecuteQuery(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(connStr)) using (SqlCommand cmd new SqlCommand(sql, conn)) { if (parameters ! null) { cmd.Parameters.AddRange(parameters); } using (SqlDataAdapter da new SqlDataAdapter(cmd)) { DataTable dt new DataTable(); da.Fill(dt); return dt; } } } public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(connStr)) using (SqlCommand cmd new SqlCommand(sql, conn)) { if (parameters ! null) { cmd.Parameters.AddRange(parameters); } conn.Open(); return cmd.ExecuteNonQuery(); // 返回受影响行数 } } }两个核心点。第一using 语句保证 SqlConnection 和 SqlCommand 用完即释放连接归还连接池SQL Server 不会因为连接句柄没关而耗尽 worker 线程这是内部系统跑一段时间后数据库突然连不上的头号原因。第二所有外部传入的值一律走 SqlParameter不要字符串拼接。拼 SQL 除了 SQL 注入风险还有一个容易忽略的问题文本框里输入带单引号的文本比如项目名客户满意度调研拼接 SQL 直接语法错误参数化后这类问题彻底消失。参数的类型和长度由 SqlParameter 推导C# 侧传 string、int、DateTime 都对应到 SQL Server 的正确类型。4.2 GridView 行操作统一走 RowCommand别在模板里挂控件事件给 GridView 加删除按钮常见做法是在列集合里加一个 ButtonFieldCommandName 指定动作名CommandArgument 绑定主键。页面上的按钮点击后事件统一在 GridView 的 RowCommand 里处理asp:ButtonField Text删除 CommandNameDeleteTask ButtonTypeButton /对应的事件代码protected void gvTasks_RowCommand(object sender, GridViewCommandEventArgs e) { if (e.CommandName DeleteTask) { // 表头按钮触发时 CommandArgument 为 null必须先判空 if (e.CommandArgument null) { return; } int taskId Convert.ToInt32(e.CommandArgument); string sql DELETE FROM dbo.Task WHERE TaskId TaskId; SqlHelper.ExecuteNonQuery(sql, new SqlParameter(TaskId, taskId)); BindTasks(); } }为什么建议统一走 RowCommand 而不是在 TemplateField 里放一个 LinkButton 再挂 OnClickTemplateField 里的控件事件需要 FindControl 或写 OnClientClick回发链路长ViewState 稍微不对就报回发或回调参数无效这是 Web Forms 里最著名的报错之一错误信息还特别误导。RowCommand 是 GridView 层面的标准事件CommandArgument 把主键从行上下文里带出来代码集中在同一处调试时打断点也方便。CommandArgument 传出来的是字符串用 Convert.ToInt32 转换前先判断是否为空否则表头按钮触发 RowCommand 时直接抛异常。4.3 RowDataBound 把状态数字翻译成前端文案数据库里 Status 是 0、1、2页面上不能直接显示数字。在不改造 GridView 的情况下用 RowDataBound 事件在每一行绑定完成后改写 Status 列。先在 GridView 的模板列里放一个 Literalasp:TemplateField HeaderText状态 ItemTemplate asp:Literal IDlitStatus runatserver/asp:Literal /ItemTemplate /asp:TemplateFieldRowDataBound 里找到这个控件并赋值protected void gvTasks_RowDataBound(object sender, GridViewRowEventArgs e) { // 跳过表头和表尾行它们没有 DataItem if (e.Row.RowType ! DataControlRowType.DataRow) return; DataRowView row (DataRowView)e.Row.DataItem; // 历史数据里可能混入 NULL先判空再转换 if (row[Status] DBNull.Value) { return; } int status Convert.ToInt32(row[Status]); Literal lit (Literal)e.Row.FindControl(litStatus); if (lit ! null) { switch (status) { case 0: lit.Text 未开始; break; case 1: lit.Text span stylecolor:#d97706进行中/span; break; case 2: lit.Text span stylecolor:#16a34a已完成/span; break; default: lit.Text 未知; break; } } }RowType 判断是为了跳过表头和表尾行表头行没有 DataItem强转 DataRowView 会抛异常。row[Status] 先判断 DBNull这条是我吃过亏的经验某个版本允许任务不设置状态历史数据里出现 NULLConvert.ToInt32 直接崩页面整页翻车日志里只有一句空引用异常排查起来特别费劲。如果你从别的系统导入任务数据比如 Excel 导入时把进度写成80%导入到 SQL Server 的 Progress 字段就会报转换失败第 5 章排查清单里专门有一条这里先记住原则数据库字段类型在导入前先 TRY_CONVERT 验证别让脏数据进门。5. 上线避坑SQL Server 连不上、分页越界、字符串转数字报错的排查清单这一章是我做这个方向踩过的坑汇总。每条按现象、原因、解决写新手上线前照着过一遍能省下至少一个通宵。5.1 现象本机能跑同事浏览器访问报数据库连接错误现象在开发机上 F5 调试一切正常发布到服务器后自己访问没问题同事访问同样的地址页面报建立与 SQL Server 的连接时发生网络相关错误或特定于实例的错误。原因通常三选一。SQL Server 的 TCP/IP 协议没启用默认只开了 Shared MemoryWindows 防火墙没放行 1433 端口连接字符串用了机器名而服务器解析不了。解决打开 SQL Server 配置管理器找到SQL Server 网络配置下的实例启用 TCP/IP重启 SQL Server 服务。确认 telnet 服务器IP 1433 能通不通就加防火墙入站规则。连接字符串统一写成 IP 加端口别写 localhost也别写服务器主机名。我见过最隐蔽的情况是服务器上有多个 SQL Server 实例默认实例里没建库数据都在命名实例里连接字符串指向默认实例自然报错。排查这类问题先从 SQL Server 配置管理器和防火墙下手不要一上来就怀疑代码。5.2 现象GridView 翻页到第 3 页后删除最后一条页面报索引越界现象列表第 1 页删数据正常翻到最后一页把该页最后一条记录删除后BindTasks() 一执行就报索引超出范围。原因删除后重新绑定GridView 的 PageIndex 还停留在原来的页码但总页数已经减少了当前页索引超过 PageCount - 1GridView 内部取行时索引越界。解决重新绑定前做一次钳制在 DataBind 之前判断private void BindTasks() { // ... 查 DataTable、赋 DataSource 的代码不变 // 删除或筛选后总页数可能减少钳制到最后一页 if (gvTasks.PageIndex gvTasks.PageCount) { gvTasks.PageIndex gvTasks.PageCount - 1; } gvTasks.DataBind(); }这个 bug 只在最后一页删最后一条的边界条件下出现测试数据不够多时根本发现不了属于典型的黑匣子式报错报错信息也指向不明。顺带一提翻页事件里修改 PageSize 后也要重新 DataBind否则 GridView 显示的行数和新 PageSize 不一致。写 GridView 相关逻辑时把页面索引变化和数据源变化这两条链路分开想能少踩一半这类坑。5.3 现象sqlserver 字符串转数字报错导入任务数据时 Progress 字段直接失败现象从 Excel 导入任务清单SQL Server 提示数据无效或报将 nvarchar 转换为数据类型 int 的语法错误整批数据导入失败。原因Progress 是 INT源数据里有的单元格是80%有的为空甚至混着高/中/低这类文本。SQL Server 做隐式转换时遇到非数字字符直接抛错而且不是跳过那几行是整批失败。解决导入前用 TRY_CONVERT 过滤。SQL Server 2012 以上版本支持 TRY_CONVERT转换失败返回 NULL配合 ISNULL 给默认值-- ProgressText 是导入表的临时字段转换失败时归 0 SELECT TaskName, ISNULL(TRY_CONVERT(INT, REPLACE(ProgressText, %, )), 0) AS Progress FROM dbo.TaskImport;C# 侧也用 int.TryParse 兜底不用 Convert.ToInt32 直接转避免输入为空字符串时抛 FormatException。这条原则对所有从 Web 页面拿到的东西都适用凡是从 GridView 的 CommandArgument、TextBox 文本、Excel 导入来的值先 TryParse 再进数据库。SQL Server 的隐式转换在数据量大的表上还会引发额外的类型转换开销能显式 CAST 就不要靠自动转。5.4 现象IIS 发布后页面报 500.19 或由于扩展配置问题无法提供请求的页面现象VS 里发布成功文件也拷到服务器了浏览器访问 .aspx 页面直接 500.19IIS 日志里写无法读取配置节。原因服务器 IIS 没装 ASP.NET 功能模块。Windows Server 默认只装静态网页功能.NET 的请求处理模块没注册或者应用程序池选的经典模式与 Web Forms 的集成管线不兼容。解决服务器管理器里添加角色和功能勾选应用程序开发下的 ASP.NET 4.x对应 .NET Framework 版本安装后重启 IIS。再检查应用程序池右键默认网站对应的池基本设置里.NET CLR 版本选 v4.0.30319托管管道模式选集成。手动搭建 IIS 时经常忘记这步报错信息又没直接说没装 ASP.NET很容易在 web.config 里白找半天。发布时如果用了 Web Deploy还要确认目标服务器装了 Web Deploy 代理否则 VS 里发布按钮能点但文件根本没传全。5.5 现象SQL Server 事务日志把磁盘撑满数据库进入只读状态现象系统跑了两个月磁盘告警检查发现数据库的 .ldf 日志文件涨到几十 GB数据库变成只读业务页面全部报错。原因数据库恢复模式是完整又没有配任何日志备份作业。完整恢复模式下日志只有在备份之后才会截断没有备份就无限增长。内部项目管理系统对数据恢复粒度没有苛刻要求完全不需要完整恢复模式的按时间点还原能力。解决右键数据库属性恢复模式改成简单日志空间自动收缩再配一个每周完整备份的维护计划。想看日志文件占用和恢复模式用这条 SQL-- 查看数据库恢复模式和日志文件空间占用 SELECT name, recovery_model_desc, log_recovery_size_desc FROM sys.databases WHERE name ProjectManageDB;简单恢复模式损失的是最近一次完整备份之后到故障点之间的日志对内部系统来说最坏情况丢一天数据完全可以接受。这个决策要记录在部署文档里不然下一位维护者看到恢复模式是简单会以为是配置错误又改回去日志再次暴涨。日志问题排查时右键数据库报表-标准报表-磁盘使用情况也能直接看到日志和数据的空间占比比数文件大小直观。6. 让系统真正被用起来进度统计、GridView 的 jQuery 体验与上线验证系统没人用往往不是功能不够而是看不到价值。项目管理系统最能说服用户的是项目进度一眼可见。给首页加一个统计视图SQL 直接聚合6.1 一条 SQL 算出项目进度先乘再除避免整数除法SELECT p.ProjectName, COUNT(t.TaskId) AS TotalTask, SUM(CASE WHEN t.Status 2 THEN 1 ELSE 0 END) AS DoneTask, CASE WHEN COUNT(t.TaskId) 0 THEN 0 ELSE CAST(SUM(CASE WHEN t.Status 2 THEN 1 ELSE 0 END) * 100 / COUNT(t.TaskId) AS INT) END AS Progress FROM dbo.Project p LEFT JOIN dbo.Task t ON p.ProjectId t.ProjectId GROUP BY p.ProjectId, p.ProjectName;注意先乘 100 再除SQL Server 的整数除法直接舍去小数先除后乘会把 8/10 得 0 再乘还是 0。COUNT(t.TaskId) 为 0 的项目单独兜底返回 0否则除零报错。这条 SQL 返回的结果集可以直接绑定到首页的 GridView也可以在 C# 里读出来画进度条。6.2 GridView 加一点 jQuery 交互ClientID 定位和行高亮GridView 渲染出来就是一个带 id 的 table给它的行加 hover 高亮和点击选中不需要任何插件。网上搜asp.net 的 gridview 的 jquery 插件很多方案绕了一圈其实原生的够用$(function () { // ClientID 保证嵌套页面里也能定位到 GridView $(#% gvTasks.ClientID % tr).hover( function () { $(this).addClass(row-hover); }, function () { $(this).removeClass(row-hover); } ); });用 ClientID 而不是写死 ID是因为 Web Forms 在主页面、用户控件嵌套时控件 ID 会被改写成 ctl00_ 前缀写死 gvTasks 在深层页面里定位不到。CSS 里定义 .row-hover 的背景色即可这段脚本放在页面底部或者单独的 js 文件里不依赖 UpdatePanel 就能工作。如果页面里有 UpdatePanel 局部刷新scriptManager 注册的脚本会在每次回发后重新执行不需要额外处理。6.3 上线前的验证清单发布后 10 分钟过一遍发布后我习惯按下面这张表过一遍全绿才算交付检查项验证方法失败时看哪里数据库连接访问一个列表页确认数据能显示SQL Server 配置管理器 TCP/IP、防火墙 1433IIS 应用池aspx 页面不报 500.19应用池 .NET CLR 版本、集成模式删除/翻页边界删最后一页最后一条记录GridView PageIndex 钳制逻辑日志与备份查看数据库恢复模式sys.databases、维护计划任务这套组合开发内部项目管理系统我走了不止一遍现在的习惯是先画表结构再写页面状态全部用枚举外部输入一律参数化上线前把第五章的清单完整过一遍。这几个习惯帮我避开了大部分返工也希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
高频变压器三明治绕法:漏感控制与EMI优化实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:11:04
从编译到烧录:ARM MCU工程搭建与调试全流程解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:11:04
审稿意见回复不再难:标准回复信的结构、句式与避坑指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:10:58
医疗大模型微调语料全流程:格式转换、清洗与配比实战指南 简介:面向大型语言模型微调训练的医疗数据集,适合算法工程师、医学信息研究者及有一定机器学习基础的初学者。资源整合了内科、外科、儿科、肿瘤科等科室的中文问诊对话,以及妇产科、男科、肝病等专科数据,并包含huatuo、llama、m… · 2026/9/25 2:14:53
基于特征线法MOC的水锤压力流量曲线计算:ZIELKE1基准算例复现与避坑指南 简介:一套基于特征线法(MOC)实现动态摩阻管道流动求解的仿真资源,面向计算流体力学初学者、管道瞬变流分析人员及开展数值仿真课程设计的工科学生。资源围绕一维非稳态管道流动问题,重点演示如何在特征线上离散连续性与… · 2026/9/25 2:14:53
Conventional Commits 1.0.0 规范全解读:从提交信息格式到自动化语义化版本 文档 【免费下载链接】conventionalcommits.org The conventional commits specification 项目地址: https://gitcode.com/gh_mirrors/co/conventionalcommits.org 点击查看 免费下载 本文基于本仓库中 约定式提交规范 v1.0.0 的乌克兰语版本(content/v… · 2026/9/25 2:14:47
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37