Skip to content

Commit

Permalink
Add Headers To Proxy (#24)
Browse files Browse the repository at this point in the history
* refactoring

* perfomance improvement

* add TracedHttpClientConfig.ProxyServiceVariablesHeaders

* add BaseServiceOptions.ProxyServiceVariablesHeaders

* context might be null

* update readme
  • Loading branch information
CptnSnail committed Mar 5, 2022
1 parent bccb818 commit 440dc7a
Show file tree
Hide file tree
Showing 13 changed files with 78 additions and 23 deletions.
12 changes: 12 additions & 0 deletions ATI.Services.Common/Extensions/DictionaryExtension.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;

namespace ATI.Services.Common.Extensions
Expand All @@ -11,5 +12,16 @@ public static bool TryGetValue<T>(this IDictionary<string, string> dictionary, s
value = default;
return dictionary.TryGetValue(key, out var strValue) && strValue.TryConvert(out value);
}

public static void AddRange<T, S>(this Dictionary<T, S> source, Dictionary<T, S> collection)
{
if (collection == null || collection.Count == 0)
return;

foreach (var (key, value) in collection.Where(item => !source.ContainsKey(item.Key)))
{
source.Add(key, value);
}
}
}
}
5 changes: 0 additions & 5 deletions ATI.Services.Common/Metrics/MetricsExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using ATI.Services.Common.Behaviors;
using ATI.Services.Common.Extensions;
using ATI.Services.Common.Initializers;
using ATI.Services.Common.Tracing;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -23,8 +20,6 @@ public static void AddMetrics(this IServiceCollection services)
services.AddSingleton<ZipkinManager>();
services.AddTransient<MetricsInitializer>();
MetricsConfig.Configure();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
AppHttpContext.Services = services.BuildServiceProvider(new ServiceProviderOptions().ValidateOnBuild);

MetricsLabelsAndHeaders.LabelsStatic = ConfigurationManager.GetSection(nameof(MetricsOptions))?.Get<MetricsOptions>()?.LabelsAndHeaders ?? new Dictionary<string, string>();
MetricsLabelsAndHeaders.UserLabels = MetricsLabelsAndHeaders.LabelsStatic.Keys.ToArray();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Linq;
using System.Threading.Tasks;
using ATI.Services.Common.ServiceVariables;
using Microsoft.AspNetCore.Http;
using Prometheus;

Expand All @@ -23,7 +24,7 @@ public MetricsStatusCodeCounterMiddleware(RequestDelegate next)
public async Task InvokeAsync(HttpContext context)
{
await _next(context);
var param = new string[] {context.Response.StatusCode.ToString()}.Concat(AppHttpContext.HeadersValues)
var param = new string[] {context.Response.StatusCode.ToString()}.Concat(AppHttpContext.MetricsHeadersValues)
.ToArray();
counter.WithLabels(param).Inc();
}
Expand Down
13 changes: 7 additions & 6 deletions ATI.Services.Common/Metrics/MetricsTracingFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using ATI.Services.Common.Logging;
using ATI.Services.Common.ServiceVariables;
using JetBrains.Annotations;
using Prometheus;
using zipkin4net;
Expand Down Expand Up @@ -182,7 +183,7 @@ public static void Init(string serviceName, TimeSpan? defaultLongRequestTime = n
actionName,
entityName,
_externalHttpServiceName,
AppHttpContext.HeadersValues,
AppHttpContext.MetricsHeadersValues,
additionalLabels),
longRequestTime ?? _longRequestTime,
requestParams,
Expand Down Expand Up @@ -227,7 +228,7 @@ public static void Init(string serviceName, TimeSpan? defaultLongRequestTime = n
actionName,
entityName,
_externalHttpServiceName,
AppHttpContext.HeadersValues,
AppHttpContext.MetricsHeadersValues,
additionalLabels),
longRequestTime ?? _longRequestTime,
requestParams,
Expand Down Expand Up @@ -261,7 +262,7 @@ public static void Init(string serviceName, TimeSpan? defaultLongRequestTime = n
actionName,
entityName,
_externalHttpServiceName,
AppHttpContext.HeadersValues,
AppHttpContext.MetricsHeadersValues,
additionalLabels),
_longRequestTime,
requestParams,
Expand Down Expand Up @@ -294,7 +295,7 @@ public static void Init(string serviceName, TimeSpan? defaultLongRequestTime = n
actionName,
entityName,
_externalHttpServiceName,
AppHttpContext.HeadersValues,
AppHttpContext.MetricsHeadersValues,
additionalLabels));


Expand Down Expand Up @@ -328,7 +329,7 @@ public static void Init(string serviceName, TimeSpan? defaultLongRequestTime = n
actionName,
entityName,
_externalHttpServiceName,
AppHttpContext.HeadersValues,
AppHttpContext.MetricsHeadersValues,
additionalLabels),
_longRequestTime,
requestParams,
Expand All @@ -349,7 +350,7 @@ public static void Init(string serviceName, TimeSpan? defaultLongRequestTime = n
actionName,
entityName,
_externalHttpServiceName,
AppHttpContext.HeadersValues,
AppHttpContext.MetricsHeadersValues,
additionalLabels));

return new TimersWrapper(metricsTimer);
Expand Down
1 change: 1 addition & 0 deletions ATI.Services.Common/Options/BaseServiceOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ public class BaseServiceOptions
public TimeSpan? LongRequestTime { get; set; }

public Dictionary<string, string> AdditionalHeaders { get; set; }
public bool ProxyServiceVariablesHeaders { get; set; } = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
using System.Collections.Generic;
using System.Linq;
using ATI.Services.Common.Extensions;
using ATI.Services.Common.Metrics;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;


namespace ATI.Services.Common.Metrics
namespace ATI.Services.Common.ServiceVariables
{
internal static class AppHttpContext
{
Expand All @@ -28,6 +29,8 @@ public static IServiceProvider Services
}
}

public static string[] MetricsHeadersValues => GetHeadersValues(MetricsLabelsAndHeaders.UserHeaders);
public static Dictionary<string, string> HeadersAndValuesToProxy => GetHeadersAndValues(ServiceVariables.HeadersToProxy);

/// <summary>
/// Provides static access to the current HttpContext
Expand All @@ -42,8 +45,15 @@ private static HttpContext Current
}
}

public static string[] HeadersValues => GetHeadersValues(Current, MetricsLabelsAndHeaders.UserHeaders);
private static string[] GetHeadersValues(string[] headersNames)
{
if (headersNames == null || headersNames.Length == 0)
return headersNames;

var context = Current;
var headersValues = headersNames.Select(label => GetHeaderValue(context, label)).ToArray();
return headersValues;
}

private static string GetHeaderValue(HttpContext context, string headerName)
{
Expand All @@ -63,10 +73,27 @@ private static string GetHeaderValue(HttpContext context, string headerName)
return "Empty";
}

private static string[] GetHeadersValues(HttpContext context, IEnumerable<string> headersNames)
private static Dictionary<string, string> GetHeadersAndValues(IReadOnlyCollection<string> headersNames)
{
var headersValues = headersNames.Select(label => GetHeaderValue(context, label)).ToArray();
return headersValues;
if (headersNames == null || headersNames.Count == 0)
return null;

var context = Current;
if (context == null)
return null;

return headersNames
.Select(header => context.Request.Headers.TryGetValue(header, out var headerValues)
&& !StringValues.IsNullOrEmpty(headerValues)
? new
{
Header = header,
Value = headerValues[0]
}
: null)
.Where(headerAndValue => headerAndValue != null)
.ToDictionary(headerAndValue => headerAndValue.Header,
headerAndValue => headerAndValue.Value);
}
}
}
2 changes: 2 additions & 0 deletions ATI.Services.Common/ServiceVariables/ServiceVariables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ public static class ServiceVariables
public static string ServiceAsClientName { get; set; }
public static string ServiceAsClientHeaderName { get; set; }
public static Dictionary<string, string> Variables { get; set; }

public static List<string> HeadersToProxy { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using ATI.Services.Common.Extensions;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace ATI.Services.Common.ServiceVariables
Expand All @@ -11,6 +12,9 @@ public static void AddServiceVariables(this IServiceCollection services)
{
services.ConfigureByName<ServiceVariablesOptions>();
services.AddTransient<ServiceVariablesInitializer>();

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
AppHttpContext.Services = services.BuildServiceProvider(new ServiceProviderOptions().ValidateOnBuild);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public Task InitializeAsync()
ServiceVariables.ServiceAsClientName = ServiceVariables.Variables.TryGetValue("ServiceAsClientName", out var name) ? name : "";
ServiceVariables.ServiceAsClientHeaderName = ServiceVariables.Variables.TryGetValue("ServiceAsClientHeaderName", out var headerName) ? headerName : "";

ServiceVariables.HeadersToProxy = _options?.HeadersToProxy ?? new List<string>();

_initialized = true;
return Task.CompletedTask;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ namespace ATI.Services.Common.ServiceVariables
public class ServiceVariablesOptions
{
public Dictionary<string, string> Variables { get; set; }
public List<string> HeadersToProxy { get; set; }
}
}
1 change: 1 addition & 0 deletions ATI.Services.Common/Tracing/TracedHttpClientConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ public class TracedHttpClientConfig
public string ServiceName { get; set; }
public TimeSpan Timeout { get; set; }
public Dictionary<string, string> Headers { get; [PublicAPI] set; } = new();
public bool ProxyServiceVariablesHeaders { get; [PublicAPI] set; } = true;
}
}
7 changes: 7 additions & 0 deletions ATI.Services.Common/Tracing/TracingHttpClientWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Text;
using NLog;
using ATI.Services.Common.Extensions;
using ATI.Services.Common.ServiceVariables;
using JetBrains.Annotations;

namespace ATI.Services.Common.Tracing
Expand Down Expand Up @@ -306,6 +307,8 @@ private HttpClient CreateHttpClient(Dictionary<string, string> additionalHeaders
using (_metricsTracingFactory.CreateTracingTimer(
TraceHelper.GetHttpTracingInfo(fullUri.ToString(), metricName, message.Content)))
{
if (Config.ProxyServiceVariablesHeaders)
message.Headers.AddRange(AppHttpContext.HeadersAndValuesToProxy);
using var requestMessage = message.ToRequestMessage();
using var responseMessage = await _httpClient.SendAsync(requestMessage);

Expand Down Expand Up @@ -362,6 +365,8 @@ private async Task<OperationResult<TResult>> SendAsync<TResult>(string methodNam
return new OperationResult<TResult>(ActionStatus.InternalServerError,
"Адрес сообщения не указан (message.FullUri==null)");

if (Config.ProxyServiceVariablesHeaders)
message.Headers.AddRange(AppHttpContext.HeadersAndValuesToProxy);
using var requestMessage = message.ToRequestMessage();
using var responseMessage = await _httpClient.SendAsync(requestMessage);

Expand Down Expand Up @@ -398,6 +403,8 @@ private async Task<OperationResult<string>> SendAsync(string methodName, HttpMes
if (message.FullUri == null)
return new OperationResult<string>(ActionStatus.InternalServerError);

if (Config.ProxyServiceVariablesHeaders)
message.Headers.AddRange(AppHttpContext.HeadersAndValuesToProxy);
using var requestMessage = message.ToRequestMessage();
using var responseMessage = await _httpClient.SendAsync(requestMessage);
var responseContent = await responseMessage.Content.ReadAsStringAsync();
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,24 +385,25 @@ nLogConfigurator.ConfigureNLog();
}
```
---
### ServiceVaribles
### ServiceVariables
Данный блок конфигурации используется для конфигурирования данных уровня всего приложения
В приложении можно вызывать
```csharp
ServiceVaribles.Variables
ServiceVariables.Variables
```
Так же имеются предопределенные поля:
```csharp
ServiceVaribles.ServiceAsClientHeaderName
ServiceVaribles.ServiceAsClientName
ServiceVariables.ServiceAsClientHeaderName
ServiceVariables.ServiceAsClientName
```
Структура секции ServiceVaribles
Структура секции ServiceVariables
``` json
"ServiceVariablesOptions": {
"Variables": {
//Передается в каждый исходящий HTTP Запрос ConsulMetricsHttpClientWrapper в качестве header'a со значением ServiceAsClientName
"ServiceAsClientHeaderName": "ClientNameHeader",
"ServiceAsClientName": "ServiceName", //имя сервиса при исходящих HTTP запросах
"HeadersToProxy": ["Header1", "Header2"] // входные http-headers, которые проксировать при походы в другие http-сервисы. Если в BaseServiceOptions передать "ProxyServiceVariablesHeaders": false, то для это http-client заголовки проксироваться не будут
"VarName-3":"Var value 3", //Дополнительные параметры
"VarName-4":"Var value 4" //Дополнительные параметры
}
Expand Down

0 comments on commit 440dc7a

Please sign in to comment.