You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows关机/注销时WPF应用发送HTTP Post请求失败问题求助

解决Windows关机/注销时HTTP请求无法完成的问题

你的核心问题在于系统不会等待SessionEnding事件中的异步操作完成——因为你的事件处理方法是async void,WPF和Windows的事件模型不会追踪这类异步方法的完成状态,会直接继续执行关机流程,导致你的HTTP请求还没完成就被终止了,而且这种进程终止不会触发常规的HttpRequestException,所以你的catch块根本没机会执行。

下面是具体的解决方案,结合你的代码修改:

关键思路

  1. 先阻止系统默认的关机流程:通过设置ev.Cancel = true,给异步请求留出执行时间;
  2. 完成HTTP请求后手动触发关机/注销:请求成功或失败后,再调用系统API执行对应的操作;
  3. 添加超时保护:避免HTTP请求卡住导致系统无法正常关机。

修改后的代码

App.xaml.cs

using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Newtonsoft.Json;
using System.Runtime.InteropServices;

namespace WpfApp1 {
    public partial class App : Application {
        static readonly HttpClient client = new();

        // 引入Windows API用于触发关机/注销
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool ExitWindowsEx(uint uFlags, uint dwReason);

        // 定义关机/注销的常量参数
        private const uint EWX_LOGOFF = 0x00;
        private const uint EWX_SHUTDOWN = 0x01;
        private const uint EWX_REBOOT = 0x02;
        private const uint EWX_FORCEIFHUNG = 0x10;

        private async void App_SessionEnding(object sender, SessionEndingCancelEventArgs ev) {
            // 第一步:阻止系统默认的关机/注销流程
            ev.Cancel = true;

            var evento = new Evento(Environment.UserName, Environment.MachineName, DateTime.Now, "Logout", "some-data");
            var json = JsonConvert.SerializeObject(evento);
            var data = new StringContent(json, Encoding.UTF8, "application/json");

            try {
                // 设置超时,避免请求无限等待(根据你的需求调整时长)
                client.Timeout = TimeSpan.FromSeconds(10);
                
                HttpResponseMessage response = await client.PostAsync("some-url", data);
                response.EnsureSuccessStatusCode();
                
                string responseBody = await response.Content.ReadAsStringAsync();
                await File.WriteAllTextAsync("WriteLines.txt", $"Success: {responseBody}");
            } catch (Exception e) {
                await File.WriteAllTextAsync("WriteLines.txt", $"Error: {e.Message}\nSession Reason: {ev.ReasonSessionEnding}");
                Console.WriteLine($"Exception Caught: {e.Message}");
            } finally {
                // 第二步:请求完成后,手动触发对应的关机/注销操作
                TriggerSystemAction(ev.ReasonSessionEnding);
            }
        }

        private void TriggerSystemAction(SessionEndReasons reason) {
            uint flags = EWX_FORCEIFHUNG; // 强制结束无响应的程序,避免卡住
            switch (reason) {
                case SessionEndReasons.Logoff:
                    flags |= EWX_LOGOFF;
                    break;
                case SessionEndReasons.Shutdown:
                case SessionEndReasons.SystemShutdown:
                    flags |= EWX_SHUTDOWN;
                    break;
                case SessionEndReasons.Restart:
                    flags |= EWX_REBOOT;
                    break;
            }
            ExitWindowsEx(flags, 0);
        }
    }

    // 确保你的Evento类定义正确
    public class Evento {
        public string UserName { get; set; }
        public string MachineName { get; set; }
        public DateTime Timestamp { get; set; }
        public string Action { get; set; }
        public string Data { get; set; }

        public Evento(string userName, string machineName, DateTime timestamp, string action, string data) {
            UserName = userName;
            MachineName = machineName;
            Timestamp = timestamp;
            Action = action;
            Data = data;
        }
    }
}

关键细节说明

  • ev.Cancel = true:这是核心,只有阻止了系统的默认流程,你的异步请求才有机会完整执行;
  • HttpClient.Timeout:必须设置超时,否则如果请求卡住(比如目标服务器无响应),系统会一直停留在等待状态,无法关机;
  • ExitWindowsEx API:相比WPF自带的Application.Shutdown,这个系统API能更准确地触发系统级的注销、关机等操作,符合你的场景;
  • finally块:确保无论请求成功还是失败,都会执行后续的关机操作,避免系统卡住。

测试建议

为了避免频繁关机调试,你可以暂时把client.PostAsync换成一个延迟操作,比如:

await Task.Delay(5000); // 模拟5秒的请求耗时

这样能验证你的代码逻辑是否正确,确认系统会等待异步操作完成后再执行关机。

内容的提问来源于stack exchange,提问作者Sebastian Ciocarlan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 04:37:36