When you add multiple RestHttpClient<TError> clients to your DI, you are expected to have different error payloads for each client. However, say in large projects when you have a large quantity of registered clients each with their own designated error payload, and you notice similarities in those types (all inherit the same type, some have the same exact properties, etc). A good developer thinks of ways to create efficiency, right? Well, this is where I came up with this request to approach the incompatibility of creating multiple Remora rest clients while using the same error payload generic type.
Why This is Needed
By creating mutiple name-indexed clients with the same error payload type, we can overcome the tediousness of creating an entire new error type with each client.
Alternatives Considered
Prior to this PR, I tried using Microsoft.Extensions.Http.ITypedClientFactory<> for these clients, but there are almost no useful guides or documentation on Microsoft for this and I found it unnecessairly hard to learn and not worth using.
Another alternative I did was to simply use standard http clients and create extensions for HttpClient to mimick RestHttpClient methods.
Additional Details
If this were to be implemented, I created a potential replacement of HttpClientBuilderExtensions.AddRestHttpClient() that accepts an additional clientName parameter, which represents the name of the client. The same functionality as the original extension method will happen if this parameter is not supplied.
public static class HttpClientBuilderExtensions
{
// If optionsName is provided, the configured settings will be stored with optionsName index.
private static Dictionary<string, JsonSerializerOptions> _serializerOptions { get; set; } = new();
public static IHttpClientBuilder AddRestHttpClient<TError>(this IServiceCollection serviceCollection, string? clientName = default, string? optionsName = default)
{
var httpClientBuilder = clientName is null ? serviceCollection.AddHttpClient<RestHttpClient<TError>>() : serviceCollection.AddHttpClient<RestHttpClient<TError>>(clientName);
serviceCollection.Replace(ServiceDescriptor.Transient(s =>
{
var httpClient = s.GetRequiredService<IHttpClientFactory>().CreateClient(httpClientBuilder.Name);
var options = s.GetRequiredService<IOptionsMonitor<JsonSerializerOptions>>().Get(optionsName);
if (!string.IsNullOrEmpty(optionsName))
_serializerOptions.Add(optionsName, options);
return new RestHttpClient<TError>(httpClient, options);
}));
// Inject rest client as normal if there is no clientName (can be grabbed with IHttpClientFactory if named)
if (clientName is null)
serviceCollection.TryAddTransient<IRestHttpClient>(s => s.GetRequiredService<RestHttpClient<TError>>());
return httpClientBuilder;
}
}
Along with this, I also have an extension method for IHttpClientFactory called CreateRestClient<TError>() that is essentially IHttpClientFactory.CreateClient() for Remora rest clients.
public static RestHttpClient<TError> CreateRestClient<TError>(this IHttpClientFactory httpClientFactory, string clientName, string? optionsName = default)
{
var serializerOptions = !string.IsNullOrEmpty(optionsName) && _serializerOptions.TryGetValue(optionsName, out var options) ? options : new JsonSerializerOptions();
return new(httpClientFactory.CreateClient(clientName), serializerOptions);
}
Finally, I will demonstrate how to use RestHttpClients as services.
// Standard (continue using if there's no clientName)
public ClassConstructor(RestHttpClient<TError> restClient) => _restClientProperty = restClient;
// Named Clients
public ClassConstructor(IHttpClientFactory clientFactory) => _restClientProperty = clientFactory.CreateRestClient<TError>("clientName");
Description
When you add multiple
RestHttpClient<TError>
clients to your DI, you are expected to have different error payloads for each client. However, say in large projects when you have a large quantity of registered clients each with their own designated error payload, and you notice similarities in those types (all inherit the same type, some have the same exact properties, etc). A good developer thinks of ways to create efficiency, right? Well, this is where I came up with this request to approach the incompatibility of creating multiple Remora rest clients while using the same error payload generic type.Why This is Needed
By creating mutiple name-indexed clients with the same error payload type, we can overcome the tediousness of creating an entire new error type with each client.
Alternatives Considered
Prior to this PR, I tried using
Microsoft.Extensions.Http.ITypedClientFactory<>
for these clients, but there are almost no useful guides or documentation on Microsoft for this and I found it unnecessairly hard to learn and not worth using.Another alternative I did was to simply use standard http clients and create extensions for
HttpClient
to mimickRestHttpClient
methods.Additional Details
If this were to be implemented, I created a potential replacement of
HttpClientBuilderExtensions.AddRestHttpClient()
that accepts an additionalclientName
parameter, which represents the name of the client. The same functionality as the original extension method will happen if this parameter is not supplied.Along with this, I also have an extension method for
IHttpClientFactory
calledCreateRestClient<TError>()
that is essentiallyIHttpClientFactory.CreateClient()
for Remora rest clients.Finally, I will demonstrate how to use RestHttpClients as services.