微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 SimpleInjector

如何解决使用 SimpleInjector

根据 https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory#extending-the-convenience-addtransienthttperrorpolicy-definition,我可以看到添加一个名称的策略。

var httpClientOptions = HttpPolicyExtensions
    .HandleTransientHttpError()
    .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
    .WaitAndRetryAsync(6,retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,retryAttempt)));

services.AddHttpClient(/*have to add a name*/)
    .AddPolicyHandler(httpClientOptions);

我使用 Simple Injector 与 .net 依赖项注入并行,并将 http 客户端工厂注入到我的消费类中,如下所示:

public polygonIoApiFetcher(IHttpClientFactory clientFactory)
{
    this.client = clientFactory.CreateClient(/* what to use here */);    
}

我的问题是我在其他库中编写了许多函数,这些函数不一定在库之间共享客户端工厂策略名称

此外,为了简单起见,我可能希望为工厂创建的所有 HttpClient 使用一个 poly 重试策略 - IHttpClientFactory 有什么方法可以返回认的 HttpClient是否应用了认的 poly 策略?

我不想对每个 https://github.com/simpleinjector/SimpleInjector/issues/654 使用类型化注册,我需要通过注入的 IHttpClientFactory 而不是注入的 HttpClient 来控制对象的生命周期消费类。

总而言之,启动时的连接/注入应该决定注入和轻松重新连接/更改的策略,而不是由消费类决定。

我已经提供了到目前为止我所做的事情,但如果我怀疑这是一个已经解决的问题,请指点迷津。

下面的想法 - 创建一个包装类

HttpClient CreateClient(this IHttpClientFactory factory) 中的无参数 System.Net.Http 扩展方法不能被覆盖,所以我想使用包装类并在注入过程中手动选择策略:

public interface IPollyHttpClientFactory
{
    HttpClient CreateClient();
}

public class PollyHttpClientFactoryWrapper
{
    private readonly string policyName;
    private readonly Container container;

    public PollyHttpClientFactoryWrapper(
        string policyName,Container container)
    {
        this.policyName = policyName ?? throw new ArgumentNullException();
        this.container = container ?? throw new ArgumentNullException();
    }

    public HttpClient CreateClient()
    {
        return this.container
            .GetInstance<IHttpClientFactory>()
            .CreateClient(this.policyName);
    }
}

注册时使用:

Container.RegisterSingleton<IHistoricalAggregates>(
    () => new polygonIoApiFetcher(
        new PollyHttpClientFactoryWrapper("RetryPolicy",Container),Container.GetInstance<ApiKeys>().polygonIoApiKey));

唯一的“问题”是我的类需要使用 IPollyHttpClientFactory 接口,但我可以接受。

解决方法

我不确定我能不能给你一个满意的答案,但这里有一个可能实现的想法。您可以使 IPollyHttpClientFactory 成为有条件的,让每个使用者都获得自己的版本。这可以使用 RegisterConditional 方法完成。例如:

var container = new Container();

container.RegisterSingleton<IHistoricalAggregates,PolygonIoApiFetcher>();

container.RegisterConditional(
    typeof(IPollyHttpClientFactory),c => typeof(PollyHttpClientFactory<>)
             .MakeGenericType(c.Consumer.ImplementationType),Lifestyle.Singleton,c => true);

container.MapPolicy<PolygonIoApiFetcher>("RetryPolicy");

此处,MapPolicy 是自定义扩展方法:

public static class ContainerPolicyExtensions
{
    public static void MapPolicy<TImplementation>(
        this Container container,string policyName) =>
        container.RegisterInstance(new Policy<TImplementation>(policyName));
}

Policy<> 是一个简单的通用数据对象,它允许保存要用于 HttpClient 的策略名称(您可以向该策略类添加与创建 http 客户端相关的任何其他数据):

public sealed record Policy<TConsumer>(string PolicyName);

PollyHttpClientFactory<>IPollyHttpClientFactory 的通用实现。它被注入了相关的 Policy<T>,因此能够创建特定于其使用者的 http 客户端:

public record PollyHttpClientFactory<TConsumer>(
    IHttpClientFactory Factory,Policy<TConsumer> Policy)
    : IPollyHttpClientFactory
{
    public HttpClient CreateClient() =>
        this.Factory.CreateClient(Policy.PolicyName);
}

或者,您可以将 RegisterMapPolicy 方法合并为一个扩展方法:

public static void RegisterWithPolicy<TService,TImplementation>(
    this Container container,string policyName,Lifestyle lifestyle = null)
    where TService : class
    where TImplementation : class,TService
{
    if (lifestyle is null) container.Register<TService,TImplementation>();
    else container.Register<TService,TImplementation>(lifestyle);
    container.MapPolicy<TImplementation>(policyName);
}

这让您可以一举完成注册和映射:

container.RegisterWithPolicy<IHistoricalAggregates,PolygonIoApiFetcher>(
    "RetryPolicy",Lifestyle.Singleton);

最后一点。在您的问题中,您从构造函数中的 调用 IHttpClientFactory.CreateClient 方法,并将客户端存储在使用者中。这通常不是一个好主意,因为它可能会让客户端存活很长时间并违背 IHttpClientFactory 的目的。相反,将 IPollyHttpClientFactory(或 IHttpClientFactory)存储在私有字段中,并且仅从使用者的方法中调用其 CreateClient 方法,并在方法的末尾处置客户端。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?