Browse Source

Resolved #5304: Introduce AbpHttpClientBuilderOptions & Remove AbpHttpClientOptions.HttpClientActions.

pull/5399/head
Halil İbrahim Kalkan 6 years ago
parent
commit
040971e1e9
  1. 79
      framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs
  2. 19
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientBuilderOptions.cs
  3. 39
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs
  4. 4
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientOptions.cs

79
framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs

@ -3,7 +3,6 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using Castle.DynamicProxy; using Castle.DynamicProxy;
using JetBrains.Annotations; using JetBrains.Annotations;
using Polly;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Castle.DynamicProxy; using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.Http.Client; using Volo.Abp.Http.Client;
@ -30,23 +29,15 @@ namespace Microsoft.Extensions.DependencyInjection
/// <param name="asDefaultServices"> /// <param name="asDefaultServices">
/// True, to register the HTTP client proxy as the default implementation for the services. /// True, to register the HTTP client proxy as the default implementation for the services.
/// </param> /// </param>
/// <param name="configureHttpClientBuilder">
/// A delegate that is used to configure an <see cref="T:Microsoft.Extensions.DependencyInjection.IHttpClientBuilder" />.
/// </param>
public static IServiceCollection AddHttpClientProxies( public static IServiceCollection AddHttpClientProxies(
[NotNull] this IServiceCollection services, [NotNull] this IServiceCollection services,
[NotNull] Assembly assembly, [NotNull] Assembly assembly,
[NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName, [NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName,
bool asDefaultServices = true, bool asDefaultServices = true)
Action<IHttpClientBuilder> configureHttpClientBuilder = null)
{ {
Check.NotNull(services, nameof(assembly)); Check.NotNull(services, nameof(assembly));
AddHttpClientFactoryAndPolicy(services, remoteServiceConfigurationName, configureHttpClientBuilder); var serviceTypes = assembly.GetTypes().Where(IsSuitableForDynamicClientProxying).ToArray();
//TODO: Make a configuration option and add remoteServiceName inside it!
var serviceTypes = assembly.GetTypes().Where(IsSuitableForDynamicClientProxying);
foreach (var serviceType in serviceTypes) foreach (var serviceType in serviceTypes)
{ {
@ -72,17 +63,11 @@ namespace Microsoft.Extensions.DependencyInjection
/// <param name="asDefaultService"> /// <param name="asDefaultService">
/// True, to register the HTTP client proxy as the default implementation for the service <typeparamref name="T"/>. /// True, to register the HTTP client proxy as the default implementation for the service <typeparamref name="T"/>.
/// </param> /// </param>
/// <param name="configureHttpClientBuilder">
/// A delegate that is used to configure an <see cref="T:Microsoft.Extensions.DependencyInjection.IHttpClientBuilder" />.
/// </param>
public static IServiceCollection AddHttpClientProxy<T>( public static IServiceCollection AddHttpClientProxy<T>(
[NotNull] this IServiceCollection services, [NotNull] this IServiceCollection services,
[NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName, [NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName,
bool asDefaultService = true, bool asDefaultService = true)
Action<IHttpClientBuilder> configureHttpClientBuilder = null)
{ {
AddHttpClientFactoryAndPolicy(services, remoteServiceConfigurationName, configureHttpClientBuilder);
return services.AddHttpClientProxy( return services.AddHttpClientProxy(
typeof(T), typeof(T),
remoteServiceConfigurationName, remoteServiceConfigurationName,
@ -90,37 +75,6 @@ namespace Microsoft.Extensions.DependencyInjection
); );
} }
/// <summary>
/// Use IHttpClientFactory and polly
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="remoteServiceConfigurationName">
/// The name of the remote service configuration to be used by the HTTP Client proxies.
/// See <see cref="AbpRemoteServiceOptions"/>.
/// </param>
/// <param name="configureHttpClientBuilder">
/// A delegate that is used to configure an <see cref="T:Microsoft.Extensions.DependencyInjection.IHttpClientBuilder" />.
/// </param>
public static IServiceCollection AddHttpClientFactoryAndPolicy(
[NotNull] this IServiceCollection services,
[NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName,
Action<IHttpClientBuilder> configureHttpClientBuilder = null)
{
var httpClientBuilder = services.AddHttpClient(remoteServiceConfigurationName);
if (configureHttpClientBuilder == null)
{
httpClientBuilder.AddTransientHttpErrorPolicy(builder =>
// retry 3 times
builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i))));
}
else
{
configureHttpClientBuilder.Invoke(httpClientBuilder);
}
return services;
}
/// <summary> /// <summary>
/// Registers HTTP Client Proxy for given service <paramref name="type"/>. /// Registers HTTP Client Proxy for given service <paramref name="type"/>.
/// </summary> /// </summary>
@ -143,6 +97,8 @@ namespace Microsoft.Extensions.DependencyInjection
Check.NotNull(type, nameof(type)); Check.NotNull(type, nameof(type));
Check.NotNullOrWhiteSpace(remoteServiceConfigurationName, nameof(remoteServiceConfigurationName)); Check.NotNullOrWhiteSpace(remoteServiceConfigurationName, nameof(remoteServiceConfigurationName));
AddHttpClientFactoryAndPolicy(services, remoteServiceConfigurationName);
services.Configure<AbpHttpClientOptions>(options => services.Configure<AbpHttpClientOptions>(options =>
{ {
options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(type, remoteServiceConfigurationName); options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(type, remoteServiceConfigurationName);
@ -189,13 +145,36 @@ namespace Microsoft.Extensions.DependencyInjection
return services; return services;
} }
private static IServiceCollection AddHttpClientFactoryAndPolicy(
[NotNull] this IServiceCollection services,
[NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName)
{
var preOptions = services.ExecutePreConfiguredActions<AbpHttpClientBuilderOptions>();
if (preOptions.ConfiguredProxyClients.Contains(remoteServiceConfigurationName))
{
return services;
}
var clientBuilder = services.AddHttpClient(remoteServiceConfigurationName);
foreach (var clientBuildAction in preOptions.ProxyClientBuildActions)
{
clientBuildAction(remoteServiceConfigurationName, clientBuilder);
}
preOptions.ConfiguredProxyClients.Add(remoteServiceConfigurationName);
return services;
}
/// <summary> /// <summary>
/// Checks wether the type is suitable to use with the dynamic proxying. /// Checks wether the type is suitable to use with the dynamic proxying.
/// Currently the type is checked statically against some fixed conditions. /// Currently the type is checked statically against some fixed conditions.
/// </summary> /// </summary>
/// <param name="type">Type to check</param> /// <param name="type">Type to check</param>
/// <returns>True, if the type is suitable for dynamic proxying. Otherwise false.</returns> /// <returns>True, if the type is suitable for dynamic proxying. Otherwise false.</returns>
static bool IsSuitableForDynamicClientProxying(Type type) private static bool IsSuitableForDynamicClientProxying(Type type)
{ {
//TODO: Add option to change type filter //TODO: Add option to change type filter

19
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientBuilderOptions.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Abp.Http.Client
{
public class AbpHttpClientBuilderOptions
{
public List<Action<string, IHttpClientBuilder>> ProxyClientBuildActions { get; }
internal HashSet<string> ConfiguredProxyClients { get; }
public AbpHttpClientBuilderOptions()
{
ProxyClientBuildActions = new List<Action<string, IHttpClientBuilder>>();
ConfiguredProxyClients = new HashSet<string>();
}
}
}

39
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs

@ -1,11 +1,11 @@
using System.Linq; using System;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http;
using Volo.Abp.Castle; using Volo.Abp.Castle;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
using Volo.Abp.Validation; using Volo.Abp.Validation;
using Polly;
namespace Volo.Abp.Http.Client namespace Volo.Abp.Http.Client
{ {
@ -18,29 +18,26 @@ namespace Volo.Abp.Http.Client
)] )]
public class AbpHttpClientModule : AbpModule public class AbpHttpClientModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpRemoteServiceOptions>(configuration);
}
public override void PostConfigureServices(ServiceConfigurationContext context)
{ {
Configure<AbpHttpClientOptions>(options => PreConfigure<AbpHttpClientBuilderOptions>(options =>
{ {
if (options.HttpClientActions.Any()) options.ProxyClientBuildActions.Add((remoteServiceName, clientBuilder) =>
{ {
var httpClientNames = options.HttpClientProxies.Select(x => x.Value.RemoteServiceName); clientBuilder.AddTransientHttpErrorPolicy(policyBuilder =>
foreach (var httpClientName in httpClientNames) policyBuilder.WaitAndRetryAsync(
{ 3,
foreach (var httpClientAction in options.HttpClientActions) i => TimeSpan.FromSeconds(Math.Pow(2, i))
{ )
context.Services.Configure<HttpClientFactoryOptions>(httpClientName, );
x => x.HttpClientActions.Add(httpClientAction.Invoke(httpClientName))); });
}
}
}
}); });
} }
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpRemoteServiceOptions>(configuration);
}
} }
} }

4
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientOptions.cs

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http;
using Volo.Abp.Http.Client.DynamicProxying; using Volo.Abp.Http.Client.DynamicProxying;
namespace Volo.Abp.Http.Client namespace Volo.Abp.Http.Client
@ -9,12 +8,9 @@ namespace Volo.Abp.Http.Client
{ {
public Dictionary<Type, DynamicHttpClientProxyConfig> HttpClientProxies { get; set; } public Dictionary<Type, DynamicHttpClientProxyConfig> HttpClientProxies { get; set; }
public List<Func<string, Action<HttpClient>>> HttpClientActions { get; }
public AbpHttpClientOptions() public AbpHttpClientOptions()
{ {
HttpClientProxies = new Dictionary<Type, DynamicHttpClientProxyConfig>(); HttpClientProxies = new Dictionary<Type, DynamicHttpClientProxyConfig>();
HttpClientActions = new List<Func<string, Action<HttpClient>>>();
} }
} }
} }

Loading…
Cancel
Save