如标题所示。
假设我注册了一个像这样的强类型客户端
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>();
但是,如注释中所述,将引发异常。我会错过令人讨厌的东西吗?还是这种安排是不可能的?
NullReferenceException
时会抛出client
。奇怪,奇怪。
这发生在XUnit项目中,可能与问题无关,但谁知道。 :)
带有 也在异常堆栈中读取 at System.Threading.LazyInitializer.EnsureInitializedCore [T](T&目标,布尔值和初始化,对象和同步锁,功能 当然可以指出问题所在。但是可能需要进一步调试。 现在可能有一些方法可以解决此问题。 :) <编辑5: 因此,似乎呼叫 使用命名客户端进行此操作的一种方法可能是 模仿扩展方法已经完成的工作。当然,现在也可以更好地公开终生服务。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.Http
和install-package Microsoft.Extensions.DependencyInjection
。
1 valueFactory)
at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory
1.Cache.get_Activator()
在** Microsoft.Extensions.Http.DefaultTypedHttpClientFactory 1.CreateClient(HttpClient httpClient) **
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func
1 valueFactory)
在Microsoft.Extensions.Http.DefaultTypedHttpClientFactory 1.Cache.get_Activator()
at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory
1.CreateClient(HttpClient httpClient)
在Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transitionCallSite,ServiceProviderEngineScope范围)
在Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService [T](IServiceProvider提供程序)
在C:\ projektit \ testit \ TypedClientTest \ TypedClientTest \ Program.cs:line 40中的TypedClientTest.Program.Main(String [] args)处.AddHttpClient
的类型为IHttpClientFactory
的客户端最终出现在“奇怪的地方”。实际上,不可能使用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);
}
}
}
答案 0 :(得分:2)
请阅读有关Typed clients的信息:
类型化的客户端在其构造函数中接受HttpClient参数
您的类应该在其构造函数中接受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);
}
}
}