From 968aa576100260ebc6cadd2d4008167b547faaa0 Mon Sep 17 00:00:00 2001
From: wangzelin <315872858@qq.com>
Date: Thu, 21 Feb 2019 15:12:14 +0800
Subject: [PATCH] Upgrade
---
Example/Example.csproj | 8 +-
Example/Program.cs | 45 ++--
Example/Startup.cs | 65 +++---
Example/appsettings.Development.json | 2 +-
README.md | 56 +++--
.../ConsulAgentConfiguration.cs | 10 +-
.../ConsulConfigurationExtensions.cs | 47 ----
.../ConsulConfigurationHostedService.cs | 78 +++++++
.../ConsulConfigurationProvider.cs | 217 ++++++++----------
.../ConsulConfigurationSource.cs | 29 ++-
.../ConsulQueryOptions.cs | 36 +--
.../Extensions.Configuration.Consul.csproj | 6 +-
.../ExtensionsMethods.cs | 144 ++++++++++++
.../IObserver.cs | 11 +
.../ObserverManager.cs | 24 ++
15 files changed, 482 insertions(+), 296 deletions(-)
delete mode 100644 src/Extensions.Configuration.Consul/ConsulConfigurationExtensions.cs
create mode 100644 src/Extensions.Configuration.Consul/ConsulConfigurationHostedService.cs
create mode 100644 src/Extensions.Configuration.Consul/ExtensionsMethods.cs
create mode 100644 src/Extensions.Configuration.Consul/IObserver.cs
create mode 100644 src/Extensions.Configuration.Consul/ObserverManager.cs
diff --git a/Example/Example.csproj b/Example/Example.csproj
index dc084b6..d9cd067 100644
--- a/Example/Example.csproj
+++ b/Example/Example.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.1
+ netcoreapp2.2
@@ -9,11 +9,11 @@
-
-
+
+
-
+
diff --git a/Example/Program.cs b/Example/Program.cs
index 0739315..25b9351 100644
--- a/Example/Program.cs
+++ b/Example/Program.cs
@@ -1,6 +1,4 @@
-using System;
-using System.IO;
-using Consul;
+using System.IO;
using Extensions.Configuration.Consul;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
@@ -8,29 +6,22 @@
namespace Example
{
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateWebHostBuilder(args).Build().Run();
- ConsulConfigurationExtensions.Shutdown();
- }
- public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateWebHostBuilder(args).Build().Run();
+ }
+ public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
- WebHost.CreateDefaultBuilder(args).ConfigureAppConfiguration((context, config) =>
- {
- config.SetBasePath(Directory.GetCurrentDirectory());
- config.AddCommandLine(args);
- config.AddJsonFile("appsettings.json", false, true);
- config.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", false, true);
- config.AddConsul(new ConsulClientConfiguration
- {
- Address = new Uri("http://192.168.1.142:8500")
- }, new ConsulQueryOptions
- {
- Prefix = "AppSetting/",
- TrimPrefix = true
- }, true);
- }).UseStartup();
- }
+ WebHost.CreateDefaultBuilder(args).ConfigureAppConfiguration((context, config) =>
+ {
+ config.SetBasePath(Directory.GetCurrentDirectory());
+ config.AddJsonFile("appsettings.json", false, true);
+ config.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", false, true);
+ //config.AddConsul("http://192.168.1.133:8500");
+ config.AddConsul(args);
+ config.AddCommandLine(args);
+ }).UseStartup();
+ }
}
diff --git a/Example/Startup.cs b/Example/Startup.cs
index cc8618e..0866448 100644
--- a/Example/Startup.cs
+++ b/Example/Startup.cs
@@ -5,6 +5,7 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Consul;
+using Extensions.Configuration.Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
@@ -17,41 +18,41 @@
namespace Example
{
- public class Startup
- {
- public Startup(IConfiguration configuration)
- {
- Configuration = configuration;
- }
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
- public IConfiguration Configuration { get; }
- public IContainer ApplicationContainer { get; private set; }
+ public IConfiguration Configuration { get; }
+ public IContainer ApplicationContainer { get; private set; }
- // This method gets called by the runtime. Use this method to add services to the container.
- public IServiceProvider ConfigureServices(IServiceCollection services)
- {
- services.AddOptions();
- services.Configure(Configuration.GetSection("TestConfig"));
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
+ // This method gets called by the runtime. Use this method to add services to the container.
+ public IServiceProvider ConfigureServices(IServiceCollection services)
+ {
+ services.AddOptions();
+ services.Configure(Configuration.GetSection("TestConfig"));
+ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
+ services.AddConsulConfigurationCenter();
+ var builder = new ContainerBuilder();
+ builder.Populate(services);
+ builder.RegisterType().InstancePerLifetimeScope();
+ builder.RegisterType().SingleInstance();
+ ApplicationContainer = builder.Build();
+ return new AutofacServiceProvider(ApplicationContainer);
+ }
- var builder = new ContainerBuilder();
- builder.Populate(services);
- builder.RegisterType().InstancePerLifetimeScope();
- builder.RegisterType().SingleInstance();
- ApplicationContainer = builder.Build();
- return new AutofacServiceProvider(ApplicationContainer);
- }
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app, IHostingEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseMvc();
- }
- }
+ app.UseMvc();
+ }
+ }
}
diff --git a/Example/appsettings.Development.json b/Example/appsettings.Development.json
index 4648c53..1d75a0b 100644
--- a/Example/appsettings.Development.json
+++ b/Example/appsettings.Development.json
@@ -1,7 +1,7 @@
{
"Logging": {
"LogLevel": {
- "Default": "Debug",
+ "Default": "Trace",
"System": "Information",
"Microsoft": "Information"
}
diff --git a/README.md b/README.md
index 23fdae2..5978957 100644
--- a/README.md
+++ b/README.md
@@ -6,50 +6,68 @@ Package | NuGet
---------|------
Extensions.Configuration.Consul|[![NuGet package](https://buildstats.info/nuget/Extensions.Configuration.Consul)](https://www.nuget.org/packages/Extensions.Configuration.Consul)
-# Usage
-### Register
+# Configuration
+
+## Hardcoded configuration
```csharp
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
- ConsulConfigurationExtensions.Shutdown();
}
+ public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+ WebHost.CreateDefaultBuilder(args).ConfigureAppConfiguration((context, config) =>
+ {
+ config.AddConsul("http://127.0.0.1:8500");
+ }).UseStartup();
+ }
+```
+
+## Command line configuration
+Command | Describetion
+---------|------
+consul-configuration-addr|Consul agent address
+consul-configuration-token|ACL Token HTTP API
+consul-configuration-dc|Consul data center
+consul-configuration-folder|Prefix of key
+
+```csharp
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateWebHostBuilder(args).Build().Run();
+ }
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args).ConfigureAppConfiguration((context, config) =>
{
- config.SetBasePath(Directory.GetCurrentDirectory());
- config.AddJsonFile("appsettings.json", false, true);
- config.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", false, true);
- config.AddConsul("http://192.168.1.142:8500", "", "AppSetting/", "dc1", true);
+ config.AddConsul(args);
}).UseStartup();
}
```
+## Reload when modified
```csharp
- public IServiceProvider ConfigureServices(IServiceCollection services)
+ public void ConfigureServices(IServiceCollection services)
{
+ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
+
+ services.AddConsulConfigurationCenter();
+
services.AddOptions();
services.Configure(Configuration.GetSection("TestConfig"));
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
-
- var builder = new ContainerBuilder();
- builder.Populate(services);
- builder.RegisterType().InstancePerLifetimeScope();
- builder.RegisterType().SingleInstance();
- ApplicationContainer = builder.Build();
- return new AutofacServiceProvider(ApplicationContainer);
+
}
```
-
-### InstancePerLifetimeScope
+# Usage
+## InstancePerLifetimeScope
```csharp
public class LibClass
{
@@ -66,7 +84,7 @@ Extensions.Configuration.Consul|[![NuGet package](https://buildstats.info/nuget/
}
```
-### SingleInstance
+## SingleInstance
```csharp
public class SingleClass
{
diff --git a/src/Extensions.Configuration.Consul/ConsulAgentConfiguration.cs b/src/Extensions.Configuration.Consul/ConsulAgentConfiguration.cs
index 5fefa40..9d78bf6 100644
--- a/src/Extensions.Configuration.Consul/ConsulAgentConfiguration.cs
+++ b/src/Extensions.Configuration.Consul/ConsulAgentConfiguration.cs
@@ -2,10 +2,10 @@
namespace Extensions.Configuration.Consul
{
- public class ConsulAgentConfiguration
- {
- public ConsulClientConfiguration ClientConfiguration { get; set; }
+ public class ConsulAgentConfiguration
+ {
+ public ConsulClientConfiguration ClientConfiguration { get; set; }
- public ConsulQueryOptions QueryOptions { get; set; }
- }
+ public ConsulQueryOptions QueryOptions { get; set; }
+ }
}
diff --git a/src/Extensions.Configuration.Consul/ConsulConfigurationExtensions.cs b/src/Extensions.Configuration.Consul/ConsulConfigurationExtensions.cs
deleted file mode 100644
index 9ca294b..0000000
--- a/src/Extensions.Configuration.Consul/ConsulConfigurationExtensions.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System;
-using Consul;
-using Microsoft.Extensions.Configuration;
-
-namespace Extensions.Configuration.Consul
-{
- public static class ConsulConfigurationExtensions
- {
-
- public static IConfigurationBuilder AddConsul(this IConfigurationBuilder configurationBuilder, ConsulClientConfiguration consulClientConfiguration, ConsulQueryOptions queryOptions, bool reloadOnChange = false)
- {
- if (consulClientConfiguration == null)
- throw new ArgumentNullException(nameof(consulClientConfiguration), "The agent url can't be empty.");
- return Add(configurationBuilder, new ConsulAgentConfiguration { ClientConfiguration = consulClientConfiguration, QueryOptions = queryOptions }, reloadOnChange);
- }
-
-
- public static IConfigurationBuilder AddConsul(this IConfigurationBuilder configurationBuilder, string agentUrl, string token = "", string prefix = "", string dataCenter = "", bool reloadOnChange = false)
- {
- if (string.IsNullOrWhiteSpace(agentUrl))
- throw new ArgumentNullException(nameof(agentUrl), "The agent url can't be empty.");
- return Add(configurationBuilder, new ConsulAgentConfiguration
- {
- ClientConfiguration = new ConsulClientConfiguration
- {
- Address = new Uri(agentUrl),
- Token = token,
- Datacenter = dataCenter
- },
- QueryOptions = new ConsulQueryOptions
- {
- Prefix = prefix
- }
- }, reloadOnChange);
- }
-
- private static IConfigurationBuilder Add(IConfigurationBuilder configurationBuilder, ConsulAgentConfiguration configuration, bool reloadOnChange)
- {
- return configurationBuilder.Add(new ConsulConfigurationSource(configuration, reloadOnChange));
- }
-
- public static void Shutdown()
- {
- ConsulConfigurationProvider.Shutdown();
- }
- }
-}
diff --git a/src/Extensions.Configuration.Consul/ConsulConfigurationHostedService.cs b/src/Extensions.Configuration.Consul/ConsulConfigurationHostedService.cs
new file mode 100644
index 0000000..40ee970
--- /dev/null
+++ b/src/Extensions.Configuration.Consul/ConsulConfigurationHostedService.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Consul;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace Extensions.Configuration.Consul
+{
+ public class ConsulConfigurationHostedService : IHostedService
+ {
+ private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
+ private ulong LastIndex { get; set; }
+
+ private HostedServiceOptions HostedServiceOptions { get; }
+
+ private ILogger Logger { get; }
+
+ public ConsulConfigurationHostedService(HostedServiceOptions hostedServiceOptions, ILogger logger)
+ {
+
+ HostedServiceOptions = hostedServiceOptions;
+ Logger = logger;
+ }
+
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ return Task.Factory.StartNew(async () =>
+ {
+ do
+ {
+ try
+ {
+ await QueryConsulAsync();
+ }
+ catch (Exception e)
+ {
+ Logger.LogError($"{e.Message}");
+ }
+
+ } while (!CancellationTokenSource.IsCancellationRequested);
+ }, CancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ }
+ private async Task QueryConsulAsync()
+ {
+ using (var client = new ConsulClient(options =>
+ {
+ options.WaitTime = ObserverManager.Configuration.ClientConfiguration.WaitTime;
+ options.Token = ObserverManager.Configuration.ClientConfiguration.Token;
+ options.Datacenter = ObserverManager.Configuration.ClientConfiguration.Datacenter;
+ options.Address = ObserverManager.Configuration.ClientConfiguration.Address;
+ }))
+ {
+ var result = await client.KV.List(ObserverManager.Configuration.QueryOptions.Folder, new QueryOptions
+ {
+ Token = ObserverManager.Configuration.ClientConfiguration.Token,
+ Datacenter = ObserverManager.Configuration.ClientConfiguration.Datacenter,
+ WaitIndex = LastIndex,
+ WaitTime = HostedServiceOptions.BlockingQueryWait
+ }, CancellationTokenSource.Token);
+ if (result.StatusCode != System.Net.HttpStatusCode.OK)
+ return;
+ if (result.LastIndex > LastIndex)
+ {
+ LastIndex = result.LastIndex;
+ ObserverManager.Notify(result.Response.ToList(), Logger);
+ }
+ }
+ }
+
+ public async Task StopAsync(CancellationToken cancellationToken)
+ {
+ CancellationTokenSource.Cancel();
+ await Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/Extensions.Configuration.Consul/ConsulConfigurationProvider.cs b/src/Extensions.Configuration.Consul/ConsulConfigurationProvider.cs
index 7734862..1042de6 100644
--- a/src/Extensions.Configuration.Consul/ConsulConfigurationProvider.cs
+++ b/src/Extensions.Configuration.Consul/ConsulConfigurationProvider.cs
@@ -1,127 +1,106 @@
-using System.Net.Http;
-using System.Text;
-using System.Threading;
+using System.Text;
using System.Threading.Tasks;
using Consul;
-using System;
+using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
namespace Extensions.Configuration.Consul
{
- internal class ConsulConfigurationProvider : ConfigurationProvider, IDisposable
- {
- private ConsulAgentConfiguration Configuration { get; }
-
- private bool ReloadOnChange { get; }
-
- private ulong LastIndex { get; set; }
-
- private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
-
- public ConsulConfigurationProvider(ConsulAgentConfiguration configuration, bool reloadOnChange)
- {
- Configuration = configuration;
- ReloadOnChange = reloadOnChange;
- }
-
-
- public static void Shutdown()
- {
- CancellationTokenSource.Cancel();
- }
-
- public override void Load()
- {
- QueryConsulAsync(CancellationTokenSource.Token).GetAwaiter().GetResult();
- if (ReloadOnChange)
- {
- Task.Factory.StartNew(async () =>
- {
- var failCount = 0;
- do
- {
- try
- {
- await QueryConsulAsync(CancellationTokenSource.Token, true);
- failCount = 0;
- }
- catch (Exception)
- {
- failCount++;
- if (Configuration.QueryOptions.FailRetryInterval != null)
- await Task.Delay(Configuration.QueryOptions.FailRetryInterval.Value,
- CancellationTokenSource.Token);
- }
-
- } while (!CancellationTokenSource.IsCancellationRequested && failCount <= Configuration.QueryOptions.ContinuousQueryFailures);
- }, CancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
- }
- }
-
-
- private async Task QueryConsulAsync(CancellationToken cancellationToken, bool blocking = false)
- {
- using (var client = new ConsulClient(options =>
- {
- options.WaitTime = Configuration.ClientConfiguration.WaitTime;
- options.Token = Configuration.ClientConfiguration.Token;
- options.Datacenter = Configuration.ClientConfiguration.Datacenter;
- options.Address = Configuration.ClientConfiguration.Address;
- }))
- {
- var result = await client.KV.List(Configuration.QueryOptions.Prefix, new QueryOptions
- {
- Token = Configuration.ClientConfiguration.Token,
- Datacenter = Configuration.ClientConfiguration.Datacenter,
- WaitIndex = LastIndex,
- WaitTime = blocking ? Configuration.QueryOptions.BlockingQueryWait : null
- }, cancellationToken);
- if (result.LastIndex > LastIndex)
- {
- if (result.Response != null)
- {
- var deleted = Data.Where(p => result.Response.All(c =>
- p.Key != (Configuration.QueryOptions.TrimPrefix
- ? c.Key.Substring(Configuration.QueryOptions.Prefix.Length,
- c.Key.Length - Configuration.QueryOptions.Prefix.Length)
- : c.Key))).ToList();
-
- foreach (var del in deleted)
- {
- Data.Remove(del.Key);
- }
-
- foreach (var item in result.Response)
- {
- if (Configuration.QueryOptions.TrimPrefix)
- {
- item.Key = item.Key.Substring(Configuration.QueryOptions.Prefix.Length,
- item.Key.Length - Configuration.QueryOptions.Prefix.Length);
- }
-
- if (!string.IsNullOrWhiteSpace(item.Key))
- {
- Set(item.Key,
- item.Value != null && item.Value?.Length > 0
- ? Encoding.UTF8.GetString(item.Value)
- : "");
- }
- }
- }
- else
- Data.Clear();
-
- LastIndex = result.LastIndex;
- if (ReloadOnChange && blocking)
- OnReload();
- }
- }
- }
-
- public void Dispose()
- {
- CancellationTokenSource.Cancel();
- }
- }
+ internal class ConsulConfigurationProvider : ConfigurationProvider, IObserver
+ {
+ private ConsulAgentConfiguration Configuration { get; }
+
+
+ public ConsulConfigurationProvider(ConsulAgentConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+
+ public override void Load()
+ {
+ QueryConsulAsync().GetAwaiter().GetResult();
+ }
+
+
+ private async Task QueryConsulAsync()
+ {
+ using (var client = new ConsulClient(options =>
+ {
+ options.WaitTime = Configuration.ClientConfiguration.WaitTime;
+ options.Token = Configuration.ClientConfiguration.Token;
+ options.Datacenter = Configuration.ClientConfiguration.Datacenter;
+ options.Address = Configuration.ClientConfiguration.Address;
+ }))
+ {
+ var result = await client.KV.List(Configuration.QueryOptions.Folder, new QueryOptions
+ {
+ Token = Configuration.ClientConfiguration.Token,
+ Datacenter = Configuration.ClientConfiguration.Datacenter
+ });
+
+ if (result.Response == null || !result.Response.Any())
+ return;
+
+ foreach (var item in result.Response)
+ {
+ item.Key = item.Key.TrimFolderPrefix(Configuration.QueryOptions.Folder);
+ if (string.IsNullOrWhiteSpace(item.Key))
+ return;
+ Set(item.Key, ReadValue(item.Value));
+ }
+ }
+ }
+
+
+ private string ReadValue(byte[] bytes)
+ {
+ return bytes != null && bytes.Length > 0
+ ? Encoding.UTF8.GetString(bytes)
+ : "";
+ }
+
+ public void OnChange(List kVs, ILogger logger)
+ {
+ if (kVs == null || !kVs.Any())
+ {
+ Data.Clear();
+ OnReload();
+ return;
+ }
+
+ var deleted = Data.Where(p => kVs.All(c =>
+ p.Key != c.Key.TrimFolderPrefix(Configuration.QueryOptions.Folder))).ToList();
+
+ foreach (var del in deleted)
+ {
+ logger.LogTrace($"Remove key [{del.Key}]");
+ Data.Remove(del.Key);
+ }
+
+ foreach (var item in kVs)
+ {
+ item.Key = item.Key.TrimFolderPrefix(Configuration.QueryOptions.Folder);
+ if (string.IsNullOrWhiteSpace(item.Key))
+ continue;
+ var newValue = ReadValue(item.Value);
+ if (Data.TryGetValue(item.Key, out var oldValue))
+ {
+ if (oldValue == newValue)
+ continue;
+
+ Set(item.Key, newValue);
+ logger.LogTrace($"The value of key [{item.Key}] is changed from [{oldValue}] to [{newValue}]");
+ }
+ else
+ {
+ Set(item.Key, newValue);
+ logger.LogTrace($"Added key [{item.Key}][{newValue}]");
+ }
+ OnReload();
+ }
+ }
+ }
}
diff --git a/src/Extensions.Configuration.Consul/ConsulConfigurationSource.cs b/src/Extensions.Configuration.Consul/ConsulConfigurationSource.cs
index 7ebfcfd..fc3e602 100644
--- a/src/Extensions.Configuration.Consul/ConsulConfigurationSource.cs
+++ b/src/Extensions.Configuration.Consul/ConsulConfigurationSource.cs
@@ -2,21 +2,20 @@
namespace Extensions.Configuration.Consul
{
- internal class ConsulConfigurationSource : IConfigurationSource
- {
- private ConsulAgentConfiguration Config { get; }
+ internal class ConsulConfigurationSource : IConfigurationSource
+ {
+ private ConsulAgentConfiguration Config { get; }
- private bool ReloadOnChange { get; }
+ public ConsulConfigurationSource(ConsulAgentConfiguration config)
+ {
+ Config = config;
+ }
- public ConsulConfigurationSource(ConsulAgentConfiguration config, bool reloadOnChange)
- {
- Config = config;
- ReloadOnChange = reloadOnChange;
- }
-
- public IConfigurationProvider Build(IConfigurationBuilder builder)
- {
- return new ConsulConfigurationProvider(Config, ReloadOnChange);
- }
- }
+ public IConfigurationProvider Build(IConfigurationBuilder builder)
+ {
+ var provider = new ConsulConfigurationProvider(Config);
+ ObserverManager.Attach(provider, Config);
+ return provider;
+ }
+ }
}
diff --git a/src/Extensions.Configuration.Consul/ConsulQueryOptions.cs b/src/Extensions.Configuration.Consul/ConsulQueryOptions.cs
index e5c3def..f33afa4 100644
--- a/src/Extensions.Configuration.Consul/ConsulQueryOptions.cs
+++ b/src/Extensions.Configuration.Consul/ConsulQueryOptions.cs
@@ -2,31 +2,17 @@
namespace Extensions.Configuration.Consul
{
- public class ConsulQueryOptions
- {
- ///
- /// The prefix string of consul key
- ///
- public string Prefix { get; set; }
+ public class ConsulQueryOptions
+ {
+ ///
+ /// The prefix string of consul key
+ ///
+ public string Folder { get; set; }
- ///
- /// Remove prefix string of consul key when binding
- ///
- public bool TrimPrefix { get; set; } = false;
+ }
- ///
- /// Wait time of long polling,the defautl is 2 minutes
- ///
- public TimeSpan? BlockingQueryWait { get; set; } = TimeSpan.FromMinutes(2);
-
- ///
- /// Continuous query failures, the default is ignore exception.
- ///
- public int ContinuousQueryFailures { get; set; } = int.MaxValue;
-
- ///
- /// Failure retry interval,the default is 2 minutes
- ///
- public TimeSpan? FailRetryInterval { get; set; } = TimeSpan.FromMinutes(2);
- }
+ public class HostedServiceOptions
+ {
+ public TimeSpan BlockingQueryWait { get; set; } = TimeSpan.FromMinutes(3);
+ }
}
diff --git a/src/Extensions.Configuration.Consul/Extensions.Configuration.Consul.csproj b/src/Extensions.Configuration.Consul/Extensions.Configuration.Consul.csproj
index 46f39ca..926ff8f 100644
--- a/src/Extensions.Configuration.Consul/Extensions.Configuration.Consul.csproj
+++ b/src/Extensions.Configuration.Consul/Extensions.Configuration.Consul.csproj
@@ -10,12 +10,14 @@
Extensions.Configuration.Consul
configuration,config,consul
Extensions.Configuration.Consul
- 1.0.2
+ 2.0.0
-
+
+
+
diff --git a/src/Extensions.Configuration.Consul/ExtensionsMethods.cs b/src/Extensions.Configuration.Consul/ExtensionsMethods.cs
new file mode 100644
index 0000000..9aeb28b
--- /dev/null
+++ b/src/Extensions.Configuration.Consul/ExtensionsMethods.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using Consul;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace Extensions.Configuration.Consul
+{
+ public static class ExtensionsMethods
+ {
+ public static IConfigurationBuilder AddConsul(this IConfigurationBuilder configurationBuilder, string address = "http://127.0.0.1:8500", string token = "", string folder = "", string dataCenter = "dc1")
+ {
+ if (string.IsNullOrWhiteSpace(address))
+ throw new ArgumentNullException(nameof(address), "The address can't be empty.");
+
+ if (!string.IsNullOrWhiteSpace(folder) && !folder.EndsWith("/"))
+ throw new ArgumentException("Folder must end with \"/\".");
+
+ return Add(configurationBuilder, new ConsulAgentConfiguration
+ {
+ ClientConfiguration = new ConsulClientConfiguration
+ {
+ Address = new Uri(address),
+ Token = token,
+ Datacenter = dataCenter
+ },
+ QueryOptions = new ConsulQueryOptions
+ {
+ Folder = folder
+ }
+ });
+ }
+ public static IConfigurationBuilder AddConsul(this IConfigurationBuilder configurationBuilder, ConsulClientConfiguration consulClientConfiguration, string folder = "")
+ {
+ if (consulClientConfiguration == null)
+ throw new ArgumentNullException(nameof(consulClientConfiguration), "The agent url can't be empty.");
+
+ if (!string.IsNullOrWhiteSpace(folder) && !folder.EndsWith("/"))
+ throw new ArgumentException("Folder must end with \"/\".");
+
+ return Add(configurationBuilder, new ConsulAgentConfiguration
+ {
+ ClientConfiguration = consulClientConfiguration,
+ QueryOptions = new ConsulQueryOptions
+ {
+ Folder = folder
+ }
+ });
+ }
+
+ public static IConfigurationBuilder AddConsul(this IConfigurationBuilder configurationBuilder, string[] args)
+ {
+ var dic = ParseCommandLineArgs(args);
+ return configurationBuilder.AddConsul(new ConsulClientConfiguration
+ {
+ Address = new Uri(dic.GetDictionaryValue("consul-configuration-addr", "http://127.0.0.1:8500")),
+ Token = dic.GetDictionaryValue("consul-configuration-token"),
+ Datacenter = dic.GetDictionaryValue("consul-configuration-dc", "dc1"),
+ WaitTime = TimeSpan.FromSeconds(10)
+ }, dic.GetDictionaryValue("consul-configuration-folder"));
+ }
+
+ private static string GetDictionaryValue(this Dictionary dictionary, string key, string defaultValue = "")
+ {
+ if (dictionary.TryGetValue(key, out var value))
+ return value;
+ return defaultValue;
+ }
+
+ public static IServiceCollection AddConsulConfigurationCenter(this IServiceCollection services, int blockingQueryWaitSeconds = 180)
+ {
+ if (blockingQueryWaitSeconds <= 0)
+ throw new ArgumentException("The value of blockingQueryWaitSeconds must be greater than 0.", nameof(blockingQueryWaitSeconds));
+ services.AddSingleton(new HostedServiceOptions { BlockingQueryWait = TimeSpan.FromSeconds(blockingQueryWaitSeconds) });
+ services.AddSingleton();
+ return services;
+ }
+
+ private static IConfigurationBuilder Add(IConfigurationBuilder configurationBuilder, ConsulAgentConfiguration configuration)
+ {
+ return configurationBuilder.Add(new ConsulConfigurationSource(configuration));
+ }
+
+ internal static string TrimFolderPrefix(this string key, string folder)
+ {
+ if (string.IsNullOrWhiteSpace(folder) || folder.Length == 0)
+ return key;
+ return key.Substring(folder.Length, key.Length - folder.Length);
+ }
+
+ private static Dictionary ParseCommandLineArgs(IEnumerable args)
+ {
+ var dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ using (var enumerator = args.GetEnumerator())
+ {
+ while (enumerator.MoveNext())
+ {
+ var key1 = enumerator.Current;
+ var startIndex = 0;
+ if (key1.StartsWith("--"))
+ startIndex = 2;
+ else if (key1.StartsWith("-"))
+ startIndex = 1;
+ else if (key1.StartsWith("/"))
+ {
+ key1 = $"--{key1.Substring(1)}";
+ startIndex = 2;
+ }
+ var length = key1.IndexOf('=');
+ string index;
+ string str;
+ if (length < 0)
+ {
+ if (startIndex != 0)
+ {
+ if (startIndex != 1)
+ index = key1.Substring(startIndex);
+ else
+ continue;
+
+ if (enumerator.MoveNext())
+ str = enumerator.Current;
+ else
+ continue;
+ }
+ else
+ continue;
+ }
+ else
+ {
+ if (startIndex == 1)
+ throw new FormatException(key1);
+ index = key1.Substring(startIndex, length - startIndex);
+ str = key1.Substring(length + 1);
+ }
+ dictionary[index] = str;
+ }
+ }
+
+ return dictionary;
+ }
+ }
+}
diff --git a/src/Extensions.Configuration.Consul/IObserver.cs b/src/Extensions.Configuration.Consul/IObserver.cs
new file mode 100644
index 0000000..cecba6b
--- /dev/null
+++ b/src/Extensions.Configuration.Consul/IObserver.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using Consul;
+using Microsoft.Extensions.Logging;
+
+namespace Extensions.Configuration.Consul
+{
+ internal interface IObserver
+ {
+ void OnChange(List kVPairs, ILogger logger);
+ }
+}
diff --git a/src/Extensions.Configuration.Consul/ObserverManager.cs b/src/Extensions.Configuration.Consul/ObserverManager.cs
new file mode 100644
index 0000000..c1c3dd7
--- /dev/null
+++ b/src/Extensions.Configuration.Consul/ObserverManager.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using Consul;
+using Microsoft.Extensions.Logging;
+
+namespace Extensions.Configuration.Consul
+{
+ internal static class ObserverManager
+ {
+ private static IObserver Observer { get; set; }
+
+ public static ConsulAgentConfiguration Configuration { get; private set; }
+
+ public static void Attach(IObserver observer, ConsulAgentConfiguration configuration)
+ {
+ Observer = observer;
+ Configuration = configuration;
+ }
+
+ public static void Notify(List kVPairs, ILogger logger)
+ {
+ Observer.OnChange(kVPairs, logger);
+ }
+ }
+}