Browse Source

Use CorrelationId and CancellationToken in the DynamicHttpProxyInterceptor

pull/818/head
Halil ibrahim Kalkan 7 years ago
parent
commit
df9325a329
  1. 7
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AspNetCoreCorrelationIdOptions.cs
  2. 8
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AspNetCoreCorrelationIdProvider.cs
  3. 7
      framework/src/Volo.Abp.Core/Volo/Abp/Tracing/CorrelationIdOptions.cs
  4. 18
      framework/src/Volo.Abp.Core/Volo/Abp/Tracing/DefaultCorrelationIdProvider.cs
  5. 5
      framework/src/Volo.Abp.Core/Volo/Abp/Tracing/ICorrelationIdProvider.cs
  6. 12
      framework/src/Volo.Abp.Core/Volo/Abp/Tracing/NullCorrelationIdProvider.cs
  7. 1
      framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj
  8. 9
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientModule.cs
  9. 92
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  10. 3
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelRemoteServiceHttpClientAuthenticator.cs

7
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AspNetCoreCorrelationIdOptions.cs

@ -1,7 +0,0 @@
namespace Volo.Abp.AspNetCore.Tracing
{
public class AspNetCoreCorrelationIdOptions
{
public string HeaderName { get; set; } = "X-Correlation-Id";
}
}

8
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Tracing/AspNetCoreCorrelationIdProvider.cs

@ -10,11 +10,11 @@ namespace Volo.Abp.AspNetCore.Tracing
public class AspNetCoreCorrelationIdProvider : ICorrelationIdProvider, ITransientDependency
{
protected IHttpContextAccessor HttpContextAccessor { get; }
protected AspNetCoreCorrelationIdOptions Options { get; }
protected CorrelationIdOptions Options { get; }
public AspNetCoreCorrelationIdProvider(
IHttpContextAccessor httpContextAccessor,
IOptions<AspNetCoreCorrelationIdOptions> options)
IOptions<CorrelationIdOptions> options)
{
HttpContextAccessor = httpContextAccessor;
Options = options.Value;
@ -29,12 +29,12 @@ namespace Volo.Abp.AspNetCore.Tracing
lock (HttpContextAccessor.HttpContext.Request.Headers)
{
string correlationId = HttpContextAccessor.HttpContext.Request.Headers[Options.HeaderName];
string correlationId = HttpContextAccessor.HttpContext.Request.Headers[Options.HttpHeaderName];
if (correlationId.IsNullOrEmpty())
{
correlationId = CreateNewCorrelationId();
HttpContextAccessor.HttpContext.Request.Headers[Options.HeaderName] = correlationId;
HttpContextAccessor.HttpContext.Request.Headers[Options.HttpHeaderName] = correlationId;
}
return correlationId;

7
framework/src/Volo.Abp.Core/Volo/Abp/Tracing/CorrelationIdOptions.cs

@ -0,0 +1,7 @@
namespace Volo.Abp.Tracing
{
public class CorrelationIdOptions
{
public string HttpHeaderName { get; set; } = "X-Correlation-Id";
}
}

18
framework/src/Volo.Abp.Core/Volo/Abp/Tracing/DefaultCorrelationIdProvider.cs

@ -0,0 +1,18 @@
using System;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Tracing
{
public class DefaultCorrelationIdProvider : ICorrelationIdProvider, ISingletonDependency
{
public string Get()
{
return CreateNewCorrelationId();
}
protected virtual string CreateNewCorrelationId()
{
return Guid.NewGuid().ToString("N");
}
}
}

5
framework/src/Volo.Abp.Core/Volo/Abp/Tracing/ICorrelationIdProvider.cs

@ -1,7 +1,10 @@
namespace Volo.Abp.Tracing
using JetBrains.Annotations;
namespace Volo.Abp.Tracing
{
public interface ICorrelationIdProvider
{
[NotNull]
string Get();
}
}

12
framework/src/Volo.Abp.Core/Volo/Abp/Tracing/NullCorrelationIdProvider.cs

@ -1,12 +0,0 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Tracing
{
public class NullCorrelationIdProvider : ICorrelationIdProvider, ISingletonDependency
{
public string Get()
{
return null;
}
}
}

1
framework/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj

@ -20,6 +20,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Castle.Core\Volo.Abp.Castle.Core.csproj" />
<ProjectReference Include="..\Volo.Abp.Http\Volo.Abp.Http.csproj" />
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />
</ItemGroup>
</Project>

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

@ -1,17 +1,20 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Castle;
using Volo.Abp.Modularity;
using Volo.Abp.Threading;
namespace Volo.Abp.Http.Client
{
[DependsOn(typeof(AbpHttpModule))]
[DependsOn(typeof(AbpCastleCoreModule))]
[DependsOn(
typeof(AbpHttpModule),
typeof(AbpCastleCoreModule),
typeof(AbpThreadingModule)
)]
public class AbpHttpClientModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<RemoteServiceOptions>(configuration);
}
}

92
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -15,21 +16,25 @@ using Volo.Abp.Http.ProxyScripting.Generators;
using Volo.Abp.Json;
using Volo.Abp.Reflection;
using Volo.Abp.Threading;
using Volo.Abp.Tracing;
namespace Volo.Abp.Http.Client.DynamicProxying
{
//TODO: Somehow capture cancellationtoken and pass to other methods...?
public class DynamicHttpProxyInterceptor<TService> : AbpInterceptor, ITransientDependency
{
private static MethodInfo GenericInterceptAsyncMethod { get; }
// ReSharper disable once StaticMemberInGenericType
protected static MethodInfo GenericInterceptAsyncMethod { get; }
protected ICancellationTokenProvider CancellationTokenProvider { get; }
protected ICorrelationIdProvider CorrelationIdProvider { get; }
protected CorrelationIdOptions CorrelationIdOptions { get; }
protected IDynamicProxyHttpClientFactory HttpClientFactory { get; }
protected IApiDescriptionFinder ApiDescriptionFinder { get; }
protected RemoteServiceOptions RemoteServiceOptions { get; }
protected AbpHttpClientOptions ClientOptions { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IRemoteServiceHttpClientAuthenticator ClientAuthenticator { get; }
private readonly IDynamicProxyHttpClientFactory _httpClientFactory;
private readonly IApiDescriptionFinder _apiDescriptionFinder;
private readonly RemoteServiceOptions _remoteServiceOptions;
private readonly AbpHttpClientOptions _clientOptions;
private readonly IJsonSerializer _jsonSerializer;
private readonly IRemoteServiceHttpClientAuthenticator _clientAuthenticator;
public ILogger<DynamicHttpProxyInterceptor<TService>> Logger { get; set; }
@ -46,14 +51,20 @@ namespace Volo.Abp.Http.Client.DynamicProxying
IOptionsSnapshot<RemoteServiceOptions> remoteServiceOptions,
IApiDescriptionFinder apiDescriptionFinder,
IJsonSerializer jsonSerializer,
IRemoteServiceHttpClientAuthenticator clientAuthenticator)
IRemoteServiceHttpClientAuthenticator clientAuthenticator,
ICancellationTokenProvider cancellationTokenProvider,
ICorrelationIdProvider correlationIdProvider,
IOptions<CorrelationIdOptions> correlationIdOptions)
{
_httpClientFactory = httpClientFactory;
_apiDescriptionFinder = apiDescriptionFinder;
_jsonSerializer = jsonSerializer;
_clientAuthenticator = clientAuthenticator;
_clientOptions = clientOptions.Value;
_remoteServiceOptions = remoteServiceOptions.Value;
CancellationTokenProvider = cancellationTokenProvider;
CorrelationIdProvider = correlationIdProvider;
CorrelationIdOptions = correlationIdOptions.Value;
HttpClientFactory = httpClientFactory;
ApiDescriptionFinder = apiDescriptionFinder;
JsonSerializer = jsonSerializer;
ClientAuthenticator = clientAuthenticator;
ClientOptions = clientOptions.Value;
RemoteServiceOptions = remoteServiceOptions.Value;
Logger = NullLogger<DynamicHttpProxyInterceptor<TService>>.Instance;
}
@ -62,11 +73,11 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{
if (invocation.Method.ReturnType == typeof(void))
{
AsyncHelper.RunSync(() => MakeRequest(invocation));
AsyncHelper.RunSync(() => MakeRequestAsync(invocation));
}
else
{
var responseAsString = AsyncHelper.RunSync(() => MakeRequest(invocation));
var responseAsString = AsyncHelper.RunSync(() => MakeRequestAsync(invocation));
//TODO: Think on that
if (TypeHelper.IsPrimitiveExtended(invocation.Method.ReturnType, true))
@ -75,7 +86,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
}
else
{
invocation.ReturnValue = _jsonSerializer.Deserialize(
invocation.ReturnValue = JsonSerializer.Deserialize(
invocation.Method.ReturnType,
responseAsString
);
@ -87,7 +98,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{
if (invocation.Method.ReturnType.GenericTypeArguments.IsNullOrEmpty())
{
return MakeRequest(invocation);
return MakeRequestAsync(invocation);
}
invocation.ReturnValue = GenericInterceptAsyncMethod
@ -99,7 +110,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
private async Task<T> MakeRequestAndGetResultAsync<T>(IAbpMethodInvocation invocation)
{
var responseAsString = await MakeRequest(invocation);
var responseAsString = await MakeRequestAsync(invocation);
//TODO: Think on that
if (TypeHelper.IsPrimitiveExtended(typeof(T), true))
@ -107,28 +118,28 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return (T)Convert.ChangeType(responseAsString, typeof(T));
}
return _jsonSerializer.Deserialize<T>(responseAsString);
return JsonSerializer.Deserialize<T>(responseAsString);
}
private async Task<string> MakeRequest(IAbpMethodInvocation invocation)
private async Task<string> MakeRequestAsync(IAbpMethodInvocation invocation)
{
using (var client = _httpClientFactory.Create())
using (var client = HttpClientFactory.Create())
{
var clientConfig = _clientOptions.HttpClientProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}.");
var remoteServiceConfig = _remoteServiceOptions.RemoteServices.GetConfigurationOrDefault(clientConfig.RemoteServiceName);
var clientConfig = ClientOptions.HttpClientProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}.");
var remoteServiceConfig = RemoteServiceOptions.RemoteServices.GetConfigurationOrDefault(clientConfig.RemoteServiceName);
var action = await _apiDescriptionFinder.FindActionAsync(remoteServiceConfig.BaseUrl, typeof(TService), invocation.Method);
var action = await ApiDescriptionFinder.FindActionAsync(remoteServiceConfig.BaseUrl, typeof(TService), invocation.Method);
var apiVersion = GetApiVersionInfo(action);
var url = remoteServiceConfig.BaseUrl + UrlBuilder.GenerateUrlWithParameters(action, invocation.ArgumentsDictionary, apiVersion);
var requestMessage = new HttpRequestMessage(action.GetHttpMethod(), url)
{
Content = RequestPayloadBuilder.BuildContent(action, invocation.ArgumentsDictionary, _jsonSerializer, apiVersion)
Content = RequestPayloadBuilder.BuildContent(action, invocation.ArgumentsDictionary, JsonSerializer, apiVersion)
};
AddHeaders(invocation, action, requestMessage, apiVersion);
await _clientAuthenticator.Authenticate(
await ClientAuthenticator.Authenticate(
new RemoteServiceHttpClientAuthenticateContext(
client,
requestMessage,
@ -137,7 +148,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
)
);
var response = await client.SendAsync(requestMessage);
var response = await client.SendAsync(requestMessage, GetCancellationToken());
if (!response.IsSuccessStatusCode)
{
@ -176,8 +187,9 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return action.SupportedVersions.Last(); //TODO: Ensure to get the latest version!
}
private static void AddHeaders(IAbpMethodInvocation invocation, ActionApiDescriptionModel action, HttpRequestMessage requestMessage, ApiVersionInfo apiVersion)
protected virtual void AddHeaders(IAbpMethodInvocation invocation, ActionApiDescriptionModel action, HttpRequestMessage requestMessage, ApiVersionInfo apiVersion)
{
//API Version
if (!apiVersion.Version.IsNullOrEmpty())
{
//TODO: What about other media types?
@ -186,8 +198,8 @@ namespace Volo.Abp.Http.Client.DynamicProxying
requestMessage.Headers.Add("api-version", apiVersion.Version);
}
//Header parameters
var headers = action.Parameters.Where(p => p.BindingSourceId == ParameterBindingSources.Header).ToArray();
foreach (var headerParameter in headers)
{
var value = HttpActionParameterHelper.FindParameterValue(invocation.ArgumentsDictionary, headerParameter);
@ -196,22 +208,25 @@ namespace Volo.Abp.Http.Client.DynamicProxying
requestMessage.Headers.Add(headerParameter.Name, value.ToString());
}
}
//CorrelationId
requestMessage.Headers.Add(CorrelationIdOptions.HttpHeaderName, CorrelationIdProvider.Get());
}
private string GetConfiguredApiVersion()
{
var clientConfig = _clientOptions.HttpClientProxies.GetOrDefault(typeof(TService))
var clientConfig = ClientOptions.HttpClientProxies.GetOrDefault(typeof(TService))
?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}.");
return _remoteServiceOptions.RemoteServices.GetOrDefault(clientConfig.RemoteServiceName)?.Version
?? _remoteServiceOptions.RemoteServices.Default?.Version;
return RemoteServiceOptions.RemoteServices.GetOrDefault(clientConfig.RemoteServiceName)?.Version
?? RemoteServiceOptions.RemoteServices.Default?.Version;
}
private async Task ThrowExceptionForResponseAsync(HttpResponseMessage response)
{
if (response.Headers.Contains(AbpHttpConsts.AbpErrorFormat))
{
var errorResponse = _jsonSerializer.Deserialize<RemoteServiceErrorResponse>(
var errorResponse = JsonSerializer.Deserialize<RemoteServiceErrorResponse>(
await response.Content.ReadAsStringAsync()
);
@ -220,5 +235,10 @@ namespace Volo.Abp.Http.Client.DynamicProxying
throw new AbpException($"Remote service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}");
}
protected virtual CancellationToken GetCancellationToken()
{
return CancellationTokenProvider.Token;
}
}
}

3
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelRemoteServiceHttpClientAuthenticator.cs

@ -15,7 +15,6 @@ namespace Volo.Abp.IdentityModel
public class IdentityModelHttpClientAuthenticator : IIdentityModelHttpClientAuthenticator, ITransientDependency
{
public ILogger<IdentityModelHttpClientAuthenticator> Logger { get; set; }
protected IdentityClientOptions ClientOptions { get; }
public IdentityModelHttpClientAuthenticator(
@ -84,6 +83,8 @@ namespace Volo.Abp.IdentityModel
protected virtual async Task<TokenResponse> GetTokenResponse(DiscoveryResponse discoveryResponse, IdentityClientConfiguration configuration)
{
//TODO: Pass cancellation token
var tokenClient = new TokenClient(discoveryResponse.TokenEndpoint, configuration.ClientId, configuration.ClientSecret);
switch (configuration.GrantType)

Loading…
Cancel
Save