我有一个使用
Microsoft.Extensions.Http
的 .NET 6 应用程序。一个典型的服务由一个接口和实现定义如下:
public interface IAddressService
{
Task<List<Address>?> List();
Task<List<Address>?> List(int appid);
Task<Address?> Get(int id);
Task<HttpResponseMessage?> Update(Address Address);
Task<Address?> Add(Address Address);
}
public class AddressService : IAddressService
{
private readonly HttpClient _httpClient;
public AddressService(HttpClient httpClient)
{
_httpClient = httpClient;
}
async Task<List<Address>?> IAddressService.List()
{
List<Address>? ret;
var response = await _httpClient.GetAsync($"api/Addresses");
if (response.IsSuccessStatusCode)
{
ret = await JsonSerializer.DeserializeAsync<List<Address>>
(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
else
{
ret = new List<Address>();
}
return ret;
}
等等。我对数据库的每个表都有一个。在配置服务中,我像这样连接它们:
services.AddTransient<MPSHttpHandler>();
services.AddHttpClient<IAddressService, AddressService>(client =>
{
client.BaseAddress = new Uri(Configuration["Settings:ApiAddress"] ?? "");
}).AddHttpMessageHandler<MPSHttpHandler>();
我必须指定每个服务(客户端)。我想知道是否有办法做类似的事情:
var clients = typeof(Program).Assembly
.GetTypes()
.Where(t => t.Name.EndsWith("Service"))
.ToList();
clients.ForEach(client =>
{
services.AddHttpClient<client.Interface, client.Implementation>(client =>
{
client.BaseAddress = new Uri(Configuration["Settings:ApiAddress"] ?? "");
}).AddHttpMessageHandler<MPSHttpHandler>();
});
我不知道如何将客户端类型设置为可以在调用 AddHttpClient 时使用它们的表单。有没有办法做到这一点?
谢谢, 吉姆
**** 更新 ****
我按照@Guru Stron 的示例实现了该方法。我更改了类型以匹配 AddHttpClient 的签名。我创建了静态类如下:
public static class MyHttpClientRegExts
{
public static IServiceCollection AddCustomHttpClient<TClient, TImplementation>(this IServiceCollection services,
IConfiguration Configuration)
{
services.AddHttpClient<TClient, TImplementation>(client =>
{
client.BaseAddress = new Uri(Configuration["Settings:ApiAddress"] ?? "");
}).AddHttpMessageHandler<MPSHttpHandler>();
return services;
}
}
我在客户端 =>
的 lambda 操作中收到以下错误CS1643: Not all code paths return a value in method of type 'func<HttpClient, TImplementaion>'
这告诉我它正在使用过载
AddHttpClient<TClient,TImplementation>(IServiceCollection, Func<HttpClient,TImplementation>)
而不是过载:
AddHttpClient<TClient,TImplementation>(IServiceCollection, Action<HttpClient>)
有办法解决这个问题吗?
谢谢, 吉姆
你可以通过构造和调用泛型方法来使用更多的反射(
AddHttpClient
实现做了一些内部的东西所以重用然后尝试重复会更好)。最简单的方法是将设置移动到单独的静态类中:
public static class MyHttpClientRegExts
{
public static IServiceCollection AddCustomHttpClient<TService, TImpl>(this IServiceCollection services,
IConfiguration Configuration)
{
services.AddHttpClient<IAddressService, AddressService>(client =>
{
client.BaseAddress = new Uri(Configuration["..."] ?? ...);
})
.AddHttpMessageHandler<MPSHttpHandler>();
return services;
}
}
然后用它来设置每项服务。让你开始的东西:
var types = typeof(Program).Assembly
.GetTypes()
.Where(t => t is { IsAbstract: false, IsClass: true } && t.Name.EndsWith("Service")) // find implementation types
.ToList();
// find the setup method
var method = typeof(MyHttpClientRegExts).GetMethod(nameof(MyHttpClientRegExts.AddCustomHttpClient));
foreach (var implType in types)
{
// find interface type to register, maybe will need some refinement
var interfaceType = implType.GetInterfaces().Single(i => i.Name.EndsWith("Service"));
// create closed generic method and invoke to register the type pair
method.MakeGenericMethod(interfaceType, implType)
.Invoke(null, new object?[] { services, Configuration });
}