【问题标题】:Verify that my DelegatingHandler was added to IHttpClientBuilder验证我的 DelegatingHandler 是否已添加到 IHttpClientBuilder
【发布时间】:2020-08-31 22:08:46
【问题描述】:

我的代码将命名为 HttpClient 添加到 ServiceCollection 并将 DelegatingHandler 添加到客户端。示例代码:

public class MyDelegatingHandler : DelegatingHandler
{
    // ...
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) =>
        {
            services.AddHttpClient("MyClient")
                .AddHttpMessageHandler(provider => new MyDelegatingHandler());
        });

在编写单元测试时,如何验证添加的DelegatingHandler 实现是MyDelegatingHanlder

【问题讨论】:

    标签: c# .net-core dependency-injection delegatinghandler


    【解决方案1】:

    此信息存储在HttpClient 的私有字段中。你可以理解它,但它有点不正统。所以,你可能感兴趣也可能不感兴趣,但我会把它扔在那里,以防你:

    public static class HttpClientExtensions
    {
        public static bool ContainsDelegatingHandler<TDelegatingHandler>(
            this HttpClient httpClient) where TDelegatingHandler: DelegatingHandler
        {
            if(httpClient == null)
            {
                throw new ArgumentNullException(nameof(httpClient));
            }
    
            var internalHandlerField = typeof(HttpMessageInvoker).GetField(
                "_handler", BindingFlags.NonPublic | BindingFlags.Instance);
            if(internalHandlerField == null)
            {
                throw new InvalidOperationException(
                    "_handler no longer exists as a private instance field of HttpClient");
            }
    
            // run down the chain of delegating handlers until there are no more
            var delegatingHandler = internalHandlerField.GetValue(httpClient) as DelegatingHandler;
            while (delegatingHandler != null)
            {
                if(delegatingHandler.GetType() == typeof(TDelegatingHandler))
                {
                    return true;
                }
                delegatingHandler = delegatingHandler.InnerHandler as DelegatingHandler;
            }
    
            return false;
        }
    }
    

    要进行测试,您首先必须使用工厂创建一个HttpClient

    var httpClient = httpClientFactory.CreateClient("MyClient");
    

    然后通过扩展运行它:

    if(!httpClient.ContainsDelegatingHandler<MyDelegatingHandler>())
    {
        throw new Exception(
            "HttpClient with name 'MyClient' does not contain " +
            $"{nameof(MyDelegatingHandler)} delegating handler.");
    }
    

    【讨论】:

    • 总有办法的,你已经告诉我了!感谢您的回答。同意,这远非最佳实践,但在测试环境下,我会说这可能是可以接受的。问完这个问题后我给了它更多的想法,我认为更合适的方法是创建一个可以模拟的DelegatingHandlerFactory,并使用它来创建注册MyDelegatingHandler作为消息处理程序。感谢您的帮助。
    • @Klicker -- 我也打算这样建议 -- 但有时人们反对在他们的负载中添加“模拟工作”。所以这是一种“2鸟/1石头”的事情。祝你好运!
    • 尽管在考虑了这个更多之后,我意识到添加工厂将允许我验证 MyDelegatingHandler 是否已创建,但不能验证它是否已分配给HttpClient。虽然可能不是最佳实践,但您的解决方案让我对帖子中的代码示例充满信心。
    • @Klicker -- 绝对。一旦你调用CreateClient,委托处理程序将被实例化——但你如何检查它是否被实例化?您可以在处理程序中创建一个静态事件字段,该字段可以在测试时从 Ctor 触发以命中某个委托,但是您正在将测试代码与生产代码混合。我不知道你还能怎么干净。
    猜你喜欢
    • 2012-07-30
    • 2020-11-05
    • 2018-06-25
    • 1970-01-01
    • 2015-03-09
    • 2022-04-29
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多