THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Browse Source

Add ConfigurationBuilder support (#105)

* Add .ConfigureAwait(false)

* Suppport ConfigurationBuilder

* Add Nacos support ConfigurationBuilder

* useGrpc
pull/110/head
彭伟 3 months ago
committed by GitHub
parent
commit
43cb177326
Signed by untrusted user: GitHub GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      .editorconfig
  2. 21
      Directory.Build.props
  3. 26
      nacos-sdk-csharp.sln
  4. 114
      samples/ConfigurationBuilderApp/ConfigurationBuilderApp.csproj
  5. 31
      samples/ConfigurationBuilderApp/Startup.cs
  6. 114
      samples/ConfigurationBuilderApp/Web.config
  7. 10
      src/Nacos.Microsoft.Extensions.Configuration/DefaultJsonConfigurationStringParser.cs
  8. 16
      src/Nacos.Microsoft.Extensions.Configuration/Impl/MsConfigServerHttpAgent.cs
  9. 2
      src/Nacos.Microsoft.Extensions.Configuration/Impl/NacosMsConfigClient.cs
  10. 48
      src/Nacos.System.Configuration/ConfigListener.cs
  11. 39
      src/Nacos.System.Configuration/ConfigListenerCollection.cs
  12. 36
      src/Nacos.System.Configuration/Nacos.System.Configuration.csproj
  13. 203
      src/Nacos.System.Configuration/NacosConfigurationBuilder.cs
  14. 76
      src/Nacos.System.Configuration/NacosConfigurationSection.cs
  15. 9
      src/Nacos.System.Configuration/README.md
  16. 2
      src/Nacos/Nacos.csproj

49
.editorconfig

@ -0,0 +1,49 @@
root = true
[*]
charset = utf-8-bom
end_of_line = crlf
indent_size = 4
indent_style = space
insert_final_newline = true
tab_width = 4
trim_trailing_whitespace = true
[.bowerrc|*.yml]
charset = utf-8
# Xml project files
[*.*proj]
indent_size = 2
# Xml build files
[*.builds]
indent_size = 2
# Xml files
[*.{xml,stylecop,resx,ruleset,xsd}]
indent_size = 2
# Xml config files
[*.{props,targets,config,nuspec,vsixmanifest,vsct}]
indent_size = 2
# JSON files
[*.json]
indent_size = 2
# Shell scripts
[*.sh]
end_of_line = lf
# ReSharper properties
resharper_csharp_wrap_lines=false
resharper_enforce_line_ending_style=true
resharper_js_wrap_lines=false
resharper_protobuf_wrap_lines=false
resharper_use_indent_from_vs=false
resharper_vb_wrap_lines=false
resharper_xmldoc_wrap_lines=false
resharper_xml_wrap_lines=false

21
Directory.Build.props

@ -1,18 +1,16 @@
<Project>
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<RepositoryType>git</RepositoryType>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn),1573,1591,1712</NoWarn>
<CodeAnalysisRuleSet>..\..\_stylecop\codeanalysis.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn),1573,1591,1712</NoWarn>
<CodeAnalysisRuleSet>..\..\_stylecop\codeanalysis.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="5.*" PrivateAssets="All" />
<ItemGroup>
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="5.*" PrivateAssets="All" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.*" PrivateAssets="All" Condition="'$(OS)' != 'Windows_NT'" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.*" PrivateAssets="All"/>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.164">
@ -20,4 +18,5 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
</Project>

26
nacos-sdk-csharp.sln

@ -31,9 +31,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nacos.AspNetCore.Tests", "t
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "parsers", "parsers", "{CFFCAA8B-3562-420B-AA8B-C525CC1ECD78}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nacos.YamlParser", "parsers\Nacos.YamlParser\Nacos.YamlParser.csproj", "{94CF8EEE-3812-47C6-998F-9105EB092036}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nacos.YamlParser", "parsers\Nacos.YamlParser\Nacos.YamlParser.csproj", "{94CF8EEE-3812-47C6-998F-9105EB092036}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nacos.IniParser", "parsers\Nacos.IniParser\Nacos.IniParser.csproj", "{CEE5E43E-F4E1-4E46-9B41-ABCBECDDEA63}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nacos.IniParser", "parsers\Nacos.IniParser\Nacos.IniParser.csproj", "{CEE5E43E-F4E1-4E46-9B41-ABCBECDDEA63}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nacos.System.Configuration", "src\Nacos.System.Configuration\Nacos.System.Configuration.csproj", "{7C20F5FB-33D4-460A-86F4-FC42122FA543}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConfigurationBuilderApp", "samples\ConfigurationBuilderApp\ConfigurationBuilderApp.csproj", "{CA0A661F-01D5-4DF7-9CD0-0399F89A8D47}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{81C1E3C0-6709-4726-A27D-C2346FAF39D7}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
README.md = README.md
README.zh-cn.md = README.zh-cn.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -89,6 +101,14 @@ Global
{CEE5E43E-F4E1-4E46-9B41-ABCBECDDEA63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CEE5E43E-F4E1-4E46-9B41-ABCBECDDEA63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CEE5E43E-F4E1-4E46-9B41-ABCBECDDEA63}.Release|Any CPU.Build.0 = Release|Any CPU
{7C20F5FB-33D4-460A-86F4-FC42122FA543}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C20F5FB-33D4-460A-86F4-FC42122FA543}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C20F5FB-33D4-460A-86F4-FC42122FA543}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C20F5FB-33D4-460A-86F4-FC42122FA543}.Release|Any CPU.Build.0 = Release|Any CPU
{CA0A661F-01D5-4DF7-9CD0-0399F89A8D47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA0A661F-01D5-4DF7-9CD0-0399F89A8D47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA0A661F-01D5-4DF7-9CD0-0399F89A8D47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA0A661F-01D5-4DF7-9CD0-0399F89A8D47}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -106,6 +126,8 @@ Global
{F3DD367A-6EF5-4188-9D28-6858AA2F60F9} = {8176B7FC-151E-4EFF-A693-F60A39109595}
{94CF8EEE-3812-47C6-998F-9105EB092036} = {CFFCAA8B-3562-420B-AA8B-C525CC1ECD78}
{CEE5E43E-F4E1-4E46-9B41-ABCBECDDEA63} = {CFFCAA8B-3562-420B-AA8B-C525CC1ECD78}
{7C20F5FB-33D4-460A-86F4-FC42122FA543} = {C473C3A7-1B44-4E1F-83C0-745AD0566FE9}
{CA0A661F-01D5-4DF7-9CD0-0399F89A8D47} = {25B1A184-1541-4F4E-A151-24A47CC08F34}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A1C5215E-0E70-4C04-B21E-5209BCF32472}

114
samples/ConfigurationBuilderApp/ConfigurationBuilderApp.csproj

@ -0,0 +1,114 @@
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CA0A661F-01D5-4DF7-9CD0-0399F89A8D47}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<RootNamespace>ConfigurationBuilderApp</RootNamespace>
<AssemblyName>ConfigurationBuilderApp</AssemblyName>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<UseIISExpress>true</UseIISExpress>
<Use64BitIISExpress />
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\ConfigurationBuilderApp.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\ConfigurationBuilderApp.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
</ItemGroup>
<ItemGroup>
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="Startup.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Nacos.System.Configuration\Nacos.System.Configuration.csproj">
<Project>{7c20f5fb-33d4-460a-86f4-fc42122fa543}</Project>
<Name>Nacos.System.Configuration</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Owin.Host.SystemWeb">
<Version>4.2.0</Version>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>12012</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:12012/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

31
samples/ConfigurationBuilderApp/Startup.cs

@ -0,0 +1,31 @@
using ConfigurationBuilderApp;
using Microsoft.Owin;
using Owin;
using System.Configuration;
using System.Threading.Tasks;
[assembly: OwinStartup(typeof(Startup))]
namespace ConfigurationBuilderApp
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Run(context =>
{
context.Response.StatusCode = 404;
var key = context.Request.Query["key"];
if (string.IsNullOrWhiteSpace(key)) return Task.CompletedTask;
var value = ConfigurationManager.AppSettings[key];
if (value != null) context.Response.StatusCode = 200;
context.Response.Headers["Content-Type"] = "text/html; charset=utf-8";
return context.Response.WriteAsync(value ?? "undefined");
});
}
}
}

114
samples/ConfigurationBuilderApp/Web.config

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<section name="nacos" type="Nacos.System.Configuration.NacosConfigurationSection, Nacos.System.Configuration" />
</configSections>
<configBuilders>
<builders>
<add name="nacos" type="Nacos.System.Configuration.NacosConfigurationBuilder, Nacos.System.Configuration" />
</builders>
</configBuilders>
<nacos tenant="cs" serverAddresses="http://localhost:8848/" userName="test2" password="123456" useGrpc="true">
<listeners>
<listener dataId="common" />
<listener dataId="demo" />
</listeners>
</nacos>
<appSettings configBuilders="nacos" />
<system.web>
<compilation debug="true" targetFramework="4.7.1" />
<httpRuntime targetFramework="4.7.1" />
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Memory" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Data.Common" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.StackTrace" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.Tracing" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Globalization.Extensions" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" culture="neutral" publicKeyToken="b77a5c561934e089" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Sockets" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.Serialization.Primitives" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Algorithms" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Security.SecureString" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Threading.Overlapped" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Xml.XPath.XDocument" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

10
src/Nacos.Microsoft.Extensions.Configuration/DefaultJsonConfigurationStringParser.cs

@ -6,11 +6,11 @@ namespace Nacos.Microsoft.Extensions.Configuration
using Nacos.Config;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using global::System;
using global::System.Collections.Generic;
using global::System.Globalization;
using global::System.IO;
using global::System.Linq;
internal class DefaultJsonConfigurationStringParser : INacosConfigurationParser
{

16
src/Nacos.Microsoft.Extensions.Configuration/Impl/MsConfigServerHttpAgent.cs

@ -1,16 +1,16 @@
namespace Nacos.Microsoft.Extensions.Configuration
{
using global::System;
using global::System.Collections.Generic;
using global::System.Diagnostics;
using global::System.Linq;
using global::System.Net;
using global::System.Net.Http;
using global::System.Threading;
using global::System.Threading.Tasks;
using Nacos.Config;
using Nacos.Config.Http;
using Nacos.Security;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class MsConfigServerHttpAgent : HttpAgent, IDisposable
{

2
src/Nacos.Microsoft.Extensions.Configuration/Impl/NacosMsConfigClient.cs

@ -1,9 +1,9 @@
namespace Nacos.Microsoft.Extensions.Configuration
{
using global::Microsoft.Extensions.Logging;
using global::System.Collections.Generic;
using Nacos;
using Nacos.Config.Http;
using System.Collections.Generic;
public class NacosMsConfigClient : AbstNacosConfigClient
{

48
src/Nacos.System.Configuration/ConfigListener.cs

@ -0,0 +1,48 @@
namespace Nacos.System.Configuration
{
using global::System;
using global::System.Configuration;
using Nacos.Config;
using Nacos.Microsoft.Extensions.Configuration;
public class ConfigListener : ConfigurationSection
{
/// <summary>
/// Configuration ID
/// </summary>
[ConfigurationProperty("dataId", IsRequired = false)]
public string DataId => this["dataId"]?.ToString();
/// <summary>
/// Configuration group
/// </summary>
[ConfigurationProperty("group", DefaultValue = "DEFAULT_GROUP", IsRequired = false)]
public string Group => this["group"]?.ToString();
[ConfigurationProperty("parserType", IsRequired = false)]
public string ParserType => this["parserType"] as string;
/// <summary>
/// The configuration parser, default is json
/// </summary>
public INacosConfigurationParser NacosConfigurationParser
{
get
{
_parser ??= new Lazy<INacosConfigurationParser>(() =>
{
if (string.IsNullOrWhiteSpace(ParserType)) return null;
var type = Type.GetType(ParserType);
if (type == null) throw new TypeLoadException("不能找到类型" + ParserType);
return (INacosConfigurationParser)Activator.CreateInstance(type);
});
return _parser.Value ?? DefaultJsonConfigurationStringParser.Instance;
}
}
private Lazy<INacosConfigurationParser> _parser;
}
}

39
src/Nacos.System.Configuration/ConfigListenerCollection.cs

@ -0,0 +1,39 @@
namespace Nacos.System.Configuration
{
using global::System.Configuration;
public class ConfigListenerCollection : ConfigurationElementCollection
{
public ConfigListenerCollection() => AddElementName = "listener";
/// <summary>
/// Gets or sets the <see cref="ConfigListener"/> at the specified index.
/// </summary>
/// <value>
/// The <see cref="ConfigListener"/>.
/// </value>
/// <param name="index">The index.</param>
public ConfigListener this[int index]
{
get => BaseGet(index) as ConfigListener;
set
{
if (BaseGet(index) != null) BaseRemoveAt(index);
BaseAdd(index, value);
}
}
/// <summary>
/// Creates the new element.
/// </summary>
protected override ConfigurationElement CreateNewElement() => new ConfigListener();
/// <summary>
/// Gets the element key.
/// </summary>
/// <param name="element">The element.</param>
protected override object GetElementKey(ConfigurationElement element)
=> $"{((ConfigListener)element).Group}#{((ConfigListener)element).DataId}";
}
}

36
src/Nacos.System.Configuration/Nacos.System.Configuration.csproj

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../build/version.props" />
<PropertyGroup>
<TargetFramework>net471</TargetFramework>
<PackageId>nacos-sdk-csharp.ConfigurationManger</PackageId>
<VersionPrefix>$(NugetVersion)</VersionPrefix>
<VersionSuffix></VersionSuffix>
<Authors>nacos-sdk-csharp Contributors</Authors>
<Description>nacos csharp sdk</Description>
<PackageTags>nacos,csharp,sdk,msconfig,ConfigurationBuilder</PackageTags>
<PackageProjectUrl>https://github.com/nacos-group/nacos-sdk-csharp</PackageProjectUrl>
<RepositoryUrl>https://github.com/nacos-group/nacos-sdk-csharp</RepositoryUrl>
<ProjectUrl>https://github.com/nacos-group/nacos-sdk-csharp</ProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageReleaseNotes>
</PackageReleaseNotes>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Include="../Nacos.Microsoft.Extensions.Configuration/DefaultJsonConfigurationStringParser.cs" />
<Compile Include="../Nacos.Microsoft.Extensions.Configuration/Impl/*.cs" />
<None Include="../../LICENSE" Pack="true" Visible="false" PackagePath="" />
<ProjectReference Include="..\Nacos\Nacos.csproj" />
<PackageReference Include="Microsoft.Configuration.ConfigurationBuilders.Base" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.0" />
<Reference Include="System.Configuration" />
</ItemGroup>
</Project>

203
src/Nacos.System.Configuration/NacosConfigurationBuilder.cs

@ -0,0 +1,203 @@
namespace Nacos.System.Configuration
{
using global::Microsoft.Configuration.ConfigurationBuilders;
using global::Microsoft.Extensions.Logging;
using global::Microsoft.Extensions.Logging.Abstractions;
using global::Microsoft.Extensions.Options;
using global::System;
using global::System.Collections.Concurrent;
using global::System.Collections.Generic;
using global::System.Collections.Specialized;
using global::System.Configuration;
using global::System.Diagnostics;
using global::System.Linq;
using global::System.Reflection;
using global::System.Threading.Tasks;
using Nacos.Microsoft.Extensions.Configuration;
using Nacos.V2;
using Nacos.V2.Config;
public class NacosConfigurationBuilder : KeyValueConfigBuilder
{
public static ILoggerFactory LoggerFactory { get; set; }
private static readonly FieldInfo ConfigurationManagerReset = typeof(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static)!;
private static readonly Dictionary<string, Tuple<NacosConfigurationSection, object>> ClientCache = new Dictionary<string, Tuple<NacosConfigurationSection, object>>(StringComparer.OrdinalIgnoreCase);
private static readonly ConcurrentDictionary<string, string> ConfigCache = new ConcurrentDictionary<string, string>();
private Task<IDictionary<string, string>[]> _data;
public override void Initialize(string name, NameValueCollection config)
{
config ??= new NameValueCollection();
if (config["mode"] == null)
{
config["mode"] = nameof(KeyValueMode.Greedy);
}
base.Initialize(name, config);
}
protected override void LazyInitialize(string name, NameValueCollection config)
{
base.LazyInitialize(name, config);
var sectionName = string.IsNullOrWhiteSpace(config["nacosConfig"]) ? "nacos" : config["nacosConfig"];
if (!ClientCache.TryGetValue(sectionName, out var cache))
{
lock (ClientCache)
{
if (!ClientCache.TryGetValue(sectionName, out cache))
{
var nacosConfig = NacosConfigurationSection.GetConfig(sectionName);
if (nacosConfig == null)
{
LoggerFactory?.CreateLogger<NacosConfigurationBuilder>().LogWarning($"Can't found `{sectionName}` config");
Trace.TraceWarning($"Can't found `{sectionName}` config");
ClientCache[sectionName] = null;
return;
}
if (nacosConfig.UseGrpc)
{
var client = new NacosConfigService(LoggerFactory ?? NullLoggerFactory.Instance, Options.Create(new NacosSdkOptions
{
ServerAddresses = nacosConfig.ServerAddresses.Split(';', ',').ToList(),
Namespace = nacosConfig.Tenant,
AccessKey = nacosConfig.AccessKey,
ContextPath = nacosConfig.ContextPath,
EndPoint = nacosConfig.EndPoint,
DefaultTimeOut = nacosConfig.DefaultTimeOut,
SecretKey = nacosConfig.SecretKey,
Password = nacosConfig.Password,
UserName = nacosConfig.UserName,
ListenInterval = 20000
}));
ClientCache[sectionName] = cache = Tuple.Create(nacosConfig, (object)client);
}
else
{
var client = new NacosMsConfigClient(LoggerFactory ?? NullLoggerFactory.Instance, new NacosOptions
{
ServerAddresses = nacosConfig.ServerAddresses.Split(';', ',').ToList(),
Namespace = nacosConfig.Tenant,
AccessKey = nacosConfig.AccessKey,
ClusterName = nacosConfig.ClusterName,
ContextPath = nacosConfig.ContextPath,
EndPoint = nacosConfig.EndPoint,
DefaultTimeOut = nacosConfig.DefaultTimeOut,
SecretKey = nacosConfig.SecretKey,
Password = nacosConfig.Password,
UserName = nacosConfig.UserName,
ListenInterval = 20000
});
ClientCache[sectionName] = cache = Tuple.Create(nacosConfig, (object)client);
}
if (nacosConfig.Listeners != null && nacosConfig.Listeners.Count > 0)
{
try
{
_ = Task.WhenAll(nacosConfig.Listeners
.OfType<ConfigListener>()
.Select(item => cache.Item2 is INacosConfigClient ncc
? ncc.AddListenerAsync(new AddListenerRequest
{
DataId = item.DataId,
Group = item.Group,
Tenant = nacosConfig.Tenant,
Callbacks = new List<Action<string>> { x => CallBackReload($"{nacosConfig.Tenant}#{item.Group}#{item.DataId}", x) }
})
: ((INacosConfigService)cache.Item2).AddListener(item.DataId, item.Group ?? ConstValue.DefaultGroup, new MsConfigListener($"{nacosConfig.Tenant}#{item.Group}#{item.DataId}"))));
}
catch (Exception ex)
{
LoggerFactory?.CreateLogger<NacosConfigurationBuilder>().LogError(ex, "AddListener fail.");
Trace.TraceError("AddListener fail" + Environment.NewLine + ex);
}
}
}
}
}
_data = cache == null ? Task.FromResult(Array.Empty<IDictionary<string, string>>()) : GetConfig(cache.Item1, cache.Item2);
}
private static Task<IDictionary<string, string>[]> GetConfig(NacosConfigurationSection config, object client) =>
Task.WhenAll(config.Listeners.OfType<ConfigListener>()
.Select(async item =>
{
if (!ConfigCache.TryGetValue($"{config.Tenant}#{item.Group}#{item.DataId}", out var data))
{
try
{
data = await (client is INacosConfigClient ncc
? ncc.GetConfigAsync(new GetConfigRequest
{
DataId = item.DataId,
Group = item.Group,
Tenant = config.Tenant
})
: ((INacosConfigService)client).GetConfig(item.DataId, item.Group ?? ConstValue.DefaultGroup, 3000))
.ConfigureAwait(false);
if (data == null)
{
LoggerFactory?.CreateLogger<NacosConfigurationBuilder>().LogWarning($"Can't get config {item.Group}#{item.DataId}");
}
}
catch (Exception ex)
{
LoggerFactory?.CreateLogger<NacosConfigurationBuilder>().LogError(ex, $"GetConfig({item.Group}#{item.DataId}) fail.");
Trace.TraceError($"GetConfig({item.Group}#{item.DataId}) fail" + Environment.NewLine + ex);
}
}
return data == null ? new Dictionary<string, string>() : item.NacosConfigurationParser.Parse(data);
}));
private static void CallBackReload(string key, string data)
{
ConfigCache[key] = data;
try
{
ConfigurationManagerReset.SetValue(null, 0);
}
catch
{
// ignored
}
}
public override string GetValue(string key)
{
foreach (var dic in _data.GetAwaiter().GetResult())
{
if (dic.TryGetValue(key, out var value)) return value;
}
return null;
}
public override ICollection<KeyValuePair<string, string>> GetAllValues(string prefix) =>
_data.GetAwaiter().GetResult().SelectMany(dic => dic).ToArray();
private class MsConfigListener : IListener
{
private readonly string _key;
public MsConfigListener(string key) => _key = key;
public void ReceiveConfigInfo(string configInfo) => CallBackReload(_key, configInfo);
}
}
}

76
src/Nacos.System.Configuration/NacosConfigurationSection.cs

@ -0,0 +1,76 @@
namespace Nacos.System.Configuration
{
using global::System;
using global::System.Configuration;
public class NacosConfigurationSection : ConfigurationSection
{
/// <summary>
/// Nacos Server Addresses
/// </summary>
[ConfigurationProperty("serverAddresses", IsRequired = true)]
public string ServerAddresses => this["serverAddresses"].ToString();
/// <summary>
/// The configuration listeners
/// </summary>
[ConfigurationProperty("listeners", IsRequired = true)]
public ConfigListenerCollection Listeners => this["listeners"] as ConfigListenerCollection;
/// <summary>
/// Tenant information. It corresponds to the Namespace field in Nacos.
/// </summary>
[ConfigurationProperty("tenant", IsRequired = true)]
public string Tenant => this["tenant"]?.ToString();
/// <summary>
/// EndPoint
/// </summary>
[ConfigurationProperty("endPoint", IsRequired = false)]
public string EndPoint => this["endPoint"]?.ToString();
[ConfigurationProperty("contextPath", DefaultValue = "nacos")]
public string ContextPath => this["contextPath"]?.ToString();
[ConfigurationProperty("clusterName", DefaultValue = "serverlist")]
public string ClusterName => this["clusterName"]?.ToString();
/// <summary>
/// default timeout, unit is Milliseconds.
/// </summary>
[ConfigurationProperty("defaultTimeOut", DefaultValue = 15000)]
public int DefaultTimeOut => Convert.ToInt32(this["defaultTimeOut"]);
/// <summary>
/// accessKey
/// </summary>
[ConfigurationProperty("accessKey")]
public string AccessKey => this["accessKey"]?.ToString();
/// <summary>
/// secretKey
/// </summary>
[ConfigurationProperty("secretKey")]
public string SecretKey => this["secretKey"]?.ToString();
/// <summary>
/// useGrpc
/// </summary>
[ConfigurationProperty("useGrpc", DefaultValue = false)]
public bool UseGrpc => Convert.ToBoolean(this["useGrpc"]);
/// <summary>
/// username
/// </summary>
[ConfigurationProperty("userName", IsRequired = true)]
public string UserName => this["userName"]?.ToString();
/// <summary>
/// password
/// </summary>
[ConfigurationProperty("password", IsRequired = true)]
public string Password => this["password"]?.ToString();
public static NacosConfigurationSection GetConfig(string sectionName) => ConfigurationManager.GetSection(string.IsNullOrWhiteSpace(sectionName) ? "nacos" : sectionName) as NacosConfigurationSection;
}
}

9
src/Nacos.System.Configuration/README.md

@ -0,0 +1,9 @@
# [ConfigurationBuilder](https://github.com/aspnet/MicrosoftConfigurationBuilders#implementing-more-keyvalue-config-builders) of nacos
## NacosConfigurationBuilder property
* mode default value is Greedy
* nacosConfig default value is nacos
* more property please see [MicrosoftConfigurationBuilders](https://github.com/aspnet/MicrosoftConfigurationBuilders)
## sample
[ConfigurationBuilderApp](https://github.com/nacos-group/nacos-sdk-csharp/tree/dev/samples/ConfigurationBuilderApp/web.config)

2
src/Nacos/Nacos.csproj

@ -39,7 +39,7 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Google.Protobuf" Version="3.14.0" />
<PackageReference Include="Grpc.Core" Version="2.34.0" />
<PackageReference Include="Grpc.Core" Version="2.34.1" />
<!--<PackageReference Include="Grpc.Net.Client" Version="2.33.1" />-->
<!--<Protobuf Include="V2\protos\nacos_grpc_service.proto" GrpcServices="Client" />-->
<!--<PackageReference Include="Grpc.Tools" Version="2.36.1" PrivateAssets="All" />-->

Loading…
Cancel
Save