Browse Source

Merge pull request #19 from colinin/3.0

upgrade Ocelot to 16.0.1
pull/21/head
cKey 6 years ago
committed by GitHub
parent
commit
e1095a233c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj
  2. 13
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayMapperProfile.cs
  3. 6
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Configuration/Repository/ApiHttpClientFileConfigurationRepository.cs
  4. 114
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionAggregator.cs
  5. 89
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Ocelot/Extenssions/OcelotMiddlewareExtensions.cs

8
aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj

@ -6,10 +6,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DotNetCore.CAP.Dashboard" Version="3.0.3" /> <PackageReference Include="DotNetCore.CAP.Dashboard" Version="3.0.4" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="3.0.3" /> <PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="3.0.4" />
<PackageReference Include="DotNetCore.CAP.InMemoryStorage" Version="3.0.3" /> <PackageReference Include="DotNetCore.CAP.InMemoryStorage" Version="3.0.4" />
<PackageReference Include="Ocelot.Provider.Polly" Version="15.0.6" /> <PackageReference Include="Ocelot.Provider.Polly" Version="16.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="Serilog.Enrichers.Assembly" Version="2.0.0" /> <PackageReference Include="Serilog.Enrichers.Assembly" Version="2.0.0" />
<PackageReference Include="Serilog.Enrichers.Process" Version="2.0.1" /> <PackageReference Include="Serilog.Enrichers.Process" Version="2.0.1" />

13
aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayMapperProfile.cs

@ -33,7 +33,8 @@ namespace LINGYUN.ApiGateway
CreateMap<RateLimitOptionsDto, FileRateLimitOptions>() CreateMap<RateLimitOptionsDto, FileRateLimitOptions>()
.ForMember(flo => flo.HttpStatusCode, map => map.MapFrom(m => m.HttpStatusCode ?? 429)); .ForMember(flo => flo.HttpStatusCode, map => map.MapFrom(m => m.HttpStatusCode ?? 429));
CreateMap<ReRouteDto, FileReRoute>() CreateMap<ReRouteDto, FileRoute>()
.ForMember(frr => frr.RouteIsCaseSensitive, map => map.MapFrom(m => m.ReRouteIsCaseSensitive))
.ForMember(frr => frr.FileCacheOptions, map => map.MapFrom(m => m.FileCacheOptions)) .ForMember(frr => frr.FileCacheOptions, map => map.MapFrom(m => m.FileCacheOptions))
.ForMember(frr => frr.Priority, map => map.MapFrom(m => m.Priority ?? 0)) .ForMember(frr => frr.Priority, map => map.MapFrom(m => m.Priority ?? 0))
.ForMember(frr => frr.Timeout, map => map.MapFrom(m => m.Timeout ?? 0)) .ForMember(frr => frr.Timeout, map => map.MapFrom(m => m.Timeout ?? 0))
@ -46,11 +47,15 @@ namespace LINGYUN.ApiGateway
.ForMember(fgc => fgc.RateLimitOptions, map => map.MapFrom(m => m.RateLimitOptions)) .ForMember(fgc => fgc.RateLimitOptions, map => map.MapFrom(m => m.RateLimitOptions))
.ForMember(fgc => fgc.ServiceDiscoveryProvider, map => map.MapFrom(m => m.ServiceDiscoveryProvider)); .ForMember(fgc => fgc.ServiceDiscoveryProvider, map => map.MapFrom(m => m.ServiceDiscoveryProvider));
CreateMap<DynamicReRouteDto, FileDynamicReRoute>(); CreateMap<DynamicReRouteDto, FileDynamicRoute>();
CreateMap<AggregateReRouteConfigDto, AggregateReRouteConfig>(); CreateMap<AggregateReRouteConfigDto, AggregateRouteConfig>()
.ForMember(arc => arc.RouteKey, map => map.MapFrom(m => m.ReRouteKey));
CreateMap<AggregateReRouteDto, FileAggregateReRoute>(); CreateMap<AggregateReRouteDto, FileAggregateRoute>()
.ForMember(far => far.RouteKeys, map => map.MapFrom(m => m.ReRouteKeys))
.ForMember(far => far.RouteKeysConfig, map => map.MapFrom(m => m.ReRouteKeysConfig))
.ForMember(far => far.RouteIsCaseSensitive, map => map.MapFrom(m => m.ReRouteIsCaseSensitive));
} }
private Dictionary<string, string> MapperDictionary(string sourceString) private Dictionary<string, string> MapperDictionary(string sourceString)

6
aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Configuration/Repository/ApiHttpClientFileConfigurationRepository.cs

@ -48,7 +48,7 @@ namespace Ocelot.Configuration.Repository
{ {
foreach (var reRouteConfig in reRouteConfiguration.Items) foreach (var reRouteConfig in reRouteConfiguration.Items)
{ {
fileConfiguration.ReRoutes.Add(_objectMapper.Map<ReRouteDto, FileReRoute>(reRouteConfig)); fileConfiguration.Routes.Add(_objectMapper.Map<ReRouteDto, FileRoute>(reRouteConfig));
} }
} }
@ -58,7 +58,7 @@ namespace Ocelot.Configuration.Repository
{ {
foreach (var dynamicRouteConfig in dynamicReRouteConfiguration.Items) foreach (var dynamicRouteConfig in dynamicReRouteConfiguration.Items)
{ {
fileConfiguration.DynamicReRoutes.Add(_objectMapper.Map<DynamicReRouteDto, FileDynamicReRoute>(dynamicRouteConfig)); fileConfiguration.DynamicRoutes.Add(_objectMapper.Map<DynamicReRouteDto, FileDynamicRoute>(dynamicRouteConfig));
} }
} }
@ -67,7 +67,7 @@ namespace Ocelot.Configuration.Repository
{ {
foreach (var aggregateRouteConfig in aggregateReRouteConfiguration.Items) foreach (var aggregateRouteConfig in aggregateReRouteConfiguration.Items)
{ {
fileConfiguration.Aggregates.Add(_objectMapper.Map<AggregateReRouteDto, FileAggregateReRoute>(aggregateRouteConfig)); fileConfiguration.Aggregates.Add(_objectMapper.Map<AggregateReRouteDto, FileAggregateRoute>(aggregateRouteConfig));
} }
} }

114
aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionAggregator.cs

@ -1,42 +1,31 @@
using Newtonsoft.Json; using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Ocelot.Multiplexer;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ocelot.Middleware.Multiplexer namespace Ocelot.Middleware.Multiplexer
{ {
public class AbpApiDefinitionAggregator : IDefinedAggregator public class AbpApiDefinitionAggregator : IDefinedAggregator
{ {
public async Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses) public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses)
{ {
// Ocelot抛弃了下游主机返回的HttpHeaders,所以没法判断是否为abp返回格式
// var isAbpResponse = responses.Any(response => response.DownstreamResponse.Headers.Any(h => h.Key.Equals("_abperrorformat")));
return await MapAbpApiDefinitionAggregateContentAsync(responses); return await MapAbpApiDefinitionAggregateContentAsync(responses);
} }
protected virtual async Task<DownstreamResponse> MapAbpApiDefinitionAggregateContentAsync(List<DownstreamContext> downstreamContexts) protected virtual async Task<DownstreamResponse> MapAbpApiDefinitionAggregateContentAsync(List<HttpContext> responses)
{ {
var responseKeys = downstreamContexts.Select(s => s.DownstreamReRoute.Key).Distinct().ToList();
JObject responseObject = null; JObject responseObject = null;
JsonMergeSettings mergeSetting = new JsonMergeSettings(); JsonMergeSettings mergeSetting = new JsonMergeSettings();
mergeSetting.MergeArrayHandling = MergeArrayHandling.Union; mergeSetting.MergeArrayHandling = MergeArrayHandling.Union;
mergeSetting.PropertyNameComparison = System.StringComparison.CurrentCultureIgnoreCase; mergeSetting.PropertyNameComparison = System.StringComparison.CurrentCultureIgnoreCase;
for (var k = 0; k < responseKeys.Count; k++) foreach (var httpResponse in responses)
{ {
var contexts = downstreamContexts.Where(w => w.DownstreamReRoute.Key == responseKeys[k]).ToList(); var content = await httpResponse.Items.DownstreamResponse().Content.ReadAsStringAsync();
if (contexts.Count == 1)
{
if (contexts[0].IsError)
{
return contexts[0].DownstreamResponse;
}
var content = await contexts[0].DownstreamResponse.Content.ReadAsStringAsync();
var contentObject = JsonConvert.DeserializeObject(content); var contentObject = JsonConvert.DeserializeObject(content);
if (responseObject == null) if (responseObject == null)
{ {
@ -47,29 +36,6 @@ namespace Ocelot.Middleware.Multiplexer
responseObject.Merge(contentObject, mergeSetting); responseObject.Merge(contentObject, mergeSetting);
} }
} }
else
{
for (var i = 0; i < contexts.Count; i++)
{
if (contexts[i].IsError)
{
return contexts[i].DownstreamResponse;
}
var content = await contexts[i].DownstreamResponse.Content.ReadAsStringAsync();
var contentObject = JsonConvert.DeserializeObject(content);
if (responseObject == null)
{
responseObject = JObject.FromObject(contentObject);
}
else
{
responseObject.Merge(contentObject, mergeSetting);
}
}
}
}
var stringContent = new StringContent(responseObject.ToString()) var stringContent = new StringContent(responseObject.ToString())
{ {
Headers = { ContentType = new MediaTypeHeaderValue("application/json") } Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
@ -79,71 +45,5 @@ namespace Ocelot.Middleware.Multiplexer
new List<KeyValuePair<string, IEnumerable<string>>>(), "OK"); new List<KeyValuePair<string, IEnumerable<string>>>(), "OK");
} }
protected virtual async Task<DownstreamResponse> MapSimpleJsonAggregateContentAsync(List<DownstreamContext> downstreamContexts)
{
var contentBuilder = new StringBuilder();
contentBuilder.Append("{");
var responseKeys = downstreamContexts.Select(s => s.DownstreamReRoute.Key).Distinct().ToList();
for (var k = 0; k < responseKeys.Count; k++)
{
var contexts = downstreamContexts.Where(w => w.DownstreamReRoute.Key == responseKeys[k]).ToList();
if (contexts.Count == 1)
{
if (contexts[0].IsError)
{
return contexts[0].DownstreamResponse;
}
var content = await contexts[0].DownstreamResponse.Content.ReadAsStringAsync();
contentBuilder.Append($"\"{responseKeys[k]}\":{content}");
}
else
{
contentBuilder.Append($"\"{responseKeys[k]}\":");
contentBuilder.Append("[");
for (var i = 0; i < contexts.Count; i++)
{
if (contexts[i].IsError)
{
return contexts[i].DownstreamResponse;
}
var content = await contexts[i].DownstreamResponse.Content.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(content))
{
continue;
}
contentBuilder.Append($"{content}");
if (i + 1 < contexts.Count)
{
contentBuilder.Append(",");
}
}
contentBuilder.Append("]");
}
if (k + 1 < responseKeys.Count)
{
contentBuilder.Append(",");
}
}
contentBuilder.Append("}");
var stringContent = new StringContent(contentBuilder.ToString())
{
Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
};
return new DownstreamResponse(stringContent, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "OK");
}
} }
} }

89
aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Ocelot/Extenssions/OcelotMiddlewareExtensions.cs

@ -1,17 +1,14 @@
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Creator; using Ocelot.Configuration.Creator;
using Ocelot.Configuration.Repository; using Ocelot.Configuration.Repository;
using Ocelot.Errors; using Ocelot.DependencyInjection;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Middleware; using Ocelot.Middleware;
using Ocelot.Middleware.Pipeline;
using Ocelot.Responses; using Ocelot.Responses;
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -28,61 +25,52 @@ namespace Ocelot.Extenssions
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, Action<OcelotPipelineConfiguration> pipelineConfiguration) public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, Action<OcelotPipelineConfiguration> pipelineConfiguration)
{ {
OcelotPipelineConfiguration ocelotPipelineConfiguration = new OcelotPipelineConfiguration(); var config = new OcelotPipelineConfiguration();
pipelineConfiguration?.Invoke(ocelotPipelineConfiguration); pipelineConfiguration?.Invoke(config);
return await builder.UseOcelot(ocelotPipelineConfiguration); return await builder.UseOcelot(config);
} }
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration) public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
{ {
await CreateConfiguration(builder); var configuration = await CreateConfiguration(builder);
ConfigureDiagnosticListener(builder); ConfigureDiagnosticListener(builder);
return CreateOcelotPipeline(builder, pipelineConfiguration); return CreateOcelotPipeline(builder, pipelineConfiguration);
} }
public static Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder app, Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction) public static Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder app, Action<IApplicationBuilder, OcelotPipelineConfiguration> builderAction)
{ => UseOcelot(app, builderAction, new OcelotPipelineConfiguration());
return app.UseOcelot(builderAction, new OcelotPipelineConfiguration());
}
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder app, Action<IOcelotPipelineBuilder, OcelotPipelineConfiguration> builderAction, OcelotPipelineConfiguration configuration) public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder app, Action<IApplicationBuilder, OcelotPipelineConfiguration> builderAction, OcelotPipelineConfiguration configuration)
{ {
await CreateConfiguration(app); await CreateConfiguration(app);
ConfigureDiagnosticListener(app); ConfigureDiagnosticListener(app);
OcelotPipelineBuilder ocelotPipelineBuilder = new OcelotPipelineBuilder(app.ApplicationServices);
builderAction?.Invoke(ocelotPipelineBuilder, configuration ?? new OcelotPipelineConfiguration()); builderAction?.Invoke(app, configuration ?? new OcelotPipelineConfiguration());
OcelotRequestDelegate ocelotDelegate = ocelotPipelineBuilder.Build();
app.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware"; app.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware";
app.Use(async delegate (HttpContext context, Func<Task> task)
{
DownstreamContext downstreamContext = new DownstreamContext(context);
await ocelotDelegate(downstreamContext);
});
return app; return app;
} }
private static IApplicationBuilder CreateOcelotPipeline(IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration) private static IApplicationBuilder CreateOcelotPipeline(IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
{ {
OcelotPipelineBuilder ocelotPipelineBuilder = new OcelotPipelineBuilder(builder.ApplicationServices); builder.BuildOcelotPipeline(pipelineConfiguration);
ocelotPipelineBuilder.BuildOcelotPipeline(pipelineConfiguration);
OcelotRequestDelegate firstDelegate = ocelotPipelineBuilder.Build(); /*
inject first delegate into first piece of asp.net middleware..maybe not like this
then because we are updating the http context in ocelot it comes out correct for
rest of asp.net..
*/
builder.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware"; builder.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware";
builder.Use(async delegate (HttpContext context, Func<Task> task)
{
DownstreamContext downstreamContext = new DownstreamContext(context);
await firstDelegate(downstreamContext);
});
return builder; return builder;
} }
private static async Task<IInternalConfiguration> CreateConfiguration(IApplicationBuilder builder) private static async Task<IInternalConfiguration> CreateConfiguration(IApplicationBuilder builder)
{ {
/* ABP框架中,Abp.HttpClient这个模块里面
* RemoteServiceOptions IOptionsSnapshot注入的,
* RemoteService服务必须在一个请求范围内
* DynamicHttpProxyInterceptor类,IOptions<RemoteServiceOptions>
*
*/
var fileConfigRepo = builder.ApplicationServices.GetRequiredService<IFileConfigurationRepository>(); var fileConfigRepo = builder.ApplicationServices.GetRequiredService<IFileConfigurationRepository>();
var fileConfig = await fileConfigRepo.Get(); var fileConfig = await fileConfigRepo.Get();
// IOptionsMonitor<FileConfiguration> fileConfig = builder.ApplicationServices.GetService<IOptionsMonitor<FileConfiguration>>(); // IOptionsMonitor<FileConfiguration> fileConfig = builder.ApplicationServices.GetService<IOptionsMonitor<FileConfiguration>>();
@ -97,26 +85,39 @@ namespace Ocelot.Extenssions
return GetOcelotConfigAndReturn(internalConfigRepo); return GetOcelotConfigAndReturn(internalConfigRepo);
} }
private static bool AdministrationApiInUse(IAdministrationPath adminPath)
{
return adminPath != null;
}
private static bool IsError(Response response)
{
return response == null || response.IsError;
}
private static IInternalConfiguration GetOcelotConfigAndReturn(IInternalConfigurationRepository provider) private static IInternalConfiguration GetOcelotConfigAndReturn(IInternalConfigurationRepository provider)
{ {
Response<IInternalConfiguration> response = provider.Get(); var ocelotConfiguration = provider.Get();
if (response?.Data == null || response.IsError)
if (ocelotConfiguration?.Data == null || ocelotConfiguration.IsError)
{ {
ThrowToStopOcelotStarting(response); ThrowToStopOcelotStarting(ocelotConfiguration);
} }
return response.Data;
return ocelotConfiguration.Data;
} }
private static void ThrowToStopOcelotStarting(Response config) private static void ThrowToStopOcelotStarting(Response config)
{ {
throw new Exception("Unable to start Ocelot, errors are: " + string.Join(",", ((IEnumerable<Error>)config.Errors).Select((Func<Error, string>)((Error x) => x.ToString())))); throw new Exception($"Unable to start Ocelot, errors are: {string.Join(",", config.Errors.Select(x => x.ToString()))}");
} }
private static void ConfigureDiagnosticListener(IApplicationBuilder builder) private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
{ {
builder.ApplicationServices.GetService<IWebHostEnvironment>(); var env = builder.ApplicationServices.GetService<IWebHostEnvironment>();
OcelotDiagnosticListener service = builder.ApplicationServices.GetService<OcelotDiagnosticListener>(); var listener = builder.ApplicationServices.GetService<OcelotDiagnosticListener>();
builder.ApplicationServices.GetService<DiagnosticListener>().SubscribeWithAdapter(service); var diagnosticListener = builder.ApplicationServices.GetService<DiagnosticListener>();
diagnosticListener.SubscribeWithAdapter(listener);
} }
} }
} }
Loading…
Cancel
Save