mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 15:10:50 +08:00 
			
		
		
		
	Reload config on change (#527)
* Reload config on change. Added test case. * added testing for adding the json with reloadOnChange = false
This commit is contained in:
		
				
					committed by
					
						
						Tom Pallister
					
				
			
			
				
	
			
			
			
						parent
						
							89f0cc786a
						
					
				
				
					commit
					ad8025df1b
				
			@@ -113,12 +113,12 @@
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            // make configuration from file system?
 | 
					            // make configuration from file system?
 | 
				
			||||||
            // earlier user needed to add ocelot files in startup configuration stuff, asp.net will map it to this
 | 
					            // earlier user needed to add ocelot files in startup configuration stuff, asp.net will map it to this
 | 
				
			||||||
            var fileConfig = builder.ApplicationServices.GetService<IOptions<FileConfiguration>>();
 | 
					            var fileConfig = builder.ApplicationServices.GetService<IOptionsMonitor<FileConfiguration>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // now create the config
 | 
					            // now create the config
 | 
				
			||||||
            var internalConfigCreator = builder.ApplicationServices.GetService<IInternalConfigurationCreator>();
 | 
					            var internalConfigCreator = builder.ApplicationServices.GetService<IInternalConfigurationCreator>();
 | 
				
			||||||
            var internalConfig = await internalConfigCreator.Create(fileConfig.Value);
 | 
					            var internalConfig = await internalConfigCreator.Create(fileConfig.CurrentValue);
 | 
				
			||||||
           //Configuration error, throw error message
 | 
					            //Configuration error, throw error message
 | 
				
			||||||
            if (internalConfig.IsError)
 | 
					            if (internalConfig.IsError)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ThrowToStopOcelotStarting(internalConfig);
 | 
					                ThrowToStopOcelotStarting(internalConfig);
 | 
				
			||||||
@@ -128,6 +128,12 @@
 | 
				
			|||||||
            var internalConfigRepo = builder.ApplicationServices.GetService<IInternalConfigurationRepository>();
 | 
					            var internalConfigRepo = builder.ApplicationServices.GetService<IInternalConfigurationRepository>();
 | 
				
			||||||
            internalConfigRepo.AddOrReplace(internalConfig.Data);
 | 
					            internalConfigRepo.AddOrReplace(internalConfig.Data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fileConfig.OnChange(async (config) =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var newInternalConfig = await internalConfigCreator.Create(config);
 | 
				
			||||||
 | 
					                internalConfigRepo.AddOrReplace(newInternalConfig.Data);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var fileConfigRepo = builder.ApplicationServices.GetService<IFileConfigurationRepository>();
 | 
					            var fileConfigRepo = builder.ApplicationServices.GetService<IFileConfigurationRepository>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var adminPath = builder.ApplicationServices.GetService<IAdministrationPath>();
 | 
					            var adminPath = builder.ApplicationServices.GetService<IAdministrationPath>();
 | 
				
			||||||
@@ -155,7 +161,7 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static async Task SetFileConfigInConsul(IApplicationBuilder builder,
 | 
					        private static async Task SetFileConfigInConsul(IApplicationBuilder builder,
 | 
				
			||||||
            IFileConfigurationRepository fileConfigRepo, IOptions<FileConfiguration> fileConfig,
 | 
					            IFileConfigurationRepository fileConfigRepo, IOptionsMonitor<FileConfiguration> fileConfig,
 | 
				
			||||||
            IInternalConfigurationCreator internalConfigCreator, IInternalConfigurationRepository internalConfigRepo)
 | 
					            IInternalConfigurationCreator internalConfigCreator, IInternalConfigurationRepository internalConfigRepo)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // get the config from consul.
 | 
					            // get the config from consul.
 | 
				
			||||||
@@ -168,7 +174,7 @@
 | 
				
			|||||||
            else if (ConfigNotStoredInConsul(fileConfigFromConsul))
 | 
					            else if (ConfigNotStoredInConsul(fileConfigFromConsul))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                //there was no config in consul set the file in config in consul
 | 
					                //there was no config in consul set the file in config in consul
 | 
				
			||||||
                await fileConfigRepo.Set(fileConfig.Value);
 | 
					                await fileConfigRepo.Set(fileConfig.CurrentValue);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -197,9 +203,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static async Task SetFileConfig(IFileConfigurationSetter fileConfigSetter, IOptions<FileConfiguration> fileConfig)
 | 
					        private static async Task SetFileConfig(IFileConfigurationSetter fileConfigSetter, IOptionsMonitor<FileConfiguration> fileConfig)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var response = await fileConfigSetter.Set(fileConfig.Value);
 | 
					            var response = await fileConfigSetter.Set(fileConfig.CurrentValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (IsError(response))
 | 
					            if (IsError(response))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										68
									
								
								test/Ocelot.AcceptanceTests/ConfigurationReloadTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								test/Ocelot.AcceptanceTests/ConfigurationReloadTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					using Ocelot.Configuration.File;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.Setter;
 | 
				
			||||||
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
 | 
					using Shouldly;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.AcceptanceTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class ConfigurationReloadTests : IDisposable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private FileConfiguration _initialConfig;
 | 
				
			||||||
 | 
					        private FileConfiguration _anotherConfig;
 | 
				
			||||||
 | 
					        private Steps _steps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public ConfigurationReloadTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _steps = new Steps();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _initialConfig = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                GlobalConfiguration = new FileGlobalConfiguration
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    RequestIdKey = "initialKey"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _anotherConfig = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                GlobalConfiguration = new FileGlobalConfiguration
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    RequestIdKey = "someOtherKey"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_reload_config_on_change()
 | 
				
			||||||
 | 
					        {           
 | 
				
			||||||
 | 
					            this.Given(x => _steps.GivenThereIsAConfiguration(_initialConfig))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunningReloadingConfig(true))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(_anotherConfig))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenIWait(2500))
 | 
				
			||||||
 | 
					                .And(x => _steps.ThenConfigShouldBe(_anotherConfig))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_not_reload_config_on_change()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					           
 | 
				
			||||||
 | 
					            this.Given(x => _steps.GivenThereIsAConfiguration(_initialConfig))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunningReloadingConfig(false))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(_anotherConfig))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenIWait(2500))
 | 
				
			||||||
 | 
					                .And(x => _steps.ThenConfigShouldBe(_initialConfig))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Dispose()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _steps.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -34,6 +34,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
    using Butterfly;
 | 
					    using Butterfly;
 | 
				
			||||||
    using Configuration.Repository;
 | 
					    using Configuration.Repository;
 | 
				
			||||||
    using Microsoft.Net.Http.Headers;
 | 
					    using Microsoft.Net.Http.Headers;
 | 
				
			||||||
 | 
					    using Ocelot.Configuration.Creator;
 | 
				
			||||||
    using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;
 | 
					    using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class Steps : IDisposable
 | 
					    public class Steps : IDisposable
 | 
				
			||||||
@@ -55,6 +56,18 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            _random = new Random();
 | 
					            _random = new Random();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async Task ThenConfigShouldBe(FileConfiguration fileConfig)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var internalConfigCreator = _ocelotServer.Host.Services.GetService<IInternalConfigurationCreator>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var internalConfigRepo = _ocelotServer.Host.Services.GetService<IInternalConfigurationRepository>();
 | 
				
			||||||
 | 
					            var internalConfig = internalConfigRepo.Get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var config = await internalConfigCreator.Create(fileConfig);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            internalConfig.Data.RequestId.ShouldBe(config.Data.RequestId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public async Task StartFakeOcelotWithWebSockets()
 | 
					        public async Task StartFakeOcelotWithWebSockets()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _ocelotBuilder = new WebHostBuilder();
 | 
					            _ocelotBuilder = new WebHostBuilder();
 | 
				
			||||||
@@ -116,6 +129,34 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
					            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void GivenOcelotIsRunningReloadingConfig(bool shouldReload)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _webHostBuilder = new WebHostBuilder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _webHostBuilder
 | 
				
			||||||
 | 
					                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
				
			||||||
 | 
					                    var env = hostingContext.HostingEnvironment;
 | 
				
			||||||
 | 
					                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
				
			||||||
 | 
					                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
				
			||||||
 | 
					                    config.AddJsonFile("ocelot.json", optional: false, reloadOnChange: shouldReload);
 | 
				
			||||||
 | 
					                    config.AddEnvironmentVariables();
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .ConfigureServices(s =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    s.AddOcelot();                    
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .Configure(app =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    app.UseOcelot().Wait();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _ocelotServer = new TestServer(_webHostBuilder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _ocelotClient = _ocelotServer.CreateClient();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
					        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user