【问题标题】:How to set HttpMessageHandler on Flurl calls globally without calling Configure()如何在不调用 Configure() 的情况下全局设置 Flurl 调用上的 HttpMessageHandler
【发布时间】:2020-07-08 13:28:48
【问题描述】:

我正在构建一个供内部使用的小型库,它依赖 Flurl 来处理所有传出的 HTTP 调用。

我想为这个库的使用者提供选择加入我们的 HTTP 调用跟踪基础设施的能力,如下所示:

Startup.cs:

... 

public void ConfigureServices(IServiceCollection services)
{
    ....
    services.AddTracing(options => ...);
    ....
}

...

我当前的AddTracing() 实现如下所示:

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddTracing(this IServiceCollection services, Action<TracingOptions> configureOptions)
    {
        var tracingOptions = new TracingOptions();
        configureOptions(tracingOptions);

        // Make these options available in DI container
        services.AddSingleton(tracingOptions);

        FlurlHttp.Configure(settings =>
        {
            settings.HttpClientFactory = new TracingHttpClientFactory(tracingOptions.ApplicationName);
        });

        return services;
    }
}

TracingHttpClientFactory 的当前实现如下所示:

public class TracingHttpClientFactory : DefaultHttpClientFactory
{
    private readonly string _applicationName;

    public TracingHttpClientFactory(string applicationName)
    {
        _applicationName = applicationName;
    }

    // override to customize how HttpMessageHandler is created/configured
    public override HttpMessageHandler CreateMessageHandler()
    {
        var tracingHandler = new TracingHandler(_applicationName, base.CreateMessageHandler());

        return tracingHandler;
    }
}

这可行,但我面临的问题是Configure() 的文档显示:只应在应用程序启动时调用一次。

因此,我通过添加跟踪(这是可选的)“浪费了”我对Configure() 的调用。在使用tracing的场景下,我之后还需要调用Configure()

我可能需要在之后调用 configure 的一个示例是在 Startup.cs 中:

... 

public void ConfigureServices(IServiceCollection services)
{
    ....
    // Configure() is being called inside AddTracing()
    services.AddTracing(options => ...);
    ....
    // This is a second call to Configure()
    FlurlHttp.Configure(settings => {
        var jsonSettings = new JsonSerializerSettings
        {
            ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
        };
        settings.JsonSerializer = new NewtonsoftJsonSerializer(jsonSettings);
    });
}
...

重点是——AddTracing() 的每个消费者都应该能够按照他们认为合适的方式配置 Flurl。 AddTracing() 的重点是简单地为 Flurl “增压”一些额外的可选功能。它并不是要接管 Configure() - 它是为了扩展它。

我一直在阅读文档here,尽管有很多地方可以进行配置,但我无法找到获得我的TracingHandler(这是一个HttpMessageHander)的方法无需在某处调用 Configure() 即可处理每个请求。

是否有适合我描述的场景的实现?

【问题讨论】:

  • "在使用tracing的场景下,我之后还需要调用Configure()。"为什么?你能详细说明那部分吗?
  • 我已进行了编辑并添加了额外说明

标签: c# asp.net-core flurl


【解决方案1】:

“启动时调用一次”建议的原因是它涉及全局范围。如果您开始在许多不同的地方弄乱全局设置,可能是在不同的线程上(例如在控制器操作方法中),您最终可能会遇到奇怪的竞争条件和其他不可预测的行为。

在您的情况下,是的,您调用了两次 Configure,但调用是连续的、非冲突的,并且在“启动”代码属于 ASP.NET Core 应用程序的地方正确完成。最重要的是,它们是在使用 Flurl 进行任何调用之前完成的。所以你在这里做的很好。

【讨论】:

  • 这很有帮助 - 谢谢。现在这对我有用,但我立即想象一些图书馆使用者不小心覆盖了我的 HttpClientFactory 甚至不知道他们做错了什么。一般来说,跟踪库消费者不应该知道或关心“services.AddTracing()”在做什么。我看到你是 Flurl 的主要贡献者,所以我确定如果有更好的方法,你会告诉我的 :) 再次感谢您的帮助。
  • 请记住,services.AddXXX 方法通常用于添加/配置注入服务,而不是更改全局设置。 “更好的方法”可能是将工厂设置为注入的FlurlClients,这更符合 IoC 模式,但是您必须告诉您的用户“当您使用这样的注入客户端时,跟踪有效”而不是而不是“无论您如何使用 Flurl,跟踪都可以在任何地方工作”。底线:如果您的图书馆可以在全球范围内配置 Flurl,那么您的图书馆的消费者也可以,除了告诉您的用户“不要那样做”之外,我想不出任何办法。
  • 是的 - 有道理。我知道我通过这种模式有点滥用 AddXXX。这是我首先发表这篇文章的主要原因。感谢您的反馈。
猜你喜欢
  • 2022-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多