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

如何为HttpClient扩展方法添加绑定到具体实例的EventHandler事件?

HttpClient实例级错误事件实现方案

需求完全可以实现,以下是两种常用的实现方式:

方案1:使用ConditionalWeakTable绑定实例与事件

该方案不需要修改原有HttpClient的创建逻辑,直接通过扩展方法实现事件与实例的绑定,使用ConditionalWeakTable做弱引用存储,不会阻碍HttpClient实例的正常垃圾回收。

实现代码

public static class HttpClientExtensions
{
    // 弱引用映射表,键为HttpClient实例,值为对应绑定的错误事件委托
    private static readonly ConditionalWeakTable<HttpClient, EventHandler<HttpClientErrorEventArgs>> _errorEventMap = new();

    // 扩展方法:为当前HttpClient实例绑定错误处理事件
    public static void AddErrorHandler(this HttpClient client, EventHandler<HttpClientErrorEventArgs> handler)
    {
        _errorEventMap.AddOrUpdate(client, handler);
    }

    public async static Task<T> GetSomthingSpecialAsync<T>(this HttpClient client, string url)
    {
        using var response = await client.GetAsync(url);
        if (response.StatusCode != System.Net.HttpStatusCode.OK)
        {
            // 触发当前实例绑定的错误事件
            if (_errorEventMap.TryGetValue(client, out var errorHandler))
            {
                errorHandler(client, new HttpClientErrorEventArgs()
                {
                    StatusCode = response.StatusCode,
                    Message = $"{response.StatusCode} {(int)response.StatusCode}"
                });
            }
            return default;
        }
        response.EnsureSuccessStatusCode();
        // 剩余业务逻辑
        // [... ]
    }
}

public class HttpClientErrorEventArgs : EventArgs
{
    public System.Net.HttpStatusCode StatusCode { get; set; }
    public string Message { get; set; }
}

使用方式

// 不同HttpClient实例可绑定独立的错误处理逻辑
var clientA = new HttpClient();
clientA.AddErrorHandler((sender, e) => 
{
    Console.WriteLine($"客户端A请求错误:{e.Message}");
});

var clientB = new HttpClient();
clientB.AddErrorHandler((sender, e) => 
{
    Console.WriteLine($"客户端B请求错误:{e.Message}");
});

方案2:自定义HttpMessageHandler(官方推荐)

这是.NET官方推荐的扩展HttpClient行为的实现方式,所有走该Handler的请求都会自动触发事件,无需在每个扩展方法中重复编写事件触发逻辑,可维护性更高。

实现代码

// 自定义请求处理Handler,内置错误事件
public class ErrorCaptureHandler : DelegatingHandler
{
    public event EventHandler<HttpClientErrorEventArgs> ErrorOccurred;

    public ErrorCaptureHandler(HttpMessageHandler innerHandler = null)
    {
        InnerHandler = innerHandler ?? new HttpClientHandler();
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);
        if (!response.IsSuccessStatusCode)
        {
            ErrorOccurred?.Invoke(request, new HttpClientErrorEventArgs
            {
                StatusCode = response.StatusCode,
                Message = $"{response.StatusCode} {(int)response.StatusCode}"
            });
        }
        return response;
    }
}

// 你原有的扩展方法不需要再处理事件触发逻辑
public static class HttpClientExtensions
{
    public async static Task<T> GetSomthingSpecialAsync<T>(this HttpClient client, string url)
    {
        using var response = await client.GetAsync(url);
        if (response.StatusCode != System.Net.HttpStatusCode.OK)
        {
            return default;
        }
        response.EnsureSuccessStatusCode();
        // 剩余业务逻辑
        // [... ]
    }
}

public class HttpClientErrorEventArgs : EventArgs
{
    public System.Net.HttpStatusCode StatusCode { get; set; }
    public string Message { get; set; }
}

使用方式

// 创建HttpClient时传入自定义Handler,每个实例绑定独立事件
var handlerA = new ErrorCaptureHandler();
handlerA.ErrorOccurred += (sender, e) => Console.WriteLine($"客户端A请求错误:{e.Message}");
var clientA = new HttpClient(handlerA);

var handlerB = new ErrorCaptureHandler();
handlerB.ErrorOccurred += (sender, e) => Console.WriteLine($"客户端B请求错误:{e.Message}");
var clientB = new HttpClient(handlerB);

内容的提问来源于stack exchange,提问作者Chris Berlin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 02:45:03