gpt4 book ai didi

c# - 是否可以将 IHttpClientFactory 注入(inject)强类型客户端?

转载 作者:行者123 更新时间:2023-11-30 16:37:53 35 4
gpt4 key购买 nike

如标题所示。

假设我注册了一个强类型的客户端,例如

var services = new ServiceCollection();

//A named client is another option that could be tried since MSDN documentation shows that being used when IHttpClientFactory is injected.
//However, it appears it gives the same exception.
//services.AddHttpClient("test", httpClient =>
services.AddHttpClient<TestClient>(httpClient =>
{
httpClient.BaseAddress = new Uri("");
});
.AddHttpMessageHandler(_ => new TestMessageHandler());

//Registering IHttpClientFactory isn't needed, hence commented.
//services.AddSingleton(sp => sp.GetRequiredService<IHttpClientFactory>());
var servicesProvider = services.BuildServiceProvider(validateScopes: true);

public class TestClient
{
private IHttpClientFactory ClientFactory { get; }
public TestClient(IHttpClientFactory clientFactory)
{
ClientFactory = clientFactory;
}

public async Task<HttpResponseMessage> CallAsync(CancellationToken cancellation = default)
{
//using(var client = ClientFactory.CreateClient("test"))
using(var client = ClientFactory.CreateClient())
{
return await client.GetAsync("/", cancellation);
}
}
}

// This throws with "Message: System.InvalidOperationException : A suitable constructor
// for type 'Test.TestClient' could not be located. Ensure the type is concrete and services
// are registered for all parameters of a public constructor.

var client = servicesProvider.GetService<TestClient>();

但如评论中所述,将抛出异常。我是否遗漏了一些显而易见的事情,或者这种安排是不可能的?

IHttpClientFactory 已注册,则在尝试解析 client 时会抛出 NullReferenceException。奇怪,奇怪。

<编辑 2:我正在考虑避免的场景也在 https://github.com/aspnet/Extensions/issues/924 中进行了描述和讨论。也许那里的书写方式是一种避免某些问题的方式,也许不太令人满意。

这发生在 XUnit 项目中,可能与问题无关,但谁知道呢。 :)

<编辑 3:显示问题的控制台程序。

using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace TypedClientTest
{

public class TestClient
{
private IHttpClientFactory ClientFactory { get; }

public TestClient(IHttpClientFactory clientFactory)
{
ClientFactory = clientFactory;
}

public async Task<HttpResponseMessage> TestAsync(CancellationToken cancellation = default)
{
using (var client = ClientFactory.CreateClient())
{
return await client.GetAsync("/", cancellation);
}
}
}

class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();

services
.AddHttpClient<TestClient>(httpClient => httpClient.BaseAddress = new Uri("https://www.github.com/"));

var servicesProvider = services.BuildServiceProvider(validateScopes: true);

//This throws that there is not a suitable constructor. Should it?
var client = servicesProvider.GetService<TestClient>();
}
}
}

使用 install-package Microsoft.Extensions.Httpinstall-package Microsoft.Extensions.DependencyInjection

同样在异常堆栈中读取

at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func1 valueFactory)
at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory
1.Cache.get_Activator() at ** Microsoft.Extensions.Http.DefaultTypedHttpClientFactory1.CreateClient(HttpClient httpClient) **
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func
1 valueFactory) at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory1.Cache.get_Activator()
at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory
1.CreateClient(HttpClient httpClient) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider) at TypedClientTest.Program.Main(String[] args) in C:\projektit\testit\TypedClientTest\TypedClientTest\Program.cs:line 40

这当然指向问题所在。但可能需要进一步调试。

https://github.com/aspnet/Extensions/blob/557995ec322f1175d6d8a72a41713eec2d194871/src/HttpClientFactory/Http/src/DefaultTypedHttpClientFactory.cs#L47在 https://github.com/aspnet/Extensions/blob/11cf90103841c35cbefe9afb8e5bf9fee696dd17/src/HttpClientFactory/Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs一般而言。

现在可能有一些方法可以解决这个问题。 :)

<编辑 5:

因此,它似乎为具有 IHttpClientFactory 的类型化客户端调用 .AddHttpClient,最终出现在“奇怪的地方”。事实上,不可能使用 IHttpClientFactory 来创建自己类型的类型化客户端。

使用命名客户端实现这一点的一种方法可能是这样的

public static class CustomServicesCollectionExtensions
{
public static IHttpClientBuilder AddTypedHttpClient<TClient>(this IServiceCollection serviceCollection, Action<HttpClient> configureClient) where TClient: class
{
//return serviceCollection.Add(new ServiceDescriptor(typeof(TClient).Name, f => new ...,*/ ServiceLifetime.Singleton));
servicesCollection.AddTransient<TClient>();
return serviceCollection.AddHttpClient(typeof(TType).Name, configureClient);
}
}

public static class HttpClientFactoryExtensions
{
public static HttpClient CreateClient<TClient>(this IHttpClientFactory clientFactory)
{
return clientFactory.CreateClient(typeof(TClient).Name);
}
}


public class TestClient
{
private IHttpClientFactory ClientFactory { get; }

public TestClient(IHttpClientFactory clientFactory)
{
ClientFactory = clientFactory;
}

public async Task<HttpResponseMessage> Test(CancellationToken cancellation = default)
{
using(var client = ClientFactory.CreateClient<TestClient>())
{
return await client.GetAsync("/", cancellation);
}
}
}

模仿扩展方法已经做的事情。当然,现在也可以更好地公开生命周期服务。

最佳答案

请阅读 Typed clients :

A typed client accepts a HttpClient parameter in its constructor

代替 IHttpClientFactory,您的类应该在其构造函数中接受 HttpClient,它将由 DI 提供(通过 AddHttpClient 扩展启用) .

public class TestClient
{
private HttpClient Client { get; }
public TestClient(HttpClient client)
{
Client = client;
}

public Task<HttpResponseMessage> CallAsync(CancellationToken cancellation = default)
{
return client.GetAsync("/", cancellation);
}
}

编辑

(基于以上修改)

如果你想覆盖 AddHttpClient 扩展方法的默认行为,那么你应该直接注册你的实现:

var services = new ServiceCollection();
services.AddHttpClient("test", httpClient =>
{
httpClient.BaseAddress = new Uri("https://localhost");
});

services.AddScoped<TestClient>();

var servicesProvider = services.BuildServiceProvider(validateScopes: true);
using (var scope = servicesProvider.CreateScope())
{
var client = scope.ServiceProvider.GetRequiredService<TestClient>();
}
public class TestClient
{
private IHttpClientFactory ClientFactory { get; }

public TestClient(IHttpClientFactory clientFactory)
{
ClientFactory = clientFactory;
}

public Task<HttpResponseMessage> CallAsync(CancellationToken cancellation = default)
{
using (var client = ClientFactory.CreateClient("test"))
{
return client.GetAsync("/", cancellation);
}
}
}

关于c# - 是否可以将 IHttpClientFactory 注入(inject)强类型客户端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56739903/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com