news 2026/3/6 17:52:30

WPF HTTPS 通信示例代码分析笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WPF HTTPS 通信示例代码分析笔记

一、项目整体结构

该项目是一个基于 WPF 的 HTTPS 通信演示程序,采用 MVVM 设计模式,主要实现了 GET/POST/PUT/DELETE 四种 HTTP 请求的发送,并展示响应结果。项目分为三个核心部分:

  • 模型层(Model):定义请求和响应的数据结构

  • 视图模型层(ViewModel):处理业务逻辑,实现数据绑定和命令绑定

  • 视图层(View):MainWindow.xaml,负责 UI 展示

二、模型层(Model)代码分析

1. 功能说明

定义HttpRequestModel(HTTP 请求模型)和HttpResponseModel(HTTP 响应模型),封装请求 / 响应的核心属性,提供默认构造函数初始化默认值。

2. 核心代码

using System; using System.Collections.Generic; ​ namespace HttpsDemoApp.Model { // HTTP请求模型:封装请求的URL、方法、请求体、请求头 public class HttpRequestModel { public string Url { get; set; } public string Method { get; set; } public string RequestBody { get; set; } public Dictionary<string, string> Headers { get; set; } ​ // 构造函数:初始化请求头字典,默认请求方法为GET public HttpRequestModel() { Headers = new Dictionary<string, string>(); Method = "GET"; } } ​ // HTTP响应模型:封装响应的状态码、状态信息、响应内容、响应头、响应时间 public class HttpResponseModel { public int StatusCode { get; set; } public string StatusMessage { get; set; } public string Content { get; set; } public Dictionary<string, string> Headers { get; set; } public DateTime ResponseTime { get; set; } ​ // 构造函数:初始化响应头字典,默认响应时间为当前时间 public HttpResponseModel() { Headers = new Dictionary<string, string>(); ResponseTime = DateTime.Now; } } }

3. 关键要点

  • HttpRequestModel:默认方法为 GET,请求头初始化为空字典

  • HttpResponseModel:响应时间默认取当前时间,响应头初始化为空字典

  • 采用Dictionary<string, string>存储请求 / 响应头,便于键值对管理

三、视图模型层(ViewModel)代码分析

1. 功能说明

实现MainViewModel(核心视图模型)和RelayCommand(命令绑定实现),处理 HTTP 请求发送逻辑,实现INotifyPropertyChanged接口支持数据双向绑定。

2. 核心代码(MainViewModel)

using HttpsDemoApp.Model; using System; using System.ComponentModel; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Windows.Input; ​ namespace HttpsDemoApp.ViewModel { // 主视图模型:实现INotifyPropertyChanged支持属性变更通知 public class MainViewModel : INotifyPropertyChanged { // 私有字段 private string _url; private string _method; private string _requestBody; private string _responseContent; private bool _isLoading; private HttpResponseModel _response; ​ // 属性变更事件 public event PropertyChangedEventHandler PropertyChanged; ​ // 公开属性(带变更通知) public string Url { get { return _url; } set { _url = value; OnPropertyChanged(nameof(Url)); } } ​ public string Method { get { return _method; } set { _method = value; OnPropertyChanged(nameof(Method)); } } ​ public string RequestBody { get { return _requestBody; } set { _requestBody = value; OnPropertyChanged(nameof(RequestBody)); } } ​ public string ResponseContent { get { return _responseContent; } set { _responseContent = value; OnPropertyChanged(nameof(ResponseContent)); } } ​ public bool IsLoading { get { return _isLoading; } set { _isLoading = value; OnPropertyChanged(nameof(IsLoading)); } } ​ public HttpResponseModel Response { get { return _response; } set { _response = value; OnPropertyChanged(nameof(Response)); } } ​ // 发送请求命令 public ICommand SendRequestCommand { get; private set; } ​ // 构造函数:初始化默认值,绑定命令 public MainViewModel() { Url = "https://jsonplaceholder.typicode.com/posts/1"; // 测试URL Method = "GET"; RequestBody = ""; ResponseContent = ""; IsLoading = false; SendRequestCommand = new RelayCommand(async param => await SendRequestAsync()); } ​ // 属性变更通知方法 protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } ​ // 异步发送HTTP请求核心方法 private async Task SendRequestAsync() { IsLoading = true; ResponseContent = "正在发送请求..."; ​ try { using (var httpClient = new HttpClient()) { HttpResponseMessage response = null; ​ // 根据请求方法执行不同操作 switch (Method.ToUpper()) { case "GET": response = await httpClient.GetAsync(Url); break; case "POST": var content = new StringContent(RequestBody, Encoding.UTF8, "application/json"); response = await httpClient.PostAsync(Url, content); break; case "PUT": var putContent = new StringContent(RequestBody, Encoding.UTF8, "application/json"); response = await httpClient.PutAsync(Url, putContent); break; case "DELETE": response = await httpClient.DeleteAsync(Url); break; } ​ // 处理响应结果 if (response != null) { var responseModel = new HttpResponseModel { StatusCode = (int)response.StatusCode, StatusMessage = response.ReasonPhrase, Content = await response.Content.ReadAsStringAsync(), ResponseTime = DateTime.Now }; ​ // 解析响应头 foreach (var header in response.Headers) { responseModel.Headers.Add(header.Key, string.Join(", ", header.Value)); } ​ Response = responseModel; // 格式化响应内容展示 ResponseContent = $"状态码: {responseModel.StatusCode} {responseModel.StatusMessage}\n\n" + $"响应时间: {responseModel.ResponseTime}\n\n" + $"响应内容:\n{responseModel.Content}"; } } } catch (HttpRequestException ex) { // HTTP请求异常处理 ResponseContent = $"HTTP 请求异常: {ex.Message}\n\n" + $"Inner Exception: {ex.InnerException?.Message}"; } catch (Exception ex) { // 通用异常处理 ResponseContent = $"异常: {ex.Message}\n\n" + $"Stack Trace: {ex.StackTrace}"; } finally { IsLoading = false; // 无论是否异常,最终结束加载状态 } } } }

3. 核心代码(RelayCommand)

// 命令实现类:支持异步执行的RelayCommand public class RelayCommand : ICommand { private readonly Func<object, Task> _execute; private readonly Func<object, bool> _canExecute; ​ public event EventHandler CanExecuteChanged; ​ // 构造函数:初始化执行方法和可执行判断方法 public RelayCommand(Func<object, Task> execute, Func<object, bool> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } ​ // 判断命令是否可执行 public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(parameter); } ​ // 执行命令(异步) public async void Execute(object parameter) { await _execute(parameter); } ​ // 触发可执行状态变更 public void RaiseCanExecuteChanged() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } }

4. 关键要点

(1)MVVM 核心特性
  • 实现INotifyPropertyChanged接口:通过OnPropertyChanged方法触发属性变更通知,使 UI 自动更新

  • 命令绑定:通过RelayCommand将按钮点击事件绑定到SendRequestAsync方法

  • 异步处理:使用async/await处理 HTTP 请求,避免 UI 线程阻塞

(2)HTTP 请求处理
  • 支持 GET/POST/PUT/DELETE 四种方法,POST/PUT 默认使用 JSON 格式请求体(UTF8 编码)

  • 使用HttpClient发送请求,通过using语句自动释放资源

  • 异常处理:区分HttpRequestException(HTTP 相关异常)和通用异常,友好展示错误信息

(3)状态管理
  • IsLoading:控制加载进度条显示,请求发送时设为 true,结束后设为 false

  • 响应结果格式化:将状态码、响应时间、响应内容拼接展示在ResponseContent

四、视图层(View)代码分析

1. 功能说明

MainWindow.xaml 作为 UI 界面,通过数据绑定关联 ViewModel 的属性和命令,实现用户交互和结果展示。

2. 核心代码

<Window x:Class="HttpsDemoApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:HttpsDemoApp" xmlns:vm="clr-namespace:HttpsDemoApp.ViewModel" mc:Ignorable="d" Title="WPF HTTPS 通信示例" Height="600" Width="900"> <Window.Resources> <!-- 布尔值转可见性转换器 --> <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" /> <!-- 自定义布尔值反转转换器(需实现) --> <local:BoolToInverseBoolConverter x:Key="BoolToInverseBoolConverter" /> </Window.Resources> <!-- 绑定视图模型作为数据上下文 --> <Window.DataContext> <vm:MainViewModel /> </Window.DataContext> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="100" /> </Grid.ColumnDefinitions> ​ <!-- URL输入框 --> <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Label Content="URL:" VerticalAlignment="Center" Margin="0,0,10,0" /> <TextBox Text="{Binding Url}" Grid.Column="1" Height="30" VerticalContentAlignment="Center" /> </Grid> ​ <!-- 请求方法选择和发送按钮 --> <Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="100" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="100" /> </Grid.ColumnDefinitions> <Label Content="方法:" VerticalAlignment="Center" Margin="0,0,10,0" /> <ComboBox SelectedValue="{Binding Method}" SelectedValuePath="Content" Grid.Column="1" Height="30"> <ComboBoxItem Content="GET" /> <ComboBoxItem Content="POST" /> <ComboBoxItem Content="PUT" /> <ComboBoxItem Content="DELETE" /> </ComboBox> <!-- 发送按钮:绑定命令,加载时禁用 --> <Button Content="发送请求" Grid.Column="3" Height="30" Command="{Binding SendRequestCommand}" IsEnabled="{Binding IsLoading, Converter={StaticResource BoolToInverseBoolConverter}}" /> </Grid> ​ <!-- 请求体输入框 --> <Grid Grid.Row="2" Grid.Column="0" Margin="0,0,0,9.667" HorizontalAlignment="Left" Width="402"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Label Content="请求体:" Margin="0,0,0,5" /> <TextBox Text="{Binding RequestBody}" Grid.Row="1" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Margin="0,0.333,-52,-0.333" /> </Grid> ​ <!-- 响应内容展示框 --> <Grid Grid.Row="2" Grid.Column="1" Margin="0,0,0,10"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="20*" /> <RowDefinition Height="23*"/> </Grid.RowDefinitions> <Label Content="响应:" Margin="0,0,0,4.667" /> <TextBox Text="{Binding ResponseContent}" Grid.Row="1" IsReadOnly="True" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Margin="-307,0,0,-0.333" Grid.RowSpan="2" /> </Grid> ​ <!-- 加载进度条 --> <Grid Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"> <ProgressBar IsIndeterminate="{Binding IsLoading}" Height="10" Visibility="{Binding IsLoading, Converter={StaticResource BoolToVisibilityConverter}}"></ProgressBar> </Grid> </Grid> </Window>

3. 关键要点

(1)数据绑定
  • Window.DataContext:绑定MainViewModel作为整个窗口的数据上下文

  • 控件绑定:

    • URL 输入框:Text="{Binding Url}"

    • 请求方法下拉框:SelectedValue="{Binding Method}"

    • 请求体输入框:Text="{Binding RequestBody}"

    • 响应内容展示框:Text="{Binding ResponseContent}"(只读)

    • 发送按钮:Command="{Binding SendRequestCommand}"

(2)转换器使用
  • BooleanToVisibilityConverter:将IsLoading(bool)转为进度条的可见性(Visibility)

  • BoolToInverseBoolConverter:反转IsLoading值,实现加载时禁用发送按钮(需补充实现该转换器类)

(3)UI 布局
  • 采用 Grid 布局,分行列管理控件位置,适配窗口大小

  • 请求体和响应内容使用多行文本框(AcceptsReturn="True"),支持换行和滚动条

五、补充说明(缺失的转换器实现)

代码中引用了BoolToInverseBoolConverter但未实现,需补充:

using System; using System.Globalization; using System.Windows.Data; ​ namespace HttpsDemoApp { public class BoolToInverseBoolConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is bool boolValue) { return !boolValue; } return false; } ​ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value is bool boolValue) { return !boolValue; } return false; } } }

六、整体总结

1. 设计模式

  • MVVM 模式:分离 UI(View)、业务逻辑(ViewModel)、数据(Model),降低耦合

  • 命令模式:通过RelayCommand实现 UI 操作与业务逻辑的解耦

2. 核心特性

  • 异步 HTTP 请求:避免 UI 阻塞,提升用户体验

  • 数据双向绑定:属性变更自动同步到 UI,UI 输入自动同步到 ViewModel

  • 异常处理:区分不同类型异常,友好展示错误信息

  • 状态管理:加载状态控制进度条和按钮可用状态

3. 改进建议

  • 增加请求头自定义功能(当前 Model 支持但 UI 未实现)

  • 优化响应内容格式化(如 JSON 格式化展示)

  • 添加请求超时设置(HttpClient.Timeout

  • 增加请求参数验证(如 URL 格式校验)

  • 完善日志记录,便于调试

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/4 2:45:22

Keysight 3000T X多总线协议触发实测

Keysight 3000T X系列示波器作为一款高性能混合信号示波器&#xff0c;因其丰富的总线协议触发功能&#xff0c;在复杂数字系统调试中表现尤为出色。本文结合实际测试场景&#xff0c;探讨Keysight 3000T X多总线协议触发功能的原理、操作步骤及实测体验&#xff0c;帮助工程师…

作者头像 李华
网站建设 2026/2/26 11:19:06

第一性原理计算:什么是晶体缺陷?

一、什么是晶体缺陷&#xff1f;晶体缺陷是指实际晶体中原子、离子或分子排列偏离理想完美周期性结构的局部不规则区域。在理论上&#xff0c;理想晶体中的粒子应严格按照空间格子重复排列&#xff0c;但现实材料由于生长过程、热运动、外部辐照或机械应力等因素&#xff0c;总…

作者头像 李华
网站建设 2026/3/4 13:08:34

艾体宝产品 | 隆重推出 Haink:Redis 的应用型 AI 智能体

认识 Haink&#xff0c;Redis 的全天候 AI 队友 各行各业的团队正在转向使用 AI 智能体&#xff0c;以加快工作节奏并提升工作智能化水平。在 Redis&#xff0c;我们从零开始构建了一个&#xff0c;以展示将 Redis 作为基础能实现何种可能。 来认识一下 Haink&#xff0c;一个由…

作者头像 李华
网站建设 2026/2/28 19:03:36

如何使用苏培Modbus TCP总线网关与西门子1200系列PLC通讯

01概述Modbus TCP通讯协议是由Modicon公司&#xff08;现已经为施耐德公司并购&#xff0c;成为其旗下的子品牌&#xff09;于1979年发明的&#xff0c;是全球最早用于工业现场的总线规约。Modbus通信协议采用的是主从通信模式&#xff08;即Master/Slave通信模式&#xff09;&…

作者头像 李华