您可以将 httpclients 添加到服务中而不必指定每个吗

问题描述 投票:0回答:1

我有一个使用

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>)

有办法解决这个问题吗?

谢谢, 吉姆

c# .net-6.0 dotnet-httpclient .net-7.0
1个回答
0
投票

你可以通过构造和调用泛型方法来使用更多的反射(

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 });
}
© www.soinside.com 2019 - 2024. All rights reserved.