feat 网关继承微服务Swagger

This commit is contained in:
2025-11-01 23:30:58 +08:00
parent ccb12389ee
commit 3cc7d2b85d
30 changed files with 1385 additions and 68 deletions

View File

@ -0,0 +1,103 @@
using Volo.Abp.Json;
namespace KonSoft.InternalGateway.Aggregations.Base;
public abstract class AggregateRemoteServiceBase<TDto> : IAggregateRemoteService<TDto>
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<AggregateRemoteServiceBase<TDto>> _logger;
protected IJsonSerializer JsonSerializer { get; }
protected AggregateRemoteServiceBase(IHttpContextAccessor httpContextAccessor, IJsonSerializer jsonSerializer,
ILogger<AggregateRemoteServiceBase<TDto>> logger)
{
_httpContextAccessor = httpContextAccessor;
JsonSerializer = jsonSerializer;
_logger = logger;
}
public async Task<Dictionary<string, TDto>> GetMultipleAsync(
Dictionary<string, string> serviceNameWithUrlDictionary)
{
Dictionary<string, Task<TDto>> completedTasks = new Dictionary<string, Task<TDto>>();
Dictionary<string, Task<TDto>> runningTasks = new Dictionary<string, Task<TDto>>();
Dictionary<string, TDto> completedResult = new Dictionary<string, TDto>();
using (HttpClient httpClient = CreateHttpClient())
{
foreach (var service in serviceNameWithUrlDictionary)
{
Task<TDto> requestTask =
MakeRequestAsync<TDto>(httpClient, service.Value);
runningTasks.Add(service.Key, requestTask);
}
while (runningTasks.Count > 0)
{
KeyValuePair<string, Task<TDto>> completedTask = await WaitForAnyTaskAsync(runningTasks);
runningTasks.Remove(completedTask.Key);
try
{
TDto result = await completedTask.Value;
completedTasks.Add(completedTask.Key, completedTask.Value);
completedResult.Add(completedTask.Key, result);
_logger.LogInformation("Localization Key: {0}, Value: {1}", completedTask.Key, result);
}
catch (Exception ex)
{
_logger.LogInformation("Error for the {0}: {1}", completedTask.Key, ex.Message);
}
}
}
return completedResult;
}
private HttpClient CreateHttpClient()
{
var httpClient = new HttpClient();
var headers = _httpContextAccessor.HttpContext?.Request.Headers;
if (headers != null)
{
foreach (var header in headers)
{
httpClient.DefaultRequestHeaders.Add(header.Key, header.Value.ToArray());
}
}
return httpClient;
}
public async Task<T> MakeRequestAsync<T>(HttpClient httpClient, string url)
{
try
{
HttpResponseMessage response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<T>(content);
}
catch (Exception e)
{
_logger.LogInformation("Error making request to {0}: {1}", url, e.Message);
throw;
}
}
public async Task<KeyValuePair<TKey, Task<TValue>>> WaitForAnyTaskAsync<TKey, TValue>(
Dictionary<TKey, Task<TValue>> tasks)
{
var completedTask = Task.WhenAny(tasks.Values);
var result = await completedTask;
var completedTaskPair = tasks.First(kv => kv.Value == result);
return completedTaskPair;
}
}

View File

@ -0,0 +1,30 @@
namespace KonSoft.InternalGateway.Aggregations.Base;
public abstract class AggregateServiceBase<TDto>
{
private readonly IAggregateRemoteService<TDto> _remoteService;
public AggregateServiceBase(IAggregateRemoteService<TDto> remoteService)
{
_remoteService = remoteService;
}
public virtual async Task<Dictionary<string, TDto>> GetMultipleFromRemoteAsync(List<string> missingKeys,
Dictionary<string, string> endpoints)
{
return await _remoteService
.GetMultipleAsync(endpoints
.Where(kv => missingKeys.Contains(kv.Key))
.ToDictionary(k => k.Key, v => v.Value));
}
public List<string> GetMissingServiceKeys(
IDictionary<string, TDto> serviceNamesWithData,
Dictionary<string, string> serviceNamesWithUrls)
{
List<string> missingKeysInCache = serviceNamesWithUrls.Keys.Except(serviceNamesWithData.Keys).ToList();
List<string> missingKeysInUrls = serviceNamesWithData.Keys.Except(serviceNamesWithUrls.Keys).ToList();
return missingKeysInCache.Concat(missingKeysInUrls).ToList();
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.Extensions.Caching.Memory;
namespace KonSoft.InternalGateway.Aggregations.Base;
public abstract class CachedServiceBase<TCacheValue> : ICachedServiceBase<TCacheValue>
{
private readonly IMemoryCache _cache;
protected MemoryCacheEntryOptions CacheEntryOptions { get; } = new()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(24),
SlidingExpiration = TimeSpan.FromHours(4)
};
protected CachedServiceBase(IMemoryCache cache)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
}
public void Add(string serviceName, TCacheValue data)
{
_cache.Set(serviceName, data, CacheEntryOptions);
}
public IDictionary<string, TCacheValue> GetManyAsync(IEnumerable<string> serviceNames)
{
var result = new Dictionary<string, TCacheValue>();
foreach (var serviceName in serviceNames)
{
if (_cache.TryGetValue(serviceName, out TCacheValue data))
{
result.Add(serviceName, data);
}
}
return result;
}
}

View File

@ -0,0 +1,8 @@
namespace KonSoft.InternalGateway.Aggregations.Base;
public interface IAggregateRemoteService<TDto>
{
Task<Dictionary<string, TDto>> GetMultipleAsync(Dictionary<string, string> serviceNameWithUrlDictionary);
Task<T> MakeRequestAsync<T>(HttpClient httpClient, string url);
Task<KeyValuePair<TKey, Task<TValue>>> WaitForAnyTaskAsync<TKey, TValue>(Dictionary<TKey, Task<TValue>> tasks);
}

View File

@ -0,0 +1,7 @@
namespace KonSoft.InternalGateway.Aggregations.Base;
public interface ICachedServiceBase<TValue>
{
void Add(string serviceName, TValue data);
IDictionary<string, TValue> GetManyAsync(IEnumerable<string> serviceNames);
}

View File

@ -0,0 +1,6 @@
namespace KonSoft.InternalGateway.Aggregations.Base;
public interface IRequestInput
{
Dictionary<string, string> Endpoints { get; }
}