diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj index 0fd1bf6fa..e4649af58 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj @@ -6,10 +6,10 @@ - - - - + + + + diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayMapperProfile.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayMapperProfile.cs index 3051cb2bc..d15676fdd 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayMapperProfile.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayMapperProfile.cs @@ -33,7 +33,8 @@ namespace LINGYUN.ApiGateway CreateMap() .ForMember(flo => flo.HttpStatusCode, map => map.MapFrom(m => m.HttpStatusCode ?? 429)); - CreateMap() + CreateMap() + .ForMember(frr => frr.RouteIsCaseSensitive, map => map.MapFrom(m => m.ReRouteIsCaseSensitive)) .ForMember(frr => frr.FileCacheOptions, map => map.MapFrom(m => m.FileCacheOptions)) .ForMember(frr => frr.Priority, map => map.MapFrom(m => m.Priority ?? 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.ServiceDiscoveryProvider, map => map.MapFrom(m => m.ServiceDiscoveryProvider)); - CreateMap(); + CreateMap(); - CreateMap(); + CreateMap() + .ForMember(arc => arc.RouteKey, map => map.MapFrom(m => m.ReRouteKey)); - CreateMap(); + CreateMap() + .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 MapperDictionary(string sourceString) diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Configuration/Repository/ApiHttpClientFileConfigurationRepository.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Configuration/Repository/ApiHttpClientFileConfigurationRepository.cs index 19f8dd97f..04bd7cf2a 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Configuration/Repository/ApiHttpClientFileConfigurationRepository.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Configuration/Repository/ApiHttpClientFileConfigurationRepository.cs @@ -38,7 +38,7 @@ namespace Ocelot.Configuration.Repository { var fileConfiguration = new FileConfiguration(); - var globalConfiguration = await _globalConfigurationAppService.GetAsync(new GlobalGetByAppIdInputDto { AppId = ApiGatewayOptions.AppId}); + var globalConfiguration = await _globalConfigurationAppService.GetAsync(new GlobalGetByAppIdInputDto { AppId = ApiGatewayOptions.AppId }); fileConfiguration.GlobalConfiguration = _objectMapper.Map(globalConfiguration); @@ -46,9 +46,9 @@ namespace Ocelot.Configuration.Repository if (reRouteConfiguration != null && reRouteConfiguration.Items.Count > 0) { - foreach(var reRouteConfig in reRouteConfiguration.Items) + foreach (var reRouteConfig in reRouteConfiguration.Items) { - fileConfiguration.ReRoutes.Add(_objectMapper.Map(reRouteConfig)); + fileConfiguration.Routes.Add(_objectMapper.Map(reRouteConfig)); } } @@ -58,7 +58,7 @@ namespace Ocelot.Configuration.Repository { foreach (var dynamicRouteConfig in dynamicReRouteConfiguration.Items) { - fileConfiguration.DynamicReRoutes.Add(_objectMapper.Map(dynamicRouteConfig)); + fileConfiguration.DynamicRoutes.Add(_objectMapper.Map(dynamicRouteConfig)); } } @@ -67,7 +67,7 @@ namespace Ocelot.Configuration.Repository { foreach (var aggregateRouteConfig in aggregateReRouteConfiguration.Items) { - fileConfiguration.Aggregates.Add(_objectMapper.Map(aggregateRouteConfig)); + fileConfiguration.Aggregates.Add(_objectMapper.Map(aggregateRouteConfig)); } } diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionAggregator.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionAggregator.cs index 8cc472987..af72d9369 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionAggregator.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionAggregator.cs @@ -1,149 +1,49 @@ -using Newtonsoft.Json; +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Ocelot.Multiplexer; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using System.Text; using System.Threading.Tasks; namespace Ocelot.Middleware.Multiplexer { public class AbpApiDefinitionAggregator : IDefinedAggregator { - public async Task Aggregate(List responses) + public async Task Aggregate(List responses) { - // Ocelot抛弃了下游主机返回的HttpHeaders,所以没法判断是否为abp返回格式 - // var isAbpResponse = responses.Any(response => response.DownstreamResponse.Headers.Any(h => h.Key.Equals("_abperrorformat"))); return await MapAbpApiDefinitionAggregateContentAsync(responses); } - protected virtual async Task MapAbpApiDefinitionAggregateContentAsync(List downstreamContexts) + protected virtual async Task MapAbpApiDefinitionAggregateContentAsync(List responses) { - var responseKeys = downstreamContexts.Select(s => s.DownstreamReRoute.Key).Distinct().ToList(); JObject responseObject = null; JsonMergeSettings mergeSetting = new JsonMergeSettings(); mergeSetting.MergeArrayHandling = MergeArrayHandling.Union; 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(); - if (contexts.Count == 1) + var content = await httpResponse.Items.DownstreamResponse().Content.ReadAsStringAsync(); + var contentObject = JsonConvert.DeserializeObject(content); + if (responseObject == null) { - if (contexts[0].IsError) - { - return contexts[0].DownstreamResponse; - } - - var content = await contexts[0].DownstreamResponse.Content.ReadAsStringAsync(); - var contentObject = JsonConvert.DeserializeObject(content); - if (responseObject == null) - { - responseObject = JObject.FromObject(contentObject); - } - else - { - responseObject.Merge(contentObject, mergeSetting); - } + responseObject = JObject.FromObject(contentObject); } 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); - } - } + responseObject.Merge(contentObject, mergeSetting); } } - var stringContent = new StringContent(responseObject.ToString()) { Headers = { ContentType = new MediaTypeHeaderValue("application/json") } }; stringContent.Headers.Add("_abperrorformat", "true"); - return new DownstreamResponse(stringContent, HttpStatusCode.OK, + return new DownstreamResponse(stringContent, HttpStatusCode.OK, new List>>(), "OK"); } - protected virtual async Task MapSimpleJsonAggregateContentAsync(List 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>>(), "OK"); - } - } } diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Ocelot/Extenssions/OcelotMiddlewareExtensions.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Ocelot/Extenssions/OcelotMiddlewareExtensions.cs index 32f013741..88765bd26 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Ocelot/Extenssions/OcelotMiddlewareExtensions.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Ocelot/Extenssions/OcelotMiddlewareExtensions.cs @@ -1,17 +1,14 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Ocelot.Configuration; using Ocelot.Configuration.Creator; using Ocelot.Configuration.Repository; -using Ocelot.Errors; +using Ocelot.DependencyInjection; using Ocelot.Logging; using Ocelot.Middleware; -using Ocelot.Middleware.Pipeline; using Ocelot.Responses; using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -28,61 +25,52 @@ namespace Ocelot.Extenssions public static async Task UseOcelot(this IApplicationBuilder builder, Action pipelineConfiguration) { - OcelotPipelineConfiguration ocelotPipelineConfiguration = new OcelotPipelineConfiguration(); - pipelineConfiguration?.Invoke(ocelotPipelineConfiguration); - return await builder.UseOcelot(ocelotPipelineConfiguration); + var config = new OcelotPipelineConfiguration(); + pipelineConfiguration?.Invoke(config); + return await builder.UseOcelot(config); } public static async Task UseOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration) { - await CreateConfiguration(builder); + var configuration = await CreateConfiguration(builder); + ConfigureDiagnosticListener(builder); + return CreateOcelotPipeline(builder, pipelineConfiguration); } - public static Task UseOcelot(this IApplicationBuilder app, Action builderAction) - { - return app.UseOcelot(builderAction, new OcelotPipelineConfiguration()); - } + public static Task UseOcelot(this IApplicationBuilder app, Action builderAction) + => UseOcelot(app, builderAction, new OcelotPipelineConfiguration()); - public static async Task UseOcelot(this IApplicationBuilder app, Action builderAction, OcelotPipelineConfiguration configuration) + public static async Task UseOcelot(this IApplicationBuilder app, Action builderAction, OcelotPipelineConfiguration configuration) { await CreateConfiguration(app); + ConfigureDiagnosticListener(app); - OcelotPipelineBuilder ocelotPipelineBuilder = new OcelotPipelineBuilder(app.ApplicationServices); - builderAction?.Invoke(ocelotPipelineBuilder, configuration ?? new OcelotPipelineConfiguration()); - OcelotRequestDelegate ocelotDelegate = ocelotPipelineBuilder.Build(); + + builderAction?.Invoke(app, configuration ?? new OcelotPipelineConfiguration()); + app.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware"; - app.Use(async delegate (HttpContext context, Func task) - { - DownstreamContext downstreamContext = new DownstreamContext(context); - await ocelotDelegate(downstreamContext); - }); + return app; } private static IApplicationBuilder CreateOcelotPipeline(IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration) { - OcelotPipelineBuilder ocelotPipelineBuilder = new OcelotPipelineBuilder(builder.ApplicationServices); - ocelotPipelineBuilder.BuildOcelotPipeline(pipelineConfiguration); - OcelotRequestDelegate firstDelegate = ocelotPipelineBuilder.Build(); + builder.BuildOcelotPipeline(pipelineConfiguration); + + /* + 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.Use(async delegate (HttpContext context, Func task) - { - DownstreamContext downstreamContext = new DownstreamContext(context); - await firstDelegate(downstreamContext); - }); + return builder; } - private static async Task CreateConfiguration(IApplicationBuilder builder) { - /* 因为ABP框架中,Abp.HttpClient这个模块里面 - * RemoteServiceOptions 是用的IOptionsSnapshot注入的,这里会出现一个异常 - * 每个RemoteService服务必须在一个请求范围内 - * 解决方案为重写DynamicHttpProxyInterceptor类,替换IOptions - * 网关不需要实现网关后台服务地址的实时更新 - */ var fileConfigRepo = builder.ApplicationServices.GetRequiredService(); var fileConfig = await fileConfigRepo.Get(); // IOptionsMonitor fileConfig = builder.ApplicationServices.GetService>(); @@ -97,26 +85,39 @@ namespace Ocelot.Extenssions 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) { - Response response = provider.Get(); - if (response?.Data == null || response.IsError) + var ocelotConfiguration = provider.Get(); + + if (ocelotConfiguration?.Data == null || ocelotConfiguration.IsError) { - ThrowToStopOcelotStarting(response); + ThrowToStopOcelotStarting(ocelotConfiguration); } - return response.Data; + + return ocelotConfiguration.Data; } private static void ThrowToStopOcelotStarting(Response config) { - throw new Exception("Unable to start Ocelot, errors are: " + string.Join(",", ((IEnumerable)config.Errors).Select((Func)((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) { - builder.ApplicationServices.GetService(); - OcelotDiagnosticListener service = builder.ApplicationServices.GetService(); - builder.ApplicationServices.GetService().SubscribeWithAdapter(service); + var env = builder.ApplicationServices.GetService(); + var listener = builder.ApplicationServices.GetService(); + var diagnosticListener = builder.ApplicationServices.GetService(); + diagnosticListener.SubscribeWithAdapter(listener); } } } \ No newline at end of file