2025.11.22总结

CS架构项目全解析
1.首先安装编译器配置环境,我这里安装的是visual studio 社区版2022
下载完编译器后配置c#环境,点击修改
image

下载红框勾选部分
image

2.项目的初始化
首先打开visual studio ,创建新项目
image
选择空项目
image

修改名字后创建
image

右键解决方案,添加新项目
image
image

直接点下一步,创建
这样就得到了服务器端的初始代码
继续右键解决方案,添加新项目
选择WPF应用程序,下一步创建好了
image

这里我修改了下名字方便识别
image

接下来是依赖的安装,和写初始化能启动的代码。visual studio依赖的安装比较麻烦。nug包管理器安装
image

客户端和服务器端的依赖需要分别安装
image

安装完之后就能成功连接数据库,
接下来写Server服务器端代码
image

appsettings.json用来配置数据库用户名密码,我这里使用的是mysql数据库

{
  "ConnectionStrings": {
    "DefaultConnection": "server=localhost;database=UserManagementDB;user=root;password=123456;port=3306"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Program.cs用来配置总的一些环境和策略

using Microsoft.EntityFrameworkCore;
using UserManagement.Server.Data;


var builder = WebApplication.CreateBuilder(args);

// 添加服务到容器
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// 添加MySQL数据库上下文 - 使用Pomelo提供程序
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));

// 添加CORS策略允许客户端访问
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll", policy =>
    {
        policy.AllowAnyOrigin()
              .AllowAnyHeader()
              .AllowAnyMethod();
    });
});

var app = builder.Build();

// 配置HTTP请求管道
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseCors("AllowAll");
app.UseAuthorization();
app.MapControllers();

// 初始化数据库
using (var scope = app.Services.CreateScope())
{
    var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

    // 确保数据库已创建
    await dbContext.Database.EnsureCreatedAsync();

    // 如果数据库为空,添加初始数据

}

Console.WriteLine("用户管理服务器启动成功!");
Console.WriteLine("API地址: https://localhost:5000");
Console.WriteLine("Swagger文档: https://localhost:5000/swagger");

app.Run();

ApplicationDbContext用来配置数据库,在这里配置好以后好像数据库表能自动写入数据库,

using Microsoft.EntityFrameworkCore;
using UserManagement.Server.Models;
namespace UserManagement.Server.Data
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }

        public DbSet<User> Users { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>(entity =>
            {
                entity.HasKey(e => e.Id);
                entity.Property(e => e.Name).IsRequired().HasMaxLength(100);
                entity.Property(e => e.Email).IsRequired().HasMaxLength(100);
                entity.Property(e => e.Age).IsRequired();
            });
        }
    }
}

接下来就是要写的实体类和controller接口

User.cs

namespace UserManagement.Server.Models
{
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public int Age { get; set; }
    }
}

UserController.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UserManagement.Server.Data;
using UserManagement.Server.Models;
namespace UserManagement.Server.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class UserController : ControllerBase
    {
        private readonly ApplicationDbContext _context;

        public UserController(ApplicationDbContext context)
        {
            _context = context;
        }

        // GET: api/user - 获取所有用户
        [HttpGet]
        public async Task<IActionResult> GetUsers()
        {
            var users = await _context.Users.ToListAsync();
            return Ok(users);
        }

        // GET api/user/5 - 根据ID获取用户
        [HttpGet("{id}")]
        public async Task<IActionResult> GetUser(int id)
        {
            var user = await _context.Users.FindAsync(id);
            if (user == null)
                return NotFound($"用户ID {id} 不存在");

            return Ok(user);
        }

        // POST api/user - 创建新用户
        [HttpPost]
        public async Task<IActionResult> CreateUser(User user)
        {
            // 自动生成ID
            var maxId = await _context.Users.MaxAsync(u => (int?)u.Id) ?? 0;
            user.Id = maxId + 1;

            _context.Users.Add(user);
            await _context.SaveChangesAsync();

            return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
        }

        // PUT api/user/5 - 更新用户
        [HttpPut("{id}")]
        public async Task<IActionResult> UpdateUser(int id, User updatedUser)
        {
            if (id != updatedUser.Id)
                return BadRequest("ID不匹配");

            var user = await _context.Users.FindAsync(id);
            if (user == null)
                return NotFound($"用户ID {id} 不存在");

            user.Name = updatedUser.Name;
            user.Email = updatedUser.Email;
            user.Age = updatedUser.Age;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!UserExists(id))
                    return NotFound();
                else
                    throw;
            }

            return Ok(user);
        }

        // DELETE api/user/5 - 删除用户
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteUser(int id)
        {
            var user = await _context.Users.FindAsync(id);
            if (user == null)
                return NotFound($"用户ID {id} 不存在");

            _context.Users.Remove(user);
            await _context.SaveChangesAsync();

            return Ok(new { message = "用户删除成功", deletedUser = user });
        }

        private bool UserExists(int id)
        {
            return _context.Users.Any(e => e.Id == id);
        }
    }
}

这样基础的后端就能写好了

接下来写客户端client

一共2+2个文件,每一个都是界面和逻辑分开来写的,和安卓的开发很像
image

MainWindow.xaml

<Window x:Class="UserManagement.Client.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="用户管理系统 - 客户端" 
        Height="600" 
        Width="900"
        WindowStartupLocation="CenterScreen"
        Background="#f0f0f0">

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="#007ACC"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="Padding" Value="10,5"/>
            <Setter Property="Margin" Value="5"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="Cursor" Value="Hand"/>
        </Style>

        <Style TargetType="DataGrid">
            <Setter Property="Margin" Value="10"/>
            <Setter Property="IsReadOnly" Value="True"/>
            <Setter Property="AutoGenerateColumns" Value="False"/>
            <Setter Property="SelectionMode" Value="Single"/>
        </Style>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- 标题区域 -->
        <Border Grid.Row="0" Background="#2D2D30" Padding="15">
            <StackPanel>
                <TextBlock Text="🐧 用户管理系统" 
                          FontSize="28" 
                          FontWeight="Bold" 
                          Foreground="White"
                          HorizontalAlignment="Center"/>
                <TextBlock x:Name="txtConnectionStatus" 
                          Text="正在连接服务器..." 
                          Foreground="#CCCCCC"
                          HorizontalAlignment="Center"
                          Margin="0,5,0,0"/>
            </StackPanel>
        </Border>

        <!-- 操作区域 -->
        <Border Grid.Row="1" Background="White" Margin="10">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>

                <!-- 操作按钮 -->
                <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10">
                    <Button x:Name="btnRefresh" Content="🔄 刷新用户列表" Click="BtnRefresh_Click" Width="120"/>
                    <Button x:Name="btnAdd" Content="➕ 添加用户" Click="BtnAdd_Click" Width="100"/>
                    <Button x:Name="btnEdit" Content="✏️ 编辑用户" Click="BtnEdit_Click" Width="100"/>
                    <Button x:Name="btnDelete" Content="🗑️ 删除用户" Click="BtnDelete_Click" Width="100" Background="#D9534F"/>
                    <TextBlock x:Name="txtUserCount" Text="用户数量: 0" Margin="20,0,0,0" VerticalAlignment="Center" FontWeight="Bold"/>
                </StackPanel>

                <!-- 用户列表 -->
                <DataGrid x:Name="dgUsers" 
                         Grid.Row="1" 
                         AutoGenerateColumns="False"
                         SelectionChanged="DgUsers_SelectionChanged">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="🔢 ID" Binding="{Binding Id}" Width="60"/>
                        <DataGridTextColumn Header="👤 姓名" Binding="{Binding Name}" Width="120"/>
                        <DataGridTextColumn Header="📧 邮箱" Binding="{Binding Email}" Width="200"/>
                        <DataGridTextColumn Header="🎂 年龄" Binding="{Binding Age}" Width="60"/>
                        <DataGridTextColumn Header="🆔 用户ID" Binding="{Binding Id}" Width="80"/>
                    </DataGrid.Columns>
                </DataGrid>
            </Grid>
        </Border>

        <!-- 状态栏 -->
        <StatusBar Grid.Row="2" Background="#E0E0E0">
            <StatusBarItem>
                <TextBlock x:Name="txtStatus" Text="就绪" FontWeight="Bold"/>
            </StatusBarItem>
            <Separator/>
            <StatusBarItem>
                <TextBlock x:Name="txtServerStatus" Text="服务器: 未连接"/>
            </StatusBarItem>
            <Separator/>
            <StatusBarItem>
                <TextBlock Text="API地址: https://localhost:7007"/>
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Windows;
using System.Windows.Controls;

namespace UserManagement.Client
{
    public partial class MainWindow : Window
    {
        private readonly HttpClient _httpClient;
        private const string BaseUrl = "https://localhost:7007/api/user";

        public MainWindow()
        {
            InitializeComponent();

            // 配置HTTP客户端,忽略SSL证书验证(仅开发环境)
            var handler = new HttpClientHandler();
            handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
            _httpClient = new HttpClient(handler);

            // 设置超时时间
            _httpClient.Timeout = TimeSpan.FromSeconds(30);

            // 程序启动时加载用户列表
            Loaded += async (s, e) => await LoadUsers();
        }

        private async System.Threading.Tasks.Task LoadUsers()
        {
            try
            {
                txtStatus.Text = "🔄 正在加载用户数据...";
                txtServerStatus.Text = "服务器: 连接中...";

                var response = await _httpClient.GetAsync(BaseUrl);
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync();
                var users = JsonSerializer.Deserialize<List<User>>(json,
                    new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

                dgUsers.ItemsSource = users;
                txtUserCount.Text = $"用户数量: {users?.Count ?? 0}";
                txtStatus.Text = "✅ 数据加载完成";
                txtServerStatus.Text = "服务器: 已连接";
                txtConnectionStatus.Text = $"✅ 已连接到服务器 - 共 {users?.Count ?? 0} 个用户";
            }
            catch (Exception ex)
            {
                txtStatus.Text = "❌ 加载失败";
                txtServerStatus.Text = "服务器: 连接失败";
                txtConnectionStatus.Text = "❌ 无法连接到服务器,请确保服务器正在运行";

                MessageBox.Show($"加载用户失败: {ex.Message}\n\n请检查:\n1. 服务器是否启动\n2. 网络连接是否正常",
                    "连接错误", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void BtnRefresh_Click(object sender, RoutedEventArgs e)
        {
            _ = LoadUsers(); // 使用丢弃操作符避免警告
        }

        private void DgUsers_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // 可以在这里添加选择改变的逻辑
        }

        private async void BtnAdd_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new UserDialog();
            if (dialog.ShowDialog() == true)
            {
                try
                {
                    var user = dialog.User;
                    var json = JsonSerializer.Serialize(user);
                    var content = new StringContent(json, Encoding.UTF8, "application/json");

                    var response = await _httpClient.PostAsync(BaseUrl, content);
                    response.EnsureSuccessStatusCode();

                    MessageBox.Show("✅ 用户添加成功!", "成功",
                        MessageBoxButton.OK, MessageBoxImage.Information);
                    await LoadUsers();
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"❌ 添加用户失败: {ex.Message}", "错误",
                        MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        private async void BtnEdit_Click(object sender, RoutedEventArgs e)
        {
            if (dgUsers.SelectedItem is User selectedUser)
            {
                var dialog = new UserDialog(selectedUser);
                if (dialog.ShowDialog() == true)
                {
                    try
                    {
                        var user = dialog.User;
                        var json = JsonSerializer.Serialize(user);
                        var content = new StringContent(json, Encoding.UTF8, "application/json");

                        var response = await _httpClient.PutAsync($"{BaseUrl}/{user.Id}", content);
                        response.EnsureSuccessStatusCode();

                        MessageBox.Show("✅ 用户更新成功!", "成功",
                            MessageBoxButton.OK, MessageBoxImage.Information);
                        await LoadUsers();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"❌ 更新用户失败: {ex.Message}", "错误",
                            MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }
            else
            {
                MessageBox.Show("⚠️ 请先选择一个要编辑的用户", "提示",
                    MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }

        private async void BtnDelete_Click(object sender, RoutedEventArgs e)
        {
            if (dgUsers.SelectedItem is User selectedUser)
            {
                var result = MessageBox.Show(
                    $"⚠️ 确定要删除用户 [{selectedUser.Name}] 吗?\n此操作不可撤销!",
                    "确认删除",
                    MessageBoxButton.YesNo,
                    MessageBoxImage.Warning);

                if (result == MessageBoxResult.Yes)
                {
                    try
                    {
                        var response = await _httpClient.DeleteAsync($"{BaseUrl}/{selectedUser.Id}");
                        response.EnsureSuccessStatusCode();

                        MessageBox.Show("✅ 用户删除成功!", "成功",
                            MessageBoxButton.OK, MessageBoxImage.Information);
                        await LoadUsers();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"❌ 删除用户失败: {ex.Message}", "错误",
                            MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }
            else
            {
                MessageBox.Show("⚠️ 请先选择一个要删除的用户", "提示",
                    MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }
    }

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public int Age { get; set; }
    }
}

UserDialog.xaml

<Window x:Class="UserManagement.Client.UserDialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="用户信息" 
        Height="300" 
        Width="400"
        WindowStartupLocation="CenterOwner"
        ResizeMode="NoResize"
        Background="#f5f5f5">

    <Border Margin="20" Background="White" CornerRadius="5" Padding="20">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <TextBlock Text="👤 姓名:" Grid.Row="0" Grid.Column="0" Margin="0,0,10,10" VerticalAlignment="Center"/>
            <TextBox x:Name="txtName" Grid.Row="0" Grid.Column="1" Margin="0,0,0,10" Height="30" Padding="5"/>

            <TextBlock Text="📧 邮箱:" Grid.Row="1" Grid.Column="0" Margin="0,0,10,10" VerticalAlignment="Center"/>
            <TextBox x:Name="txtEmail" Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" Height="30" Padding="5"/>

            <TextBlock Text="🎂 年龄:" Grid.Row="2" Grid.Column="0" Margin="0,0,10,10" VerticalAlignment="Center"/>
            <TextBox x:Name="txtAge" Grid.Row="2" Grid.Column="1" Margin="0,0,0,20" Height="30" Padding="5"/>

            <StackPanel Grid.Row="4" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right">
                <Button x:Name="btnOk" Content="✅ 确定" Width="80" Margin="0,0,10,0" Click="BtnOk_Click" Background="#5CB85C"/>
                <Button x:Name="btnCancel" Content="❌ 取消" Width="80" Click="BtnCancel_Click" Background="#D9534F"/>
            </StackPanel>
        </Grid>
    </Border>
</Window>

UserDialog.xaml.cs

using System.Windows;

namespace UserManagement.Client
{
    public partial class UserDialog : Window
    {
        public User User { get; private set; }

        public UserDialog(User user = null)
        {
            InitializeComponent();

            if (user != null)
            {
                User = user;
                txtName.Text = user.Name;
                txtEmail.Text = user.Email;
                txtAge.Text = user.Age.ToString();
                Title = "✏️ 编辑用户信息";
            }
            else
            {
                User = new User();
                Title = "➕ 添加新用户";
            }
        }

        private void BtnOk_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtName.Text))
            {
                MessageBox.Show("请输入用户姓名", "验证错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                txtName.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(txtEmail.Text) || !txtEmail.Text.Contains("@"))
            {
                MessageBox.Show("请输入有效的邮箱地址", "验证错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                txtEmail.Focus();
                return;
            }

            if (!int.TryParse(txtAge.Text, out int age) || age < 1 || age > 150)
            {
                MessageBox.Show("请输入有效的年龄(1-150)", "验证错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                txtAge.Focus();
                return;
            }

            User.Name = txtName.Text.Trim();
            User.Email = txtEmail.Text.Trim();
            User.Age = age;

            DialogResult = true;
            Close();
        }

        private void BtnCancel_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
            Close();
        }
    }
}

这样服务器端和客户端的简单代码都写好了。
不过要是启动的话,还需要配置启动顺序,要先启动服务器,再启动客户端
image

image

配置完以后点启动。启动后会弹出三个窗口。
一个是客户端窗口
一个是服务器日志
还有一个是所有接口的界面,类似postman,可以调试接口通不通
image

posted @ 2025-11-22 23:55  臧博涛  阅读(16)  评论(0)    收藏  举报