mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 00:58:15 +08:00
* #298 initial hacking around better aggregation * #298 bit more hacking around * #298 abstraction over httpresponsemessage * #298 tidying up * #298 docs * #298 missed this
This commit is contained in:
@ -2,12 +2,10 @@
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using System.IO;
|
||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
namespace Ocelot.Cache.Middleware
|
||||
{
|
||||
@ -72,38 +70,31 @@ namespace Ocelot.Cache.Middleware
|
||||
Logger.LogDebug($"finished response added to cache for {downstreamUrlKey}");
|
||||
}
|
||||
|
||||
private void SetHttpResponseMessageThisRequest(DownstreamContext context, HttpResponseMessage response)
|
||||
private void SetHttpResponseMessageThisRequest(DownstreamContext context, DownstreamResponse response)
|
||||
{
|
||||
context.DownstreamResponse = response;
|
||||
}
|
||||
|
||||
internal HttpResponseMessage CreateHttpResponseMessage(CachedResponse cached)
|
||||
internal DownstreamResponse CreateHttpResponseMessage(CachedResponse cached)
|
||||
{
|
||||
if (cached == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var response = new HttpResponseMessage(cached.StatusCode);
|
||||
|
||||
foreach (var header in cached.Headers)
|
||||
{
|
||||
response.Headers.Add(header.Key, header.Value);
|
||||
}
|
||||
|
||||
var content = new MemoryStream(Convert.FromBase64String(cached.Body));
|
||||
|
||||
response.Content = new StreamContent(content);
|
||||
var streamContent = new StreamContent(content);
|
||||
|
||||
foreach (var header in cached.ContentHeaders)
|
||||
{
|
||||
response.Content.Headers.Add(header.Key, header.Value);
|
||||
streamContent.Headers.Add(header.Key, header.Value);
|
||||
}
|
||||
|
||||
return response;
|
||||
return new DownstreamResponse(streamContent, cached.StatusCode, cached.Headers.ToList());
|
||||
}
|
||||
|
||||
internal async Task<CachedResponse> CreateCachedResponse(HttpResponseMessage response)
|
||||
internal async Task<CachedResponse> CreateCachedResponse(DownstreamResponse response)
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
@ -111,7 +102,7 @@ namespace Ocelot.Cache.Middleware
|
||||
}
|
||||
|
||||
var statusCode = response.StatusCode;
|
||||
var headers = response.Headers.ToDictionary(v => v.Key, v => v.Value);
|
||||
var headers = response.Headers.ToDictionary(v => v.Key, v => v.Values);
|
||||
string body = null;
|
||||
|
||||
if (response.Content != null)
|
||||
|
@ -14,6 +14,7 @@ namespace Ocelot.Configuration.Builder
|
||||
private List<HttpMethod> _upstreamHttpMethod;
|
||||
private string _upstreamHost;
|
||||
private List<DownstreamReRoute> _downstreamReRoutes;
|
||||
private string _aggregator;
|
||||
|
||||
public ReRouteBuilder()
|
||||
{
|
||||
@ -56,6 +57,12 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReRouteBuilder WithAggregator(string aggregator)
|
||||
{
|
||||
_aggregator = aggregator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReRoute Build()
|
||||
{
|
||||
return new ReRoute(
|
||||
@ -63,7 +70,8 @@ namespace Ocelot.Configuration.Builder
|
||||
new PathTemplate(_upstreamTemplate),
|
||||
_upstreamHttpMethod,
|
||||
_upstreamTemplatePattern,
|
||||
_upstreamHost
|
||||
_upstreamHost,
|
||||
_aggregator
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ namespace Ocelot.Configuration.Creator
|
||||
.WithUpstreamTemplatePattern(upstreamTemplatePattern)
|
||||
.WithDownstreamReRoutes(applicableReRoutes)
|
||||
.WithUpstreamHost(aggregateReRoute.UpstreamHost)
|
||||
.WithAggregator(aggregateReRoute.Aggregator)
|
||||
.Build();
|
||||
|
||||
return reRoute;
|
||||
|
@ -8,6 +8,7 @@ namespace Ocelot.Configuration.File
|
||||
public string UpstreamPathTemplate { get;set; }
|
||||
public string UpstreamHost { get; set; }
|
||||
public bool ReRouteIsCaseSensitive { get; set; }
|
||||
public string Aggregator { get; set; }
|
||||
|
||||
// Only supports GET..are you crazy!! POST, PUT WOULD BE CRAZY!! :)
|
||||
public List<string> UpstreamHttpMethod
|
||||
|
@ -12,13 +12,15 @@ namespace Ocelot.Configuration
|
||||
PathTemplate upstreamPathTemplate,
|
||||
List<HttpMethod> upstreamHttpMethod,
|
||||
UpstreamPathTemplate upstreamTemplatePattern,
|
||||
string upstreamHost)
|
||||
string upstreamHost,
|
||||
string aggregator)
|
||||
{
|
||||
UpstreamHost = upstreamHost;
|
||||
DownstreamReRoute = downstreamReRoute;
|
||||
UpstreamPathTemplate = upstreamPathTemplate;
|
||||
UpstreamHttpMethod = upstreamHttpMethod;
|
||||
UpstreamTemplatePattern = upstreamTemplatePattern;
|
||||
Aggregator = aggregator;
|
||||
}
|
||||
|
||||
public PathTemplate UpstreamPathTemplate { get; private set; }
|
||||
@ -26,5 +28,6 @@ namespace Ocelot.Configuration
|
||||
public List<HttpMethod> UpstreamHttpMethod { get; private set; }
|
||||
public string UpstreamHost { get; private set; }
|
||||
public List<DownstreamReRoute> DownstreamReRoute { get; private set; }
|
||||
public string Aggregator {get; private set;}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ using CacheManager.Core;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using IdentityServer4.AccessTokenValidation;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
namespace Ocelot.DependencyInjection
|
||||
{
|
||||
@ -23,5 +24,10 @@ namespace Ocelot.DependencyInjection
|
||||
|
||||
IOcelotBuilder AddTransientDelegatingHandler<T>(bool global = false)
|
||||
where T : DelegatingHandler;
|
||||
|
||||
IOcelotBuilder AddSingletonDefinedAggregator<T>()
|
||||
where T : class, IDefinedAggregator;
|
||||
IOcelotBuilder AddTransientDefinedAggregator<T>()
|
||||
where T : class, IDefinedAggregator;
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +154,8 @@ namespace Ocelot.DependencyInjection
|
||||
_services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
|
||||
_services.TryAddSingleton<IPlaceholders, Placeholders>();
|
||||
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
|
||||
_services.TryAddSingleton<IResponseAggregatorFactory, InMemoryResponseAggregatorFactory>();
|
||||
_services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
|
||||
}
|
||||
|
||||
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
|
||||
@ -188,6 +190,20 @@ namespace Ocelot.DependencyInjection
|
||||
return new OcelotAdministrationBuilder(_services, _configurationRoot);
|
||||
}
|
||||
|
||||
public IOcelotBuilder AddSingletonDefinedAggregator<T>()
|
||||
where T : class, IDefinedAggregator
|
||||
{
|
||||
_services.AddSingleton<IDefinedAggregator, T>();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOcelotBuilder AddTransientDefinedAggregator<T>()
|
||||
where T : class, IDefinedAggregator
|
||||
{
|
||||
_services.AddTransient<IDefinedAggregator, T>();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IOcelotBuilder AddSingletonDelegatingHandler<THandler>(bool global = false)
|
||||
where THandler : DelegatingHandler
|
||||
{
|
||||
|
@ -35,6 +35,7 @@
|
||||
PathTemplateDoesntStartWithForwardSlash,
|
||||
FileValidationFailedError,
|
||||
UnableToFindDelegatingHandlerProviderError,
|
||||
CouldNotFindPlaceholderError
|
||||
CouldNotFindPlaceholderError,
|
||||
CouldNotFindAggregatorError
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
namespace Ocelot.Headers
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using Ocelot.Configuration.Creator;
|
||||
using Ocelot.Infrastructure;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
|
||||
public class AddHeadersToResponse : IAddHeadersToResponse
|
||||
{
|
||||
@ -17,7 +17,7 @@ namespace Ocelot.Headers
|
||||
_placeholders = placeholders;
|
||||
}
|
||||
|
||||
public void Add(List<AddHeader> addHeaders, HttpResponseMessage response)
|
||||
public void Add(List<AddHeader> addHeaders, DownstreamResponse response)
|
||||
{
|
||||
foreach(var add in addHeaders)
|
||||
{
|
||||
@ -31,11 +31,11 @@ namespace Ocelot.Headers
|
||||
continue;
|
||||
}
|
||||
|
||||
response.Headers.TryAddWithoutValidation(add.Key, value.Data);
|
||||
response.Headers.Add(new Header(add.Key, new List<string> { value.Data }));
|
||||
}
|
||||
else
|
||||
{
|
||||
response.Headers.TryAddWithoutValidation(add.Key, add.Value);
|
||||
response.Headers.Add(new Header(add.Key, new List<string> { add.Value }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Infrastructure;
|
||||
using Ocelot.Infrastructure.Extensions;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.Responses;
|
||||
|
||||
@ -12,19 +12,21 @@ namespace Ocelot.Headers
|
||||
{
|
||||
public class HttpResponseHeaderReplacer : IHttpResponseHeaderReplacer
|
||||
{
|
||||
private IPlaceholders _placeholders;
|
||||
private readonly IPlaceholders _placeholders;
|
||||
|
||||
public HttpResponseHeaderReplacer(IPlaceholders placeholders)
|
||||
{
|
||||
_placeholders = placeholders;
|
||||
}
|
||||
|
||||
public Response Replace(HttpResponseMessage response, List<HeaderFindAndReplace> fAndRs, DownstreamRequest request)
|
||||
public Response Replace(DownstreamResponse response, List<HeaderFindAndReplace> fAndRs, DownstreamRequest request)
|
||||
{
|
||||
foreach (var f in fAndRs)
|
||||
{
|
||||
var dict = response.Headers.ToDictionary(x => x.Key);
|
||||
|
||||
//if the response headers contain a matching find and replace
|
||||
if(response.Headers.TryGetValues(f.Key, out var values))
|
||||
if(dict.TryGetValue(f.Key, out var values))
|
||||
{
|
||||
//check to see if it is a placeholder in the find...
|
||||
var placeholderValue = _placeholders.Get(f.Find, request);
|
||||
@ -32,16 +34,17 @@ namespace Ocelot.Headers
|
||||
if(!placeholderValue.IsError)
|
||||
{
|
||||
//if it is we need to get the value of the placeholder
|
||||
//var find = replacePlaceholder(httpRequestMessage);
|
||||
var replaced = values.ToList()[f.Index].Replace(placeholderValue.Data, f.Replace.LastCharAsForwardSlash());
|
||||
response.Headers.Remove(f.Key);
|
||||
response.Headers.Add(f.Key, replaced);
|
||||
var replaced = values.Values.ToList()[f.Index].Replace(placeholderValue.Data, f.Replace.LastCharAsForwardSlash());
|
||||
|
||||
response.Headers.Remove(response.Headers.First(item => item.Key == f.Key));
|
||||
response.Headers.Add(new Header(f.Key, new List<string> { replaced }));
|
||||
}
|
||||
else
|
||||
{
|
||||
var replaced = values.ToList()[f.Index].Replace(f.Find, f.Replace);
|
||||
response.Headers.Remove(f.Key);
|
||||
response.Headers.Add(f.Key, replaced);
|
||||
var replaced = values.Values.ToList()[f.Index].Replace(f.Find, f.Replace);
|
||||
|
||||
response.Headers.Remove(response.Headers.First(item => item.Key == f.Key));
|
||||
response.Headers.Add(new Header(f.Key, new List<string> { replaced }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
using Ocelot.Middleware;
|
||||
|
||||
namespace Ocelot.Headers
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using Ocelot.Configuration.Creator;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
public interface IAddHeadersToResponse
|
||||
{
|
||||
void Add(List<AddHeader> addHeaders, HttpResponseMessage response);
|
||||
void Add(List<AddHeader> addHeaders, DownstreamResponse response);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.Responses;
|
||||
|
||||
@ -8,6 +9,6 @@ namespace Ocelot.Headers
|
||||
{
|
||||
public interface IHttpResponseHeaderReplacer
|
||||
{
|
||||
Response Replace(HttpResponseMessage response, List<HeaderFindAndReplace> fAndRs, DownstreamRequest httpRequestMessage);
|
||||
Response Replace(DownstreamResponse response, List<HeaderFindAndReplace> fAndRs, DownstreamRequest httpRequestMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Collections.Generic;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using Ocelot.Responses;
|
||||
|
||||
namespace Ocelot.Headers
|
||||
{
|
||||
public interface IRemoveOutputHeaders
|
||||
{
|
||||
Response Remove(HttpResponseHeaders headers);
|
||||
Response Remove(List<Header> headers);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using Ocelot.Responses;
|
||||
|
||||
namespace Ocelot.Headers
|
||||
@ -14,14 +17,11 @@ namespace Ocelot.Headers
|
||||
{
|
||||
"Transfer-Encoding"
|
||||
};
|
||||
public Response Remove(HttpResponseHeaders headers)
|
||||
{
|
||||
foreach (var unsupported in _unsupportedRequestHeaders)
|
||||
{
|
||||
headers.Remove(unsupported);
|
||||
}
|
||||
|
||||
public Response Remove(List<Header> headers)
|
||||
{
|
||||
headers.RemoveAll(x => _unsupportedRequestHeaders.Contains(x.Key));
|
||||
return new OkResponse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
namespace Ocelot.Middleware
|
||||
@ -27,9 +28,9 @@ namespace Ocelot.Middleware
|
||||
|
||||
public DownstreamRequest DownstreamRequest { get; set; }
|
||||
|
||||
public HttpResponseMessage DownstreamResponse { get; set; }
|
||||
public DownstreamResponse DownstreamResponse { get; set; }
|
||||
|
||||
public List<Error> Errors { get;set; }
|
||||
public List<Error> Errors { get; }
|
||||
|
||||
public bool IsError => Errors.Count > 0;
|
||||
}
|
||||
|
31
src/Ocelot/Middleware/DownstreamResponse.cs
Normal file
31
src/Ocelot/Middleware/DownstreamResponse.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Ocelot.Middleware
|
||||
{
|
||||
public class DownstreamResponse
|
||||
{
|
||||
public DownstreamResponse(HttpContent content, HttpStatusCode statusCode, List<Header> headers)
|
||||
{
|
||||
Content = content;
|
||||
StatusCode = statusCode;
|
||||
Headers = headers ?? new List<Header>();
|
||||
}
|
||||
|
||||
public DownstreamResponse(HttpResponseMessage response)
|
||||
:this(response.Content, response.StatusCode, response.Headers.Select(x => new Header(x.Key, x.Value)).ToList())
|
||||
{
|
||||
}
|
||||
|
||||
public DownstreamResponse(HttpContent content, HttpStatusCode statusCode, IEnumerable<KeyValuePair<string, IEnumerable<string>>> headers)
|
||||
:this(content, statusCode, headers.Select(x => new Header(x.Key, x.Value)).ToList())
|
||||
{
|
||||
}
|
||||
|
||||
public HttpContent Content { get; }
|
||||
public HttpStatusCode StatusCode { get; }
|
||||
public List<Header> Headers { get; }
|
||||
}
|
||||
}
|
16
src/Ocelot/Middleware/Header.cs
Normal file
16
src/Ocelot/Middleware/Header.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ocelot.Middleware
|
||||
{
|
||||
public class Header
|
||||
{
|
||||
public Header(string key, IEnumerable<string> values)
|
||||
{
|
||||
Key = key;
|
||||
Values = values ?? new List<string>();
|
||||
}
|
||||
|
||||
public string Key { get; }
|
||||
public IEnumerable<string> Values { get; }
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Ocelot.Errors;
|
||||
|
||||
namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public class CouldNotFindAggregatorError : Error
|
||||
{
|
||||
public CouldNotFindAggregatorError(string aggregator)
|
||||
: base($"Could not find Aggregator: {aggregator}", OcelotErrorCode.CouldNotFindAggregatorError)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
10
src/Ocelot/Middleware/Multiplexer/IDefinedAggregator.cs
Normal file
10
src/Ocelot/Middleware/Multiplexer/IDefinedAggregator.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public interface IDefinedAggregator
|
||||
{
|
||||
Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Responses;
|
||||
|
||||
namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public interface IDefinedAggregatorProvider
|
||||
{
|
||||
Response<IDefinedAggregator> Get(ReRoute reRoute);
|
||||
}
|
||||
}
|
@ -6,6 +6,6 @@ namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public interface IResponseAggregator
|
||||
{
|
||||
Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamContexts);
|
||||
Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamResponses);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
using Ocelot.Configuration;
|
||||
|
||||
namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public interface IResponseAggregatorFactory
|
||||
{
|
||||
IResponseAggregator Get(ReRoute reRoute);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
using Ocelot.Configuration;
|
||||
|
||||
namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public class InMemoryResponseAggregatorFactory : IResponseAggregatorFactory
|
||||
{
|
||||
private readonly UserDefinedResponseAggregator _userDefined;
|
||||
private readonly SimpleJsonResponseAggregator _simple;
|
||||
|
||||
public InMemoryResponseAggregatorFactory(IDefinedAggregatorProvider provider)
|
||||
{
|
||||
_userDefined = new UserDefinedResponseAggregator(provider);
|
||||
_simple = new SimpleJsonResponseAggregator();
|
||||
}
|
||||
|
||||
public IResponseAggregator Get(ReRoute reRoute)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(reRoute.Aggregator))
|
||||
{
|
||||
return _userDefined;
|
||||
}
|
||||
|
||||
return _simple;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Configuration;
|
||||
|
||||
@ -6,11 +7,11 @@ namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public class Multiplexer : IMultiplexer
|
||||
{
|
||||
private readonly IResponseAggregator _aggregator;
|
||||
private readonly IResponseAggregatorFactory _factory;
|
||||
|
||||
public Multiplexer(IResponseAggregator aggregator)
|
||||
public Multiplexer(IResponseAggregatorFactory factory)
|
||||
{
|
||||
_aggregator = aggregator;
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public async Task Multiplex(DownstreamContext context, ReRoute reRoute, OcelotRequestDelegate next)
|
||||
@ -31,15 +32,40 @@ namespace Ocelot.Middleware.Multiplexer
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
var downstreamContexts = new List<DownstreamContext>();
|
||||
var contexts = new List<DownstreamContext>();
|
||||
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
var finished = await task;
|
||||
downstreamContexts.Add(finished);
|
||||
contexts.Add(finished);
|
||||
}
|
||||
|
||||
await _aggregator.Aggregate(reRoute, context, downstreamContexts);
|
||||
await Map(reRoute, context, contexts);
|
||||
}
|
||||
|
||||
private async Task Map(ReRoute reRoute, DownstreamContext context, List<DownstreamContext> contexts)
|
||||
{
|
||||
if (reRoute.DownstreamReRoute.Count > 1)
|
||||
{
|
||||
var aggregator = _factory.Get(reRoute);
|
||||
await aggregator.Aggregate(reRoute, context, contexts);
|
||||
}
|
||||
else
|
||||
{
|
||||
MapNotAggregate(context, contexts);
|
||||
}
|
||||
}
|
||||
|
||||
private void MapNotAggregate(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
||||
{
|
||||
//assume at least one..if this errors then it will be caught by global exception handler
|
||||
var finished = downstreamContexts.First();
|
||||
|
||||
originalContext.Errors.AddRange(finished.Errors);
|
||||
|
||||
originalContext.DownstreamRequest = finished.DownstreamRequest;
|
||||
|
||||
originalContext.DownstreamResponse = finished.DownstreamResponse;
|
||||
}
|
||||
|
||||
private async Task<DownstreamContext> Fire(DownstreamContext context, OcelotRequestDelegate next)
|
||||
|
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Responses;
|
||||
|
||||
namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public class ServiceLocatorDefinedAggregatorProvider : IDefinedAggregatorProvider
|
||||
{
|
||||
private readonly Dictionary<string, IDefinedAggregator> _aggregators;
|
||||
|
||||
public ServiceLocatorDefinedAggregatorProvider(IServiceProvider services)
|
||||
{
|
||||
_aggregators = services.GetServices<IDefinedAggregator>().ToDictionary(x => x.GetType().Name);
|
||||
}
|
||||
|
||||
public Response<IDefinedAggregator> Get(ReRoute reRoute)
|
||||
{
|
||||
if(_aggregators.ContainsKey(reRoute.Aggregator))
|
||||
{
|
||||
return new OkResponse<IDefinedAggregator>(_aggregators[reRoute.Aggregator]);
|
||||
}
|
||||
|
||||
return new ErrorResponse<IDefinedAggregator>(new CouldNotFindAggregatorError(reRoute.Aggregator));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
@ -12,18 +11,6 @@ namespace Ocelot.Middleware.Multiplexer
|
||||
public class SimpleJsonResponseAggregator : IResponseAggregator
|
||||
{
|
||||
public async Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
||||
{
|
||||
if (reRoute.DownstreamReRoute.Count > 1)
|
||||
{
|
||||
await MapAggregtes(originalContext, downstreamContexts);
|
||||
}
|
||||
else
|
||||
{
|
||||
MapNotAggregate(originalContext, downstreamContexts);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MapAggregtes(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
||||
{
|
||||
await MapAggregateContent(originalContext, downstreamContexts);
|
||||
}
|
||||
@ -34,7 +21,7 @@ namespace Ocelot.Middleware.Multiplexer
|
||||
|
||||
contentBuilder.Append("{");
|
||||
|
||||
for (int i = 0; i < downstreamContexts.Count; i++)
|
||||
for (var i = 0; i < downstreamContexts.Count; i++)
|
||||
{
|
||||
if (downstreamContexts[i].IsError)
|
||||
{
|
||||
@ -54,13 +41,12 @@ namespace Ocelot.Middleware.Multiplexer
|
||||
|
||||
contentBuilder.Append("}");
|
||||
|
||||
originalContext.DownstreamResponse = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
var stringContent = new StringContent(contentBuilder.ToString())
|
||||
{
|
||||
Content = new StringContent(contentBuilder.ToString())
|
||||
{
|
||||
Headers = {ContentType = new MediaTypeHeaderValue("application/json")}
|
||||
}
|
||||
Headers = {ContentType = new MediaTypeHeaderValue("application/json")}
|
||||
};
|
||||
|
||||
originalContext.DownstreamResponse = new DownstreamResponse(stringContent, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>());
|
||||
}
|
||||
|
||||
private static void MapAggregateError(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts, int i)
|
||||
@ -68,17 +54,5 @@ namespace Ocelot.Middleware.Multiplexer
|
||||
originalContext.Errors.AddRange(downstreamContexts[i].Errors);
|
||||
originalContext.DownstreamResponse = downstreamContexts[i].DownstreamResponse;
|
||||
}
|
||||
|
||||
private void MapNotAggregate(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
||||
{
|
||||
//assume at least one..if this errors then it will be caught by global exception handler
|
||||
var finished = downstreamContexts.First();
|
||||
|
||||
originalContext.Errors = finished.Errors;
|
||||
|
||||
originalContext.DownstreamRequest = finished.DownstreamRequest;
|
||||
|
||||
originalContext.DownstreamResponse = finished.DownstreamResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Configuration;
|
||||
|
||||
namespace Ocelot.Middleware.Multiplexer
|
||||
{
|
||||
public class UserDefinedResponseAggregator : IResponseAggregator
|
||||
{
|
||||
private readonly IDefinedAggregatorProvider _provider;
|
||||
|
||||
public UserDefinedResponseAggregator(IDefinedAggregatorProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
public async Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamResponses)
|
||||
{
|
||||
var aggregator = _provider.Get(reRoute);
|
||||
|
||||
if (!aggregator.IsError)
|
||||
{
|
||||
var aggregateResponse = await aggregator.Data
|
||||
.Aggregate(downstreamResponses.Select(x => x.DownstreamResponse).ToList());
|
||||
|
||||
originalContext.DownstreamResponse = aggregateResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
originalContext.Errors.AddRange(aggregator.Errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -22,11 +22,6 @@
|
||||
|
||||
public static class OcelotMiddlewareExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the Ocelot default middlewares
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
|
||||
{
|
||||
await builder.UseOcelot(new OcelotPipelineConfiguration());
|
||||
@ -34,12 +29,6 @@
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers Ocelot with a combination of default middlewares and optional middlewares in the configuration
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <param name="pipelineConfiguration"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
|
||||
{
|
||||
var configuration = await CreateConfiguration(builder);
|
||||
@ -230,26 +219,14 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void UseIfNotNull(this IApplicationBuilder builder, Func<HttpContext, Func<Task>, Task> middleware)
|
||||
{
|
||||
if (middleware != null)
|
||||
{
|
||||
builder.Use(middleware);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure a DiagnosticListener to listen for diagnostic events when the middleware starts and ends
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
|
||||
{
|
||||
private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
|
||||
{
|
||||
var env = (IHostingEnvironment)builder.ApplicationServices.GetService(typeof(IHostingEnvironment));
|
||||
var listener = (OcelotDiagnosticListener)builder.ApplicationServices.GetService(typeof(OcelotDiagnosticListener));
|
||||
var diagnosticListener = (DiagnosticListener)builder.ApplicationServices.GetService(typeof(DiagnosticListener));
|
||||
diagnosticListener.SubscribeWithAdapter(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnShutdown(IApplicationBuilder app)
|
||||
{
|
||||
|
@ -5,9 +5,7 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
@ -83,7 +81,6 @@
|
||||
{
|
||||
foreach (var header in request.Headers)
|
||||
{
|
||||
//todo get rid of if..
|
||||
if (IsSupportedHeader(header))
|
||||
{
|
||||
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
|
||||
|
@ -1,10 +1,6 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||
using Ocelot.Requester.QoS;
|
||||
|
||||
namespace Ocelot.Requester.Middleware
|
||||
{
|
||||
@ -36,7 +32,7 @@ namespace Ocelot.Requester.Middleware
|
||||
|
||||
Logger.LogDebug("setting http response message");
|
||||
|
||||
context.DownstreamResponse = response.Data;
|
||||
context.DownstreamResponse = new DownstreamResponse(response.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,14 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Ocelot.Headers;
|
||||
using Ocelot.Responses;
|
||||
using Ocelot.Middleware;
|
||||
|
||||
namespace Ocelot.Responder
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Cannot unit test things in this class due to methods not being implemented
|
||||
/// on .net concretes used for testing
|
||||
@ -25,7 +22,7 @@ namespace Ocelot.Responder
|
||||
_removeOutputHeaders = removeOutputHeaders;
|
||||
}
|
||||
|
||||
public async Task SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response)
|
||||
public async Task SetResponseOnHttpContext(HttpContext context, DownstreamResponse response)
|
||||
{
|
||||
_removeOutputHeaders.Remove(response.Headers);
|
||||
|
||||
@ -36,12 +33,12 @@ namespace Ocelot.Responder
|
||||
|
||||
foreach (var httpResponseHeader in response.Content.Headers)
|
||||
{
|
||||
AddHeaderIfDoesntExist(context, httpResponseHeader);
|
||||
AddHeaderIfDoesntExist(context, new Header(httpResponseHeader.Key, httpResponseHeader.Value));
|
||||
}
|
||||
|
||||
var content = await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
AddHeaderIfDoesntExist(context, new KeyValuePair<string, IEnumerable<string>>("Content-Length", new []{ content.Length.ToString() }) );
|
||||
AddHeaderIfDoesntExist(context, new Header("Content-Length", new []{ content.Length.ToString() }) );
|
||||
|
||||
context.Response.OnStarting(state =>
|
||||
{
|
||||
@ -70,11 +67,11 @@ namespace Ocelot.Responder
|
||||
}, context);
|
||||
}
|
||||
|
||||
private static void AddHeaderIfDoesntExist(HttpContext context, KeyValuePair<string, IEnumerable<string>> httpResponseHeader)
|
||||
private static void AddHeaderIfDoesntExist(HttpContext context, Header httpResponseHeader)
|
||||
{
|
||||
if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key))
|
||||
{
|
||||
context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Value.ToArray()));
|
||||
context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Values.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
namespace Ocelot.Responder
|
||||
{
|
||||
public interface IHttpResponder
|
||||
{
|
||||
Task SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response);
|
||||
Task SetResponseOnHttpContext(HttpContext context, DownstreamResponse response);
|
||||
void SetErrorResponseOnContext(HttpContext context, int statusCode);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||
using Ocelot.Infrastructure.Extensions;
|
||||
|
||||
namespace Ocelot.Responder.Middleware
|
||||
|
Reference in New Issue
Block a user