手把手教你开发档案软件C/S版模块,含完整代码

一、开发环境准备与项目初始化

为了确保本文档的实操性,我们将采用目前主流且跨平台的 .NET 8 SDK 作为基础框架。服务端使用 ASP.NET Core 构建 Web API 提供数据接口,客户端使用 WinForms 构建桌面操作界面,数据存储采用轻量级的 SQLite 数据库,无需用户额外安装数据库服务。

1. 安装必要的开发工具

你需要确保系统中已安装 .NET 8 SDK。打开命令行工具(CMD 或 PowerShell),输入以下命令检查版本。如果未安装,请直接访问 https://dotnet.microsoft.com/download 下载并安装 .NET 8.0 SDK。

```bash dotnet --version ```

建议安装 Visual Studio 2022 Community(免费版)以便进行可视化窗体设计,下载地址:https://visualstudio.microsoft.com/downloads/。在安装时,务必勾选“.NET 桌面开发”和“ASP.NET 和 Web 开发”两个工作负载。

2. 创建解决方案目录结构

在本地磁盘(例如 D 盘)创建一个名为 ArchiveSystem 的文件夹。在该目录下打开命令行,依次执行以下命令来创建服务端和客户端的项目骨架:

```bash 创建服务端 Web API 项目 dotnet new webapi -n ArchiveServer 创建客户端 WinForms 项目 dotnet new winforms -n ArchiveClient 将两个项目添加到同一个解决方案中,方便管理 dotnet new sln -n ArchiveSystem dotnet sln add ArchiveServer/ArchiveServer.csproj dotnet sln add ArchiveClient/ArchiveClient.csproj ```

二、服务端开发:基于 ASP.NET Core 的档案管理接口

服务端负责档案数据的持久化存储和对外提供 API 接口。我们将使用 Entity Framework Core (EF Core) 来操作 SQLite 数据库。

1. 配置依赖包与数据库连接

进入服务端目录,添加 EF Core 和 SQLite 的驱动包。在命令行执行:

```bash cd ArchiveServer dotnet add package Microsoft.EntityFrameworkCore.Sqlite dotnet add package Microsoft.EntityFrameworkCore.Design ```

接下来,我们需要创建档案数据模型。在 ArchiveServer 项目根目录下新建一个文件夹 Models,并在其中创建 ArchiveItem.cs 文件,完整代码如下:

```csharp using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace ArchiveServer.Models { // 档案实体类 public class ArchiveItem { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] [MaxLength(100)] public string Title { get; set; } = string.Empty; // 档案标题 [MaxLength(50)] public string Category { get; set; } = string.Empty; // 档案分类 public DateTime CreateDate { get; set; } = DateTime.Now; // 归档日期 [MaxLength(500)] public string? Description { get; set; } // 档案描述 } } ```

Models 文件夹下继续创建数据库上下文类 ArchiveDbContext.cs

```csharp using Microsoft.EntityFrameworkCore; namespace ArchiveServer.Models { public class ArchiveDbContext : DbContext { public ArchiveDbContext(DbContextOptions options) : base(options) { } public DbSet Archives { get; set; } } } ```

2. 编写完整的 CRUD 业务逻辑

打开 Program.cs,删除所有默认生成的代码,替换为以下完整的配置代码。这段代码配置了数据库连接、跨域访问(CORS)策略以及完整的增删改查接口。

```csharp using Microsoft.EntityFrameworkCore; using ArchiveServer.Models; var builder = WebApplication.CreateBuilder(args); // 1. 配置 SQLite 数据库 builder.Services.AddDbContext(options => options.UseSqlite("Data Source=archive.db")); // 2. 配置跨域访问,允许 WinForms 客户端调用 builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); builder.Services.AddControllers(); var app = builder.Build(); // 3. 自动创建数据库(如果不存在) using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); db.Database.EnsureCreated(); } app.UseCors("AllowAll"); app.MapControllers(); // 定义 API 接口 // 获取所有档案 app.MapGet("/api/archives", async (ArchiveDbContext db) => { return await db.Archives.ToListAsync(); }); // 根据ID获取单个档案 app.MapGet("/api/archives/{id}", async (int id, ArchiveDbContext db) => { return await db.Archives.FindAsync(id) is ArchiveItem archive ? Results.Ok(archive) : Results.NotFound(); }); // 新增档案 app.MapPost("/api/archives", async (ArchiveItem archive, ArchiveDbContext db) => { db.Archives.Add(archive); await db.SaveChangesAsync(); return Results.Created($"/api/archives/{archive.Id}", archive); }); // 更新档案 app.MapPut("/api/archives/{id}", async (int id, ArchiveItem inputArchive, ArchiveDbContext db) => { var archive = await db.Archives.FindAsync(id); if (archive is null) return Results.NotFound(); archive.Title = inputArchive.Title; archive.Category = inputArchive.Category; archive.Description = inputArchive.Description; archive.CreateDate = inputArchive.CreateDate; await db.SaveChangesAsync(); return Results.NoContent(); }); // 删除档案 app.MapDelete("/api/archives/{id}", async (int id, ArchiveDbContext db) => { if (await db.Archives.FindAsync(id) is ArchiveItem archive) { db.Archives.Remove(archive); await db.SaveChangesAsync(); return Results.Ok(); } return Results.NotFound(); }); app.Run(); ```

此时,服务端代码已编写完毕。在命令行输入 dotnet run 即可启动服务端,默认监听地址为 http://localhost:5000https://localhost:5001

三、客户端开发:WinForms 界面与通信实现

手把手教你开发档案软件C/S版模块,含完整代码

客户端部分我们将构建一个简洁的 Windows 窗体应用,包含数据列表展示和新增/编辑/删除功能。

1. 创建客户端项目并配置

确保当前目录在解决方案根目录,进入客户端项目:

```bash cd ArchiveClient ```

为了简化 HTTP 请求和 JSON 处理,我们引入 Newtonsoft.Json 库:

```bash dotnet add package Newtonsoft.Json ```

2. 设计档案管理界面

为了方便大家直接复现,我们不使用可视化设计器拖拽控件,而是直接通过代码生成界面。打开 Form1.cs,将代码替换为以下内容。这包含了一个 DataGridView 用于显示列表,以及右侧的输入框和操作按钮。

```csharp using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Json; using System.Text; using System.Windows.Forms; using Newtonsoft.Json; namespace ArchiveClient { public partial class Form1 : Form { // 声明控件 private DataGridView dgvArchives; private TextBox txtTitle, txtCategory, txtDescription, txtId; private DateTimePicker dtpDate; private Button btnAdd, btnUpdate, btnDelete, btnRefresh; private static readonly HttpClient client = new HttpClient(); // 注意:这里的服务端地址需要根据实际启动情况调整,通常为 http://localhost:5xxx private const string ApiBaseUrl = "http://localhost:5000/api/archives"; public Form1() { InitializeComponent(); LoadDataAsync(); // 启动时加载数据 } private void InitializeComponent() { this.Text = "档案管理系统 C/S 版"; this.Width = 800; this.Height = 500; this.StartPosition = FormStartPosition.CenterScreen; // 表格控件 dgvArchives = new DataGridView { Dock = DockStyle.Left, Width = 450, AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill, ReadOnly = true, AllowUserToAddRows = false }; dgvArchives.SelectionMode = DataGridViewSelectionMode.FullRowSelect; dgvArchives.CellClick += DgvArchives_CellClick; // 点击行选择数据 // 输入面板 var panelRight = new Panel { Dock = DockStyle.Fill, Padding = new Padding(10) }; txtId = new TextBox { Visible = false }; // 隐藏ID字段 var lblTitle = new Label { Text = "档案", Top = 20, Left = 0, AutoSize = true }; txtTitle = new TextBox { Top = 40, Left = 0, Width = 300 }; var lblCategory = new Label { Text = "档案分类:", Top = 80, Left = 0, AutoSize = true }; txtCategory = new TextBox { Top = 100, Left = 0, Width = 300 }; var lblDate = new Label { Text = "归档日期:", Top = 140, Left = 0, AutoSize = true }; dtpDate = new DateTimePicker { Top = 160, Left = 0, Width = 300, Format = DateTimePickerFormat.Short }; var lblDesc = new Label { Text = "档案描述:", Top = 200, Left = 0, AutoSize = true }; txtDescription = new TextBox { Top = 220, Left = 0, Width = 300, Height = 80, Multiline = true }; // 按钮 btnAdd = new Button { Text = "新增档案", Top = 320, Left = 0, Width = 90, Height = 30 }; btnAdd.Click += BtnAdd_Click; btnUpdate = new Button { Text = "修改保存", Top = 320, Left = 100, Width = 90, Height = 30 }; btnUpdate.Click += BtnUpdate_Click; btnDelete = new Button { Text = "删除选中", Top = 320, Left = 200, Width = 90, Height = 30, ForeColor = System.Drawing.Color.Red }; btnDelete.Click += BtnDelete_Click; btnRefresh = new Button { Text = "刷新列表", Top = 360, Left = 0, Width = 290, Height = 30 }; btnRefresh.Click += (s, e) => LoadDataAsync(); // 添加控件到面板 panelRight.Controls.AddRange(new Control[] { txtId, lblTitle, txtTitle, lblCategory, txtCategory, lblDate, dtpDate, lblDesc, txtDescription, btnAdd, btnUpdate, btnDelete, btnRefresh }); // 添加控件到窗体 this.Controls.Add(dgvArchives); this.Controls.Add(panelRight); } // 业务逻辑方法 // 加载数据 private async void LoadDataAsync() { try { var data = await client.GetFromJsonAsync>(ApiBaseUrl); dgvArchives.DataSource = data; } catch (Exception ex) { MessageBox.Show($"加载失败: {ex.Message}"); } } // 点击表格行回显数据 private void DgvArchives_CellClick(object? sender, DataGridViewCellEventArgs e) { if (e.RowIndex >= 0) { var row = dgvArchives.Rows[e.RowIndex]; txtId.Text = row.Cells["Id"].Value?.ToString(); txtTitle.Text = row.Cells["Title"].Value?.ToString(); txtCategory.Text = row.Cells["Category"].Value?.ToString(); txtDescription.Text = row.Cells["Description"].Value?.ToString(); if (DateTime.TryParse(row.Cells["CreateDate"].Value?.ToString(), out var dt)) { dtpDate.Value = dt; } } } // 新增 private async void BtnAdd_Click(object? sender, EventArgs e) { var newItem = new ArchiveItem { Title = txtTitle.Text, Category = txtCategory.Text, Description = txtDescription.Text, CreateDate = dtpDate.Value }; var response = await client.PostAsJsonAsync(ApiBaseUrl, newItem); if (response.IsSuccessStatusCode) { MessageBox.Show("新增成功"); LoadDataAsync(); ClearInputs(); } } // 修改 private async void BtnUpdate_Click(object? sender, EventArgs e) { if (string.IsNullOrEmpty(txtId.Text)) { MessageBox.Show("请先选择一条记录"); return; } var updateItem = new ArchiveItem { Id = int.Parse(txtId.Text), Title = txtTitle.Text, Category = txtCategory.Text, Description = txtDescription.Text, CreateDate = dtpDate.Value }; var response = await client.PutAsJsonAsync($"{ApiBaseUrl}/{updateItem.Id}", updateItem); if (response.IsSuccessStatusCode) { MessageBox.Show("修改成功"); LoadDataAsync(); } } // 删除 private async void BtnDelete_Click(object? sender, EventArgs e) { if (string.IsNullOrEmpty(txtId.Text)) { MessageBox.Show("请先选择一条记录"); return; } var dlg = MessageBox.Show("确认删除?", "提示", MessageBoxButtons.OKCancel); if (dlg == DialogResult.OK) { var response = await client.DeleteAsync($"{ApiBaseUrl}/{txtId.Text}"); if (response.IsSuccessStatusCode) { MessageBox.Show("删除成功"); LoadDataAsync(); ClearInputs(); } } } private void ClearInputs() { txtId.Clear(); txtTitle.Clear(); txtCategory.Clear(); txtDescription.Clear(); } } // 定义与服务端对应的实体类(用于反序列化) public class ArchiveItem { public int Id { get; set; } public string Title { get; set; } public string Category { get; set; } public DateTime CreateDate { get; set; } public string? Description { get; set; } } } ```

注意: 由于 WinForms 默认未启用 System.Net.Http.Json 的扩展方法支持,如果 PostAsJsonAsync 报错,请确保项目文件 ArchiveClient.csproj 中包含以下框架引用,或者手动使用 StringContentJsonConvert.SerializeObject 发送请求。上述代码为了稳健性,已引入 Newtonsoft.Json,但使用了 .NET 6+ 自带的扩展方法。如遇编译错误,请修改 ArchiveClient.csproj 为:

```xml WinExe net8.0-windows enable true enable ```

四、编译运行与功能验证

至此,所有代码已准备就绪。现在我们将启动整个 C/S 系统并进行功能测试。

1. 启动服务端

打开第一个命令行窗口,进入 ArchiveServer 目录,运行以下命令启动服务端:

```bash cd D:\ArchiveSystem\ArchiveServer dotnet run ```

观察控制台输出,你会看到类似 Now listening on: http://localhost:5000 的提示。请记住这个端口号,如果系统自动分配了 5001 或其他端口,请务必修改客户端代码 Form1.cs 中的 ApiBaseUrl 常量,使其与实际地址一致。

2. 启动客户端

打开第二个命令行窗口,进入 ArchiveClient 目录,运行以下命令启动客户端:

```bash cd D:\ArchiveSystem\ArchiveClient dotnet run ```

3. 实操验证增删改查功能

客户端窗体弹出后,按照以下步骤验证:

  • 新增测试: 在右侧输入标题“2023年度财务报表”,分类“财务”,选择日期,点击“新增档案”。左侧列表应立即刷新显示该条目。
  • 查询测试: 启动时列表会自动加载,点击“刷新列表”可重新从服务端获取最新数据。
  • 修改测试: 点击左侧列表中的某一行,右侧文本框会自动填充内容。修改“档案描述”字段,点击“修改保存”,观察列表内容是否更新。
  • 删除测试: 选中一行,点击“删除选中”,确认弹窗后,该行应从列表中移除。

以上步骤完成了从零构建一个档案软件 C/S 版模块的全过程。服务端负责数据逻辑,客户端负责交互,两者通过 HTTP 协议进行高效通信,且无需配置复杂的 IIS 或 SQL Server,实现了零门槛落地。

AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

扫码咨询
安答联动微信公众号二维码

微信扫码关注安答联动

申请试用
热线电话
申请试用

安答联动档案管理系统