mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 10:35:28 +08:00 
			
		
		
		
	Expand other branch pipes (#416)
* Expand other branch pipes * Expand other branch pipes * Expand other branch pipes * optimization Expand other branch pipes ,Add Unit test * I hope to add two attributes to IOcelotBuilder for easy extension.
This commit is contained in:
		
				
					committed by
					
						
						Tom Pallister
					
				
			
			
				
	
			
			
			
						parent
						
							8f4ae03290
						
					
				
				
					commit
					5c940acf0e
				
			@@ -4,11 +4,15 @@ using System;
 | 
				
			|||||||
using System.Net.Http;
 | 
					using System.Net.Http;
 | 
				
			||||||
using IdentityServer4.AccessTokenValidation;
 | 
					using IdentityServer4.AccessTokenValidation;
 | 
				
			||||||
using Ocelot.Middleware.Multiplexer;
 | 
					using Ocelot.Middleware.Multiplexer;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
 | 
					using Microsoft.Extensions.Configuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.DependencyInjection
 | 
					namespace Ocelot.DependencyInjection
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public interface IOcelotBuilder
 | 
					    public interface IOcelotBuilder
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        IServiceCollection Services { get; }
 | 
				
			||||||
 | 
					        IConfiguration Configuration { get; }
 | 
				
			||||||
        IOcelotBuilder AddStoreOcelotConfigurationInConsul();
 | 
					        IOcelotBuilder AddStoreOcelotConfigurationInConsul();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
 | 
					        IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,10 @@ namespace Ocelot.DependencyInjection
 | 
				
			|||||||
        private readonly IServiceCollection _services;
 | 
					        private readonly IServiceCollection _services;
 | 
				
			||||||
        private readonly IConfiguration _configurationRoot;
 | 
					        private readonly IConfiguration _configurationRoot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IServiceCollection Services => _services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IConfiguration Configuration => _configurationRoot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
 | 
					        public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _configurationRoot = configurationRoot;
 | 
					            _configurationRoot = configurationRoot;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,13 +29,19 @@
 | 
				
			|||||||
            return builder;
 | 
					            return builder;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, Action<OcelotPipelineConfiguration> pipelineConfiguration)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var config = new OcelotPipelineConfiguration();
 | 
				
			||||||
 | 
					            pipelineConfiguration?.Invoke(config);
 | 
				
			||||||
 | 
					            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)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var configuration = await CreateConfiguration(builder);
 | 
					            var configuration = await CreateConfiguration(builder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            CreateAdministrationArea(builder, configuration);
 | 
					            CreateAdministrationArea(builder, configuration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(UsingRafty(builder))
 | 
					            if (UsingRafty(builder))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                SetUpRafty(builder);
 | 
					                SetUpRafty(builder);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -78,7 +84,7 @@
 | 
				
			|||||||
        private static bool UsingRafty(IApplicationBuilder builder)
 | 
					        private static bool UsingRafty(IApplicationBuilder builder)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var possible = builder.ApplicationServices.GetService(typeof(INode)) as INode;
 | 
					            var possible = builder.ApplicationServices.GetService(typeof(INode)) as INode;
 | 
				
			||||||
            if(possible != null)
 | 
					            if (possible != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return true;
 | 
					                return true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -196,7 +202,7 @@
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var ocelotConfiguration = provider.Get();
 | 
					            var ocelotConfiguration = provider.Get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(ocelotConfiguration?.Data == null || ocelotConfiguration.IsError)
 | 
					            if (ocelotConfiguration?.Data == null || ocelotConfiguration.IsError)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ThrowToStopOcelotStarting(ocelotConfiguration);
 | 
					                ThrowToStopOcelotStarting(ocelotConfiguration);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -216,7 +222,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void CreateAdministrationArea(IApplicationBuilder builder, IInternalConfiguration configuration)
 | 
					        private static void CreateAdministrationArea(IApplicationBuilder builder, IInternalConfiguration configuration)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if(!string.IsNullOrEmpty(configuration.AdministrationPath))
 | 
					            if (!string.IsNullOrEmpty(configuration.AdministrationPath))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                builder.Map(configuration.AdministrationPath, app =>
 | 
					                builder.Map(configuration.AdministrationPath, app =>
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
namespace Ocelot.Middleware
 | 
					namespace Ocelot.Middleware
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using Ocelot.Middleware.Pipeline;
 | 
				
			||||||
    using System;
 | 
					    using System;
 | 
				
			||||||
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
    using System.Threading.Tasks;
 | 
					    using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class OcelotPipelineConfiguration
 | 
					    public class OcelotPipelineConfiguration
 | 
				
			||||||
@@ -38,5 +40,9 @@
 | 
				
			|||||||
        /// This allows the user to implement there own query string manipulation logic
 | 
					        /// This allows the user to implement there own query string manipulation logic
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public Func<DownstreamContext, Func<Task>, Task> PreQueryStringBuilderMiddleware { get; set; }
 | 
					        public Func<DownstreamContext, Func<Task>, Task> PreQueryStringBuilderMiddleware { get; set; }
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// This is an extension that will branch to different pipes
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public List<Func<IOcelotPipelineBuilder, Func<DownstreamContext, bool>>> MapWhenOcelotPipeline { get; } = new List<Func<IOcelotPipelineBuilder, Func<DownstreamContext, bool>>>();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,13 +80,14 @@ namespace Ocelot.Middleware.Pipeline
 | 
				
			|||||||
                    var diagnosticListener = (DiagnosticListener)app.ApplicationServices.GetService(typeof(DiagnosticListener));
 | 
					                    var diagnosticListener = (DiagnosticListener)app.ApplicationServices.GetService(typeof(DiagnosticListener));
 | 
				
			||||||
                    var middlewareName = ocelotDelegate.Target.GetType().Name;
 | 
					                    var middlewareName = ocelotDelegate.Target.GetType().Name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    OcelotRequestDelegate wrapped = context => {
 | 
					                    OcelotRequestDelegate wrapped = context =>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
                        try
 | 
					                        try
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            Write(diagnosticListener, "Ocelot.MiddlewareStarted", middlewareName, context);
 | 
					                            Write(diagnosticListener, "Ocelot.MiddlewareStarted", middlewareName, context);
 | 
				
			||||||
                            return ocelotDelegate(context);
 | 
					                            return ocelotDelegate(context);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        catch(Exception ex)
 | 
					                        catch (Exception ex)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            WriteException(diagnosticListener, ex, "Ocelot.MiddlewareException", middlewareName, context);
 | 
					                            WriteException(diagnosticListener, ex, "Ocelot.MiddlewareException", middlewareName, context);
 | 
				
			||||||
                            throw ex;
 | 
					                            throw ex;
 | 
				
			||||||
@@ -117,7 +118,7 @@ namespace Ocelot.Middleware.Pipeline
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void Write(DiagnosticListener diagnosticListener, string message, string middlewareName, DownstreamContext context)
 | 
					        private static void Write(DiagnosticListener diagnosticListener, string message, string middlewareName, DownstreamContext context)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if(diagnosticListener != null)
 | 
					            if (diagnosticListener != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                diagnosticListener.Write(message, new { name = middlewareName, context = context });
 | 
					                diagnosticListener.Write(message, new { name = middlewareName, context = context });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -125,7 +126,7 @@ namespace Ocelot.Middleware.Pipeline
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void WriteException(DiagnosticListener diagnosticListener, Exception exception, string message, string middlewareName, DownstreamContext context)
 | 
					        private static void WriteException(DiagnosticListener diagnosticListener, Exception exception, string message, string middlewareName, DownstreamContext context)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if(diagnosticListener != null)
 | 
					            if (diagnosticListener != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                diagnosticListener.Write(message, new { name = middlewareName, context = context, exception = exception });
 | 
					                diagnosticListener.Write(message, new { name = middlewareName, context = context, exception = exception });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -160,6 +161,28 @@ namespace Ocelot.Middleware.Pipeline
 | 
				
			|||||||
            return app.Use(next => new MapWhenMiddleware(next, options).Invoke);
 | 
					            return app.Use(next => new MapWhenMiddleware(next, options).Invoke);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static IOcelotPipelineBuilder MapWhen(this IOcelotPipelineBuilder app, Func<IOcelotPipelineBuilder, Predicate> pipelineBuilderFunc)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (app == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new ArgumentNullException(nameof(app));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (pipelineBuilderFunc == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new ArgumentNullException(nameof(pipelineBuilderFunc));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            var branchBuilder = app.New();
 | 
				
			||||||
 | 
					            var predicate = pipelineBuilderFunc.Invoke(app);
 | 
				
			||||||
 | 
					            var branch = branchBuilder.Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var options = new MapWhenOptions
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Predicate = predicate,
 | 
				
			||||||
 | 
					                Branch = branch
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            return app.Use(next => new MapWhenMiddleware(next, options).Invoke);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static Func<T, DownstreamContext, IServiceProvider, Task> Compile<T>(MethodInfo methodinfo, ParameterInfo[] parameters)
 | 
					        private static Func<T, DownstreamContext, IServiceProvider, Task> Compile<T>(MethodInfo methodinfo, ParameterInfo[] parameters)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var middleware = typeof(T);
 | 
					            var middleware = typeof(T);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,15 @@ namespace Ocelot.Middleware.Pipeline
 | 
				
			|||||||
            // It also sets the Request Id if anything is set globally
 | 
					            // It also sets the Request Id if anything is set globally
 | 
				
			||||||
            builder.UseExceptionHandlerMiddleware();
 | 
					            builder.UseExceptionHandlerMiddleware();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //Expand other branch pipes
 | 
				
			||||||
 | 
					            if (pipelineConfiguration.MapWhenOcelotPipeline != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                foreach (var pipeline in pipelineConfiguration.MapWhenOcelotPipeline)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    builder.MapWhen(pipeline);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // If the request is for websockets upgrade we fork into a different pipeline
 | 
					            // If the request is for websockets upgrade we fork into a different pipeline
 | 
				
			||||||
            builder.MapWhen(context => context.HttpContext.WebSockets.IsWebSocketRequest,
 | 
					            builder.MapWhen(context => context.HttpContext.WebSockets.IsWebSocketRequest,
 | 
				
			||||||
                app =>
 | 
					                app =>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,13 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
    using Microsoft.Extensions.Configuration;
 | 
					    using Microsoft.Extensions.Configuration;
 | 
				
			||||||
    using Microsoft.Extensions.DependencyInjection;
 | 
					    using Microsoft.Extensions.DependencyInjection;
 | 
				
			||||||
    using Ocelot.DependencyInjection;
 | 
					    using Ocelot.DependencyInjection;
 | 
				
			||||||
 | 
					    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
				
			||||||
 | 
					    using Ocelot.DownstreamUrlCreator.Middleware;
 | 
				
			||||||
 | 
					    using Ocelot.LoadBalancer.Middleware;
 | 
				
			||||||
    using Ocelot.Middleware;
 | 
					    using Ocelot.Middleware;
 | 
				
			||||||
    using Ocelot.Middleware.Pipeline;
 | 
					    using Ocelot.Middleware.Pipeline;
 | 
				
			||||||
 | 
					    using Ocelot.Request.Middleware;
 | 
				
			||||||
 | 
					    using Ocelot.WebSockets.Middleware;
 | 
				
			||||||
    using Pivotal.Discovery.Client;
 | 
					    using Pivotal.Discovery.Client;
 | 
				
			||||||
    using Shouldly;
 | 
					    using Shouldly;
 | 
				
			||||||
    using Steeltoe.Common.Discovery;
 | 
					    using Steeltoe.Common.Discovery;
 | 
				
			||||||
@@ -26,6 +31,16 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_expand_pipeline()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Given(_ => GivenTheDepedenciesAreSetUp())
 | 
				
			||||||
 | 
					                 .When(_ => WhenIExpandBuild())
 | 
				
			||||||
 | 
					                 .Then(_ => ThenThePipelineIsBuilt())
 | 
				
			||||||
 | 
					                 .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenThePipelineIsBuilt()
 | 
					        private void ThenThePipelineIsBuilt()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _handlers.ShouldNotBeNull();
 | 
					            _handlers.ShouldNotBeNull();
 | 
				
			||||||
@@ -36,6 +51,23 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
            _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
 | 
					            _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenIExpandBuild()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            OcelotPipelineConfiguration configuration = new OcelotPipelineConfiguration();
 | 
				
			||||||
 | 
					            configuration.MapWhenOcelotPipeline.Add((app) =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                app.UseDownstreamRouteFinderMiddleware();
 | 
				
			||||||
 | 
					                app.UseDownstreamRequestInitialiser();
 | 
				
			||||||
 | 
					                app.UseLoadBalancingMiddleware();
 | 
				
			||||||
 | 
					                app.UseDownstreamUrlCreatorMiddleware();
 | 
				
			||||||
 | 
					                app.UseWebSocketsProxyMiddleware();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return context => context.HttpContext.WebSockets.IsWebSocketRequest;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void GivenTheDepedenciesAreSetUp()
 | 
					        private void GivenTheDepedenciesAreSetUp()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            IConfigurationBuilder test = new ConfigurationBuilder();
 | 
					            IConfigurationBuilder test = new ConfigurationBuilder();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -79,6 +79,8 @@ namespace Ocelot.UnitTests.Middleware
 | 
				
			|||||||
            del.Invoke(_downstreamContext);
 | 
					            del.Invoke(_downstreamContext);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheFuncIsInThePipeline()
 | 
					        private void ThenTheFuncIsInThePipeline()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _counter.ShouldBe(1);
 | 
					            _counter.ShouldBe(1);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user