Compare commits

..

310 Commits
v0.8.5 ... dev

Author SHA1 Message Date
LiZhengHao 7afd0d2870
Fix UriTool to retrieve correct IP when preferredNetworks is null (#336) 2024-11-26 01:16:00 +00:00
catcherwong c02eca0a22 prepare v1.3.10
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-11-03 15:38:26 +00:00
LiZhengHao c26496ee89
preferredNetworks supports multiple prefixes and regular expressions (#331) 2024-10-29 05:59:15 +00:00
memoyu d2918c37e3
Upgrade System.Text.Json version to 8.0.5 (#332) 2024-10-26 15:24:03 +00:00
ZUOXIANGE 86ba5d878b
fix method name and comment (#323) 2024-09-23 10:40:04 +00:00
Catcher Wong ded6426c8c
Merge pull request #321 from nacos-group/naming-redo
align java sdk for naming redo
2024-09-21 14:12:51 +08:00
catcherwong 237bddc703 align java sdk for naming redo
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-09-21 06:08:48 +00:00
catcherwong a3a8022361 add package readme for Nacos.Microsoft.Extensions.ServiceDiscovery
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-09-20 15:24:14 +00:00
catcherwong d65d967e85 update workflow to support Nacos.Microsoft.Extensions.ServiceDiscovery
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-09-20 15:08:23 +00:00
ZUOXIANGE 60de3cb573
Microsoft.Extensions.ServiceDiscovery support (#317)
* Microsoft.Extensions.ServiceDiscovery  support

* comment fix

* comment fix
2024-09-20 02:54:42 +00:00
catcherwong 59b02d31a7 update version to 1.3.9
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-09-17 06:28:55 +00:00
Catcher Wong 4adf6d87fc
rm netcoreapp31 and some changes (#316)
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-09-17 06:24:21 +00:00
Catcher Wong 2f77ac59f2
replace ntjson with stjson (#315)
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-09-17 06:03:38 +00:00
Catcher Wong 85719ccffc
replace Grpc.Core with Grpc.Net.Client (#314)
* replace Grpc.Core with Grpc.Net.Client

Signed-off-by: catcherwong <catcher_hwq@outlook.com>

* update github action

Signed-off-by: catcherwong <catcher_hwq@outlook.com>

* fix java 8 setup

Signed-off-by: catcherwong <catcher_hwq@outlook.com>

---------

Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-09-17 05:38:45 +00:00
Catcher Wong cb9f1d16ce
TFM RM net5 and ADD net8 (#313)
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-08-23 00:54:43 +00:00
Catcher Wong 686e3bfdc8
Merge branch 'master' into dev 2024-08-20 10:06:20 +08:00
Catcher Wong 3ea0fdef46
update version to 1.3.8 (#311)
Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-08-20 02:00:45 +00:00
memoyu 5f14c1d7d4
fix:block under multiple listeners to re-listen #300 #306 #307 (#308) 2024-08-11 15:07:16 +00:00
memoyu e6cf34bbfe
upgrade deps packages #302 (#304) 2024-07-25 01:06:35 +00:00
Catcher Wong 185362b2af
Fix naming http signature (#297) (#298)
* fix namint http signature error



* update version to 1.3.7



---------

Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-07-11 02:09:28 +00:00
Catcher Wong c7a50c7764
Fix naming http signature (#297)
* fix namint http signature error

Signed-off-by: catcherwong <catcher_hwq@outlook.com>

* update version to 1.3.7

Signed-off-by: catcherwong <catcher_hwq@outlook.com>

---------

Signed-off-by: catcherwong <catcher_hwq@outlook.com>
2024-07-11 01:19:04 +00:00
Catcher Wong 42fb0b56cd
Merge pull request #294 from nacos-group/dev
release v1.3.6
2024-06-27 08:59:04 +08:00
Catcher Wong 4359f77eaa
Update version.props 2024-06-27 00:49:36 +00:00
memoyu d40db4ab61
fix: if the config key changes, re-listen (#293) 2024-06-26 00:36:20 +00:00
Memoyu 7664d2d36a
docs: update sample code #284 (#285) 2023-11-21 10:36:36 +00:00
Catcher Wong 81d54b2bbf
Merge pull request #247 from nacos-group/dev
release v1.3.5
2023-04-11 23:08:47 +08:00
Catcher Wong 290cc6d784
update version (#246)
* update version

* chore: back setup java
2023-04-11 23:02:29 +08:00
Lycoris 40afb63e45
修复使用ak,sk 连接nacos时,403验签失败问题 (#245) 2023-04-11 22:42:52 +08:00
Lycoris 27e92bd2c6
修复http模式下,生成签名问题 (#244) 2023-04-11 13:45:25 +08:00
inversionhourglass 9a700ad62e
Config support custom endpoint port. (#230)
Co-authored-by: taoye <taoye01@benlai.com>
2022-08-31 22:25:18 +08:00
Catcher Wong f12c66a3b2
Merge pull request #223 from nacos-group/dev
prepare v1.3.4
2022-08-10 22:03:19 +08:00
Catcher Wong 68df6f5351
Merge pull request #222 from nacos-group/update-action-and-docs
chore: update nacos version and docs
2022-08-10 09:44:16 +08:00
catcherwong a29ef5086e chore: update nacos version and docs 2022-08-10 07:59:33 +08:00
Catcher Wong ce3de526e1
Merge pull request #221 from nacos-group/iss-218
fix(aspnetcore): wrong ASPNETCORE_URLS lead to wrong ip
2022-08-07 14:38:58 +08:00
catcherwong 76463efd14 chore: unpass unit test for RegSvcBgTaskTests 2022-08-07 14:32:30 +08:00
catcherwong 22537b78b8 fix(aspnetcore): wrong ASPNETCORE_URLS lead to wrong ip 2022-08-07 14:17:42 +08:00
Catcher Wong 9597becbf4
Merge pull request #219 from nacos-group/OpenApi
Add some open api
2022-07-30 12:03:43 +08:00
catcherwong 30d9b1c2a4 feat(openapi): add query system metrics 2022-07-30 11:54:08 +08:00
Catcher Wong 8ebdb6b1cb
Merge pull request #215 from nacos-group/batchReg
feat(naming): add batchRegisterInstance
2022-07-13 22:24:59 +08:00
catcherwong 15994e4463 feat(naming): add batchRegisterInstance 2022-07-13 21:39:01 +08:00
catcherwong 4b11429f76 feat: add namespace operation in openapi 2022-07-06 23:11:23 +08:00
Catcher Wong cca6ba4921
Merge pull request #214 from nacos-group/dev
fix: NU5100 error when packing Nacos.System.Configuration
2022-07-03 10:15:45 +08:00
catcherwong f2d57d6640 fix: NU5100 error when packing Nacos.System.Configuration 2022-07-03 10:06:46 +08:00
Catcher Wong 7d67c1d8da
Merge pull request #213 from nacos-group/dev
update version to 1.3.4
2022-07-02 09:23:38 +08:00
catcherwong 31d4465e16 update version to 1.3.4 2022-07-02 09:05:45 +08:00
Catcher Wong 4e78c2d059
Merge pull request #212 from zlzforever/dev
upgrade deps packages
2022-07-02 00:02:48 +08:00
Lewis Zou 8184ce58e0 upgrade deps packages 2022-07-01 23:46:46 +08:00
Catcher Wong 1e995cdd76
Merge pull request #208 from nacos-group/dev
v1.3.3 release
2022-05-30 23:01:06 +08:00
catcherwong 66712bc22c docs: add v1.3.3 release note 2022-05-30 22:43:53 +08:00
Catcher Wong db995de99e
Merge pull request #207 from nacos-group/docs/package-readme-file
docs: package readme file
2022-05-30 22:01:36 +08:00
catcherwong 8c8e5879f7 docs: package readme file 2022-05-30 14:05:18 +08:00
Catcher Wong 17a7dadfa1
Merge pull request #206 from nacos-group/iss-205
feat: config cache from JM.SNAPSHOT.PATH at first (#205)
2022-05-29 23:51:40 +08:00
catcherwong b8cd831e97 feat: config cache from JM.SNAPSHOT.PATH at first (#205) 2022-05-29 23:34:03 +08:00
Catcher Wong e13041e8a3
Merge pull request #204 from nacos-group/update-ci-nacosversion
chore: update ci nacos version
2022-05-26 10:40:31 +08:00
Catcher Wong b728ca143d
Improve Microsoft.Extensions.Configuration Integration (#203)
* feat: INacosConfigService and ILoggerFactory from di

* test: add more ut for ms config

* feat: AddNacosV2Configuration parameter with useful things

* feat: add UseNacosConfig for hostbuilder extension

* style: remove some useless code and add some comments
2022-05-26 10:32:51 +08:00
catcherwong d88a74a6d4 chore: update ci nacos version 2022-05-25 23:07:40 +08:00
Catcher Wong 83eae087eb
Merge pull request #202 from nacos-group/dev
v1.3.3
2022-05-24 19:24:13 +08:00
Catcher Wong 28b66a6181
Merge pull request #201 from nacos-group/iss-200-startup-error
fix: ReceiveConfigInfo dict get item error in startup (#200)
2022-05-24 19:10:37 +08:00
catcherwong 4718fba1e2 fix: ReceiveConfigInfo dict get item error in startup (#200) 2022-05-24 17:02:02 +08:00
Catcher Wong 7936de782f
Merge pull request #197 from nacos-group/dev
fix IsSubscribed exception when NamingUseRpc is false
2022-04-09 09:32:06 +08:00
Catcher Wong 99575dde9d
Merge pull request #196 from nacos-group/iss-194
fix(naming): IsSubscribed exception when NamingUseRpc is false (#194)
2022-04-09 09:24:33 +08:00
catcherwong 671246e462 fix(naming): IsSubscribed exception when NamingUseRpc is false (#194) 2022-04-09 09:19:08 +08:00
Catcher Wong a5c22793ff
Merge pull request #193 from SpringHgui/patch-1
[fix] on empty config throw ArgumentNullException
2022-03-21 22:17:43 +08:00
Gui.H da0b20b68d
Update MyNacosConfigFilter.cs
[fix] on empty config throw ArgumentNullException
2022-03-21 20:07:26 +08:00
Catcher Wong 479c745ff3
Merge pull request #190 from nacos-group/dev
v1.3.2 release
2022-03-15 00:24:17 +08:00
catcherwong 4e4d50916a docs: release note 2022-03-15 00:18:38 +08:00
Catcher Wong 35280e75f6
Merge pull request #189 from nacos-group/iss-187
fix: naming with empty namespace
2022-03-15 00:08:45 +08:00
catcherwong 0c8dd5ff4b fix: naming with empty namespace 2022-03-15 00:01:16 +08:00
Catcher Wong 30b864a3de
Merge pull request #182 from nacos-group/dev
fix QueryInstancesOfService error cluster param
2022-02-12 09:38:33 +08:00
Catcher Wong 885682c23c
Merge pull request #181 from nacos-group/iss-180-http-clusters
fix: QueryInstancesOfService error cluster param (#180)
2022-02-12 09:29:20 +08:00
catcherwong ea7c120c68 fix: QueryInstancesOfService error cluster param (#180) 2022-02-11 12:18:19 +08:00
Catcher Wong 44f9574a03
Merge pull request #178 from nacos-group/dev
v1.3.1
2022-01-20 08:14:45 +08:00
Catcher Wong de6ef4d391
Merge pull request #177 from nacos-group/iss-176
fix: config parser thread safe issus
2022-01-17 14:13:32 +08:00
catcherwong e63fae29d2 fix: config parser thread safe issus (#176) 2022-01-17 14:07:59 +08:00
catcherwong 5ddf979222 up: Upgrading dependencies. 2022-01-15 11:26:11 +08:00
catcherwong fb6bf55f16 fix: timeout issue 2022-01-15 11:12:29 +08:00
catcherwong 92b3fd433e docs: update docs 2022-01-11 11:17:24 +08:00
catcherwong 011fac8a8b fix: add judgement for is subscribe services. 2022-01-05 18:04:25 +08:00
catcherwong e6d04e33e8 fix: service push when new data lastRefTime lessthan old data lastRefTime 2021-12-29 16:41:45 +08:00
Catcher Wong 4515a638ac
Merge pull request #173 from nacos-group/dev
fix pageSize error when send ServiceListRequest
2021-12-22 22:07:44 +08:00
catcherwong 71a51f7bf9 chore: version++ 2021-12-22 21:55:04 +08:00
catcherwong c3a3f240bd fix: ServiceListRequest pageSize error 2021-12-22 21:51:24 +08:00
Catcher Wong 49615063fd
Merge pull request #171 from nacos-group/dev
v1.3.0
2021-12-09 19:04:28 +08:00
catcherwong 1b17cb2199 docs: update docs and remove useless code 2021-11-28 21:59:03 +08:00
Catcher Wong 97ace972b4
Merge pull request #169 from nacos-group/updateproto
Update proto to remove RequestStream
2021-11-28 20:41:54 +08:00
catcherwong 24c995830f improve: update proto to remove RequestStream 2021-11-28 20:35:44 +08:00
catcherwong db474a5fe9 docs: update docs for the value of namespace 2021-11-21 10:33:41 +08:00
Catcher Wong afa9fa59bf
Merge pull request #167 from nacos-group/serverportoffset
Add nacos server port offset configuration from environment variable
2021-11-21 10:15:48 +08:00
catcherwong ce01d8de32 feat: Add nacos server port offset configuration from environment variable 2021-11-21 10:11:15 +08:00
catcherwong 48d737293f feat: update sample to net6 2021-11-14 12:17:35 +08:00
Catcher Wong 823b545846
Merge pull request #164 from nacos-group/net6
feat: support net6
2021-11-11 11:33:18 +08:00
catcherwong 52730fb1c9 feat: support net6 2021-11-11 11:01:40 +08:00
Catcher Wong d2d4febf53
Merge pull request #163 from nacos-group/dev
v1.2.2
2021-11-07 15:35:56 +08:00
catcherwong a4711f1aa6 feat: add doc 2021-11-07 15:27:45 +08:00
catcherwong 745f2b5acd improve: server push empty protection (#155) 2021-10-10 22:51:53 +08:00
Catcher Wong 4651250f94
Merge pull request #162 from liiujinfu/dev
add auto decompression, fix #161
2021-10-10 12:03:06 +08:00
liujinfu c5d4c234ef add auto decompression, fix #161 2021-10-09 12:02:13 +08:00
catcherwong 0d677827fe chore: fix typo 2021-10-09 11:03:44 +08:00
catcherwong 9b4b37d5c7 chore: relase parser packages (#160) 2021-10-09 10:53:16 +08:00
catcherwong 789cac0e94 docs: update index of readthedocs 2021-10-07 15:55:40 +08:00
catcherwong 005dab9df2 feat: version++ 2021-10-07 15:51:32 +08:00
Catcher Wong 89e51d563b
Merge pull request #159 from nacos-group/dev
fix pack
2021-10-07 15:39:50 +08:00
catcherwong 3e45767d05 fix: net471 pack 2021-10-07 15:36:39 +08:00
catcherwong 125046e38e docs: update 1.2.1 releasenote 2021-10-07 15:24:22 +08:00
Catcher Wong c810a88565
Merge pull request #158 from nacos-group/dev
v1.2.1 release
2021-10-07 15:21:03 +08:00
catcherwong 0727b82b1e docs: update 1.2.1 releasenote 2021-10-07 15:14:58 +08:00
catcherwong c6c899d73c docs: add 1.2.1 releasenote 2021-10-07 15:09:33 +08:00
Catcher Wong 9723f723a0
Merge pull request #157 from nacos-group/iss-154
fix: naming with http subscribe do not trigger OnEvent (#154)
2021-10-07 14:49:24 +08:00
catcherwong 247e288edc test: add ut for ServiceInfoHolder 2021-10-07 14:43:52 +08:00
catcherwong ba0125db98 fix: naming with http subscribe do not trigger OnEvent (#154) 2021-10-07 14:16:52 +08:00
catcherwong 6238b5ef98 docs: update documents 2021-09-20 11:34:51 +08:00
catcherwong f05841993a sample: remove old usages 2021-09-19 00:00:29 +08:00
Catcher Wong f3d3e9d6b7
Merge pull request #153 from nacos-group/iss-152
test: add ut for Nacos.Microsoft.Extensions.Configuration (#152)
2021-09-18 12:23:22 +08:00
catcherwong 8ea1258eb7 test: add ut for Nacos.Microsoft.Extensions.Configuration (#152) 2021-09-18 11:54:03 +08:00
Catcher Wong f8ffa08d19
Merge pull request #151 from DillonHuang/fix149
修改Issue:#149 Listeners中配置多个DataId时,更新DataId的内容后,配置项覆盖不正确
2021-09-18 08:24:09 +08:00
dillon fdab19de7b fix #149 2021-09-17 19:54:31 +08:00
Catcher Wong 1a0b5198d9
Merge pull request #148 from nacos-group/iss-146
Remove old v1 code and fix some known issues
2021-09-14 19:22:28 +08:00
catcherwong a1a9a99414 chore: remove dependency 2021-09-14 14:50:49 +08:00
catcherwong 7c46f5e455 fix: improve timeout issue 2021-09-14 09:20:00 +08:00
catcherwong ab51aa6fa7 chore: fix unstable ut for SecurityProxyTests 2021-09-14 08:37:42 +08:00
catcherwong d5da1d36c8 test: remove running judge 2021-09-13 19:16:24 +08:00
catcherwong e2727426eb perf: config cache and remove not required property 2021-09-13 19:00:10 +08:00
catcherwong b84018c906 fix: add timeout for RequestProxy 2021-09-12 21:41:04 +08:00
catcherwong fe6def7887 improve: add grpc.core 2021-09-12 14:21:30 +08:00
catcherwong 976ddad822 test: add more ut 2021-09-12 12:04:11 +08:00
catcherwong 0877b7dcc7 test: add some ut for RegSvcBgTask 2021-09-11 16:08:23 +08:00
catcherwong 3796e979ca test: add ut for UriTool 2021-09-11 15:11:08 +08:00
catcherwong 67080488dc chore: remove old v1 code (#146) 2021-09-11 14:49:10 +08:00
Catcher Wong 42101d308e
Merge pull request #145 from nacos-group/iss-144
Clean up and update ResolveServerInfo of RpcClient
2021-09-11 11:21:32 +08:00
catcherwong e9d13f224a improve: update ResolveServerInfo of RpcClient (#144) 2021-09-11 11:07:33 +08:00
catcherwong 767e879aec chore: update client version and remove clientip of ConnectionSetupRequest 2021-09-10 23:25:36 +08:00
Catcher Wong c1e4c284d7
Merge pull request #142 from nacos-group/dev
v1.2.0 release
2021-09-05 12:18:06 +08:00
catcherwong 833d78d6f1 docs: update documentation 2021-09-05 12:07:21 +08:00
Catcher Wong 3b0cf8b144
Merge pull request #141 from nacos-group/doc
feat: add doc (#140)
2021-09-04 13:19:22 +08:00
catcherwong 769dec41c4 feat: add doc (#140) 2021-09-04 13:17:52 +08:00
Catcher Wong 3c8337de2f
Merge pull request #139 from nacos-group/improve-rpcstatus
improve: make rpcstatus error message readable
2021-09-03 22:58:05 +08:00
catcherwong ea2f4a903f improve: make rpcstatus error message readable 2021-09-03 08:56:15 +08:00
Catcher Wong 4b14817538
Merge pull request #138 from nacos-group/iss-137
fix: request login interface too frequently (#137)
2021-09-02 20:43:35 +08:00
catcherwong a173055e28 fix: request login interface too frequently (#137) 2021-09-02 19:58:37 +08:00
Catcher Wong 1d8f543002
Merge pull request #132 from nacos-group/iss-131
fix: pass section for AddNacosV2Naming
2021-08-11 08:44:59 +08:00
catcherwong 14408a0e54 fix: pass section for AddNacosV2Naming (#131) 2021-08-11 08:26:30 +08:00
Catcher Wong 475beda62e
Update version.props 2021-08-09 08:28:04 +08:00
Catcher Wong d8d0813b99
Merge pull request #130 from nacos-group/dev
prepare v1.1.1
2021-08-08 10:27:06 +08:00
catcherwong f55688c70c fix conflict 2021-08-08 10:09:09 +08:00
catcherwong 576fd401b1 chore: update to nacos version to 2.0.2 2.0.3 2021-08-08 10:00:43 +08:00
catcherwong d42fed9448 fix: Don't create PushReceiver when using rpc 2021-08-08 09:56:19 +08:00
Catcher Wong e746010c16
improve: when naming not use grpc, do not create NamingGrpcClientProxy (#127) 2021-07-30 08:46:14 +08:00
Catcher Wong 3c6a63ebe3
Support some feature for v1.1.1 (#125)
* fixed issue (#119)

* Add redo feature for naming client (#122)

* feat: add redo feature for naming client

* fix: naming DoUnsubscribe param error.

* feat: impl failover reactor of naming (#123)

* improve: WeightRoundRobin (#121)

Co-authored-by: code-jar <ricarod_jar@outlook.com>
2021-07-25 11:25:16 +08:00
Catcher Wong 06d458497c
Merge pull request #124 from nacos-group/iss-121
improve WeightRoundRobin
2021-07-25 11:14:40 +08:00
catcherwong 4253b2d3a8 improve: WeightRoundRobin (#121) 2021-07-25 11:09:51 +08:00
Catcher Wong 0d04e5ef27
feat: impl failover reactor of naming (#123) 2021-07-25 11:01:26 +08:00
Catcher Wong 80bdd09212
Add redo feature for naming client (#122)
* feat: add redo feature for naming client

* fix: naming DoUnsubscribe param error.
2021-07-24 14:59:56 +08:00
Catcher Wong 8de447b67a
Merge pull request #120 from code-jar/dev
fixed issue (#119)
2021-06-28 19:55:39 +08:00
code-jar 9a91cf32a8 fixed issue (#119) 2021-06-26 14:55:16 +08:00
Catcher Wong ead5748e3c
Merge pull request #118 from nacos-group/dev
PublishConfig fail with some special content
2021-06-24 08:58:30 +08:00
catcherwong 92101ab9f7 docs: update version and add ut for (#116) 2021-06-24 08:53:17 +08:00
Catcher Wong 343f3191cb
Merge pull request #117 from StratosBlue/dev
make v2 ServerHttpAgent use the right way to request.
2021-06-24 08:40:37 +08:00
Stratos 306f283f9a make v2 ServerHttpAgent use the right way to request. 2021-06-22 15:13:34 +08:00
Catcher Wong c34b285f37
Delete issue-default-template.md 2021-06-19 09:57:45 +08:00
Catcher Wong 0fd198118f Update issue templates 2021-06-19 09:56:37 +08:00
Catcher Wong f21c576620
Merge pull request #112 from nacos-group/dev
log: add log for config rpc server request handler
2021-06-14 00:40:17 +08:00
catcherwong 7000290bd7 log: add log for config rpc server request handler 2021-06-14 00:24:12 +08:00
Catcher Wong 9577a69db6
Merge pull request #111 from nacos-group/dev
Update sample and readme
2021-06-13 22:03:40 +08:00
catcherwong eae5fe8f18 docs: update sample and readme 2021-06-13 21:55:52 +08:00
catcherwong 5c741f6a25 refactor: v2 configurationsource mark tenant obsolete, using namespace replace 2021-06-13 21:51:28 +08:00
Catcher Wong 3db7938b8c
Merge pull request #110 from nacos-group/dev
v1.1.0
2021-06-13 15:03:24 +08:00
catcherwong 87b3bde801 feat: enhance config filter integrate with msconfig 2021-06-13 14:32:40 +08:00
catcherwong 89dc598fd9 feat: Support config filter 2021-06-13 01:14:52 +08:00
catcherwong 2d7804bb51 chore: update to nacos version to 2.0.1 2.0.2 2021-06-12 12:26:28 +08:00
catcherwong 883b827817 docs: update readme 2021-06-12 12:20:43 +08:00
catcherwong fd0637e2f8 feat: adapte newest sdk 2021-06-12 12:09:45 +08:00
catcherwong 0fbd4f2943 Merge branch 'dev' of https://github.com/nacos-group/nacos-sdk-csharp into dev 2021-06-12 10:55:46 +08:00
catcherwong b179bb6779 feat: Support fetching server list from endpoint with namespace and constant export 2021-06-12 10:52:48 +08:00
catcherwong 7bc8e494fe Fix: Add/Remove cache before call server 2021-06-12 09:57:53 +08:00
catcherwong 322da0c477 feat: AddNacosAspNet support section of Configuration 2021-06-10 13:38:02 +08:00
catcherwong 6f5aeac7ab refactor: work with const value 2021-05-31 23:00:18 +08:00
catcherwong 03139a89a4 feat: remove set in connection event lister 2021-05-31 22:50:00 +08:00
catcherwong 255f6c01fc chore: ci split test proj 2021-05-18 11:53:18 +08:00
catcherwong 79fcba1df3 chore: test build and pack 2021-05-18 11:12:57 +08:00
catcherwong 1a024d5036 chore: test build Nacos.System.Configuration 2021-05-18 09:47:54 +08:00
彭伟 43cb177326
Add ConfigurationBuilder support (#105)
* Add .ConfigureAwait(false)

* Suppport ConfigurationBuilder

* Add Nacos support ConfigurationBuilder

* useGrpc
2021-05-18 08:26:22 +08:00
Catcher Wong 7fe688d62a
Merge pull request #104 from nacos-group/dev
fix some issue
2021-05-16 13:29:13 +08:00
Catcher Wong be746fec5d
Merge pull request #103 from pengweiqhca/callback
添加.ConfigureAwait(false)避免死锁
2021-05-16 10:10:57 +08:00
彭伟 d4f8937d87 Merge branch 'dev' of https://github.com/nacos-group/nacos-sdk-csharp into callback 2021-05-16 10:03:58 +08:00
彭伟 064dc34ffd Merge branch 'callback' of https://github.com/pengweiqhca/nacos-sdk-csharp-1 into callback
# Conflicts:
#	src/Nacos.Microsoft.Extensions.Configuration/Impl/MsConfigServerHttpAgent.cs
#	src/Nacos/Config/AbstNacosConfigClient.cs
#	src/Nacos/Config/Http/HttpAgent.cs
#	src/Nacos/Config/Http/ServerHttpAgent.cs
2021-05-16 10:03:53 +08:00
Catcher Wong c54f39a111
Merge pull request #102 from pengweiqhca/callback
修复#98
2021-05-16 10:03:32 +08:00
彭伟 de06988f9c Merge branch 'ca' into callback
# Conflicts:
#	src/Nacos.Microsoft.Extensions.Configuration/Impl/MsConfigServerHttpAgent.cs
#	src/Nacos/Config/AbstNacosConfigClient.cs
#	src/Nacos/Config/Http/HttpAgent.cs
#	src/Nacos/Config/Http/ServerHttpAgent.cs
2021-05-16 10:02:23 +08:00
Catcher Wong dc891d2d2e
Merge branch 'dev' into callback 2021-05-16 09:54:04 +08:00
Catcher Wong 46c1a9cc0f
Merge pull request #101 from pengweiqhca/ca
添加.ConfigureAwait(false)避免死锁
2021-05-16 09:45:26 +08:00
彭伟 065f3e5008 Merge branch 'Branch_b0227fa1' into ca
# Conflicts:
#	src/Nacos.Microsoft.Extensions.Configuration/Impl/MsConfigServerHttpAgent.cs
#	src/Nacos/Config/AbstNacosConfigClient.cs
#	src/Nacos/Config/Failover/FileLocalConfigInfoProcessor.cs
#	src/Nacos/Config/ServerListManager.cs
#	src/Nacos/Naming/Cache/DiskCache.cs
#	src/Nacos/Naming/Cache/FailoverReactor.cs
#	src/Nacos/Security/SecurityProxy.cs
2021-05-15 23:32:27 +08:00
彭伟 18038641a3 添加.ConfigureAwait(false)避免死锁 2021-05-15 23:27:29 +08:00
彭伟 59883ff2d2 添加.ConfigureAwait(false)避免死锁 2021-05-15 23:18:59 +08:00
彭伟 571a1c4751 Merge branch 'v1' into dev
# Conflicts:
#	src/Nacos.Microsoft.Extensions.Configuration/Impl/MsConfigServerHttpAgent.cs
#	src/Nacos/Config/AbstNacosConfigClient.cs
2021-05-15 23:01:35 +08:00
彭伟 052ef1f983 修复[#98](https://github.com/nacos-group/nacos-sdk-csharp/issues/98) 2021-05-15 22:54:35 +08:00
catcherwong 41aa4ebd6e Merge branch 'dev' of https://github.com/nacos-group/nacos-sdk-csharp into dev 2021-05-14 17:55:49 +08:00
catcherwong f12a803be2 fix: services.AddNacosAspNet with action mode 2021-05-14 15:05:26 +08:00
catcherwong 23474cd85d feat: encrypt data key failover 2021-05-13 22:44:29 +08:00
catcherwong f7966b8e3c fix: dict safe get value 2021-05-13 08:31:06 +08:00
catcherwong 1b59329eea fix: KeyNotFoundException 2021-05-12 23:27:22 +08:00
catcherwong a45ea2743b Merge branch 'dev' of https://github.com/nacos-group/nacos-sdk-csharp into dev 2021-05-12 23:00:13 +08:00
catcherwong a679f22ca1 feat: config support cas md5 and encrypted data key 2021-05-12 22:53:47 +08:00
catcherwong ceb7fd8fca refactor:udp port can read from env 2021-05-11 20:18:37 +08:00
catcherwong b84a578a4d chore: update to nacos version 2021-05-02 07:23:48 +08:00
catcherwong 0d25013320 feat: support naming push empty protection 2021-05-02 07:16:32 +08:00
Catcher Wong 3a01d9453f
Merge pull request #94 from nacos-group/dev
fix naming update task error
2021-04-26 20:06:58 +08:00
catcherwong c987e29dc1 fix: naming update task error 2021-04-26 19:52:28 +08:00
catcherwong faffd2dfa2 log: naming grpc connection event listener add log 2021-04-26 15:49:15 +08:00
catcherwong 5a43d9a0ee config: update next version to 1.1.0 2021-04-18 13:46:50 +08:00
Catcher Wong 5229ef7420
Merge pull request #91 from nacos-group/dev
improve logging of Nacos.Microsoft.Extensions.Configuration
2021-04-18 12:05:02 +08:00
catcherwong 3f5d16fc68 feat: improve logging of Nacos.Microsoft.Extensions.Configuration 2021-04-18 11:39:11 +08:00
Catcher Wong 8c1ebb2106
Merge pull request #89 from nacos-group/dev
fix some known issues
2021-04-17 23:06:34 +08:00
catcherwong 83b1d3cc92 fix: nacos logger factory 2021-04-17 22:59:09 +08:00
catcherwong ffc8671c4e fix: ci build 2021-04-17 22:55:26 +08:00
catcherwong 92d77296ad feat: msconfig add console log 2021-04-17 22:51:43 +08:00
catcherwong 25383573d7 feat: sync proto file and update netutils 2021-04-17 11:40:14 +08:00
catcherwong 20cff75deb chore: try to fix windows ci 2021-04-11 15:08:12 +08:00
catcherwong cd023ae268 chore: update to nacos 2.0.0 bugfix 2021-04-11 14:52:12 +08:00
catcherwong 5fe1c7cb0b feat: update serviceinfoupdateservice 2021-04-11 14:47:44 +08:00
catcherwong fa90cff459 feat: publish config support type 2021-04-11 14:02:36 +08:00
catcherwong ab33cc5027 feat: naming http record response body when status not eq 200 2021-03-27 11:49:06 +08:00
黄文清 6ae555fd45 fix: refresh server list log 2021-03-24 20:46:27 +08:00
Catcher Wong 76cee61f37
Merge pull request #83 from nacos-group/dev
Try to adapt cloud usage
2021-03-23 17:57:33 +08:00
黄文清 a8f9a8b6b3 fix: try to adapt SAE 2021-03-23 17:22:44 +08:00
黄文清 c0aff448cc fix: http acm return 403 2021-03-23 17:09:00 +08:00
黄文清 4ac6ac3012 feat: done some todo list 2021-03-23 14:55:16 +08:00
Catcher Wong 2247c6c3d1
Merge pull request #82 from nacos-group/dev
fix: Grpc request bi stream,payload parse error
2021-03-21 14:26:25 +08:00
catcherwong a49445c590 fix: Grpc request bi stream,payload parse error 2021-03-21 13:07:37 +08:00
Catcher Wong e503ad7339
Merge pull request #81 from nacos-group/dev
Release v1.0.1
2021-03-20 22:30:19 +08:00
catcherwong 4de9106bd5 chore: ci stable 1.x 2021-03-20 22:20:47 +08:00
catcherwong a653b1f86f test: update test and auth 2021-03-20 22:16:17 +08:00
catcherwong f9d0bc7b91 fix: naming request exception logging message 2021-03-20 10:48:53 +08:00
catcherwong 79a333d15d fix: login url can not convert to Uri 2021-03-20 10:41:40 +08:00
catcherwong 5cb64c8b2b Merge branch 'dev' of https://github.com/nacos-group/nacos-sdk-csharp into dev 2021-03-20 10:09:43 +08:00
catcherwong 381923d2bc chore: update nacos server version 2021-03-20 10:09:05 +08:00
黄文清 a8bbb06a18 feat: update logger 2021-03-17 19:04:56 +08:00
catcherwong 9aab8b73a1 1. HashUtil using v2
2. Add comments
2021-03-11 08:47:29 +08:00
catcherwong 7878abdee6 1. config add sign headers
2. connection setup request add client id
3. update config query response
2021-03-10 19:19:04 +08:00
catcherwong d3cb08bede remove useless code 2021-03-05 19:58:34 +08:00
catcherwong 7114bf70e3 keep config and naming using diff channel 2021-03-05 12:19:49 +08:00
catcherwong e185ded3ff update proto and version 2021-03-04 20:26:24 +08:00
Catcher Wong 1645598807
Merge pull request #76 from nacos-group/dev
fixed metadata bug
2021-03-02 19:53:18 +08:00
catcherwong fcaed9b3d9 fixed metadata error of naming (#75) 2021-03-02 17:54:30 +08:00
catcherwong 0958f5c256 Make Nacos.AspNetCore some class Obsolete 2021-03-01 09:06:19 +08:00
catcherwong 24d014636a update sample for GetServerAsync 2021-02-23 08:36:29 +08:00
Catcher Wong 8403178eef
Merge pull request #73 from nacos-group/dev
Intergrate ASP.NET Core
2021-02-21 16:06:23 +08:00
catcherwong ca23dc6e24 update docs 2021-02-21 15:59:26 +08:00
catcherwong 7d6ae0d7c0 Integrate ASP.NET Core Discovery 2021-02-21 14:54:07 +08:00
catcherwong 9fab0c0d78 Integrate ASP.NET Core support RemoveListener 2021-02-21 11:08:51 +08:00
catcherwong 8fb626037f update version to 1.0.0 2021-02-20 20:10:24 +08:00
Catcher Wong 720dc56a1b
Merge pull request #72 from nacos-group/dev
for nacos 2.0
2021-02-20 20:07:24 +08:00
catcherwong aae905af88 adjust naming timeout 2021-02-20 20:00:47 +08:00
catcherwong 722939a7e4 adjust config timeout 2021-02-20 19:50:02 +08:00
catcherwong f916567c7b remove unofficial 2021-02-20 18:40:59 +08:00
catcherwong b5b5f3add7 v2 config init security proxy 2021-02-20 18:38:24 +08:00
catcherwong 08bc243f92 config request add common headers 2021-02-06 16:12:26 +08:00
catcherwong edb9915e3e 1. update serviceinfoupdateservice
2. namingpushresponsehandler -> namingpushrequesthandler
2021-02-06 13:45:42 +08:00
catcherwong 36cc51df3b naming grpc support auth 2021-02-06 12:34:03 +08:00
Catcher Wong 0a96a30ea1
update nacos server to 2.0.0-BETA 2021-02-05 19:31:14 +08:00
catcherwong 467b22c0d8 config getlabel add appname 2021-02-04 18:25:33 +08:00
catcherwong 4914f46cfb 1. rpcclient support connection reset
2. rpcclient support client detection
3. rpcclient support health check
4. rpcclient support error response
5. adjust grpcutils parse method
2021-02-04 18:24:20 +08:00
catcherwong 268bf9e4b1 adapt the newest nacos 2.0 2021-01-31 22:23:24 +08:00
catcherwong 45c04c7e20 fixed file content length (#69) 2021-01-30 10:05:13 +08:00
catcherwong 122a33bbba update default timeout 2021-01-24 14:52:07 +08:00
catcherwong 8dc451a86d adjust unit test 2021-01-24 14:22:49 +08:00
catcherwong 07115aa19e nacos server from ALPHA2 to ALPHA1 2021-01-24 00:40:52 +08:00
catcherwong ab77d78d3b 1. work for RpcConnectionEventListener
2. down ALPHA2 to ALPHA1
2021-01-24 00:37:57 +08:00
catcherwong d489b77f47 add some tests for v2 2021-01-23 11:50:06 +08:00
catcherwong 0b77b91920 Improve using HttpClient (#64) 2021-01-23 11:01:24 +08:00
catcherwong e51eb33548 fixed lb strategy when instanceid is null (#67) 2021-01-23 10:37:25 +08:00
catcherwong defd9b9714 add test 2021-01-17 16:53:16 +08:00
catcherwong da1fab9c6a update github action 2021-01-17 15:48:55 +08:00
catcherwong ca7f7b847a 1. update remote connection type
2. update utils methods
2021-01-17 14:11:48 +08:00
catcherwong 02c8464b83 1. fix typo ConfigPubishResponse -> ConfigPublishResponse
2. simplify rpcclientstatus
3. support reconnect
2021-01-16 17:11:18 +08:00
catcherwong 405ab36245 wip naming udp 2021-01-16 14:16:17 +08:00
catcherwong 2e455b374d adjust struct 2021-01-10 22:03:57 +08:00
catcherwong 963210fef2 config integration with asp.net core 2021-01-10 20:47:58 +08:00
catcherwong 45bd0d1147 config work for both http and rpc 2021-01-10 15:45:02 +08:00
catcherwong 94e677878f 1. done rpc config listener
2. wip http config listener
2021-01-09 15:08:48 +08:00
catcherwong a07b3a4da7 1. modify config sample
2. fixed bug for publish config
2021-01-09 12:00:04 +08:00
catcherwong 2468c63f5c config v2 add get signheaders 2021-01-09 11:23:19 +08:00
catcherwong 2dbd1cb507 1. add use rpc config
2. fixed null logger
2021-01-09 00:03:18 +08:00
catcherwong 55d510d96e move Null2DefaultGroup to ParamUtils 2021-01-08 23:47:01 +08:00
catcherwong 2352591745 merge 2021-01-08 23:40:08 +08:00
catcherwong 5259882f52 wip config http + rpc 2021-01-07 20:07:33 +08:00
catcherwong 6f46af798e wip ConfigTransportClient 2021-01-07 00:36:48 +08:00
catcherwong 3264415b6a Merge branch 'dev' of https://github.com/nacos-group/nacos-sdk-csharp into dev 2021-01-06 20:44:28 +08:00
catcherwong b6eb8d63a3 wip client worker 2021-01-06 20:43:07 +08:00
catcherwong 87abbe7810 work for config v2 2021-01-06 09:08:38 +08:00
catcherwong e7a9a45ec0 update naming with aspnet 2021-01-06 00:10:00 +08:00
catcherwong 869b7ca098 fixed some naming bugs and update samples 2021-01-05 00:06:05 +08:00
catcherwong 09dc81ae75 remove useless code 2021-01-04 11:44:26 +08:00
catcherwong daee05c366 wip naming feat 2021-01-04 11:30:56 +08:00
catcherwong c1f02c2caf fix svcinfoholder bug and add some tostring 2021-01-04 00:00:14 +08:00
catcherwong d4ff4f73a9 wip naming 2021-01-03 16:47:09 +08:00
catcherwong b60c96935d merge old v2 2021-01-03 14:10:21 +08:00
catcherwong 0f97beedaf rm old v2 folder 2021-01-03 01:18:42 +08:00
catcherwong 6fde515fa3 check gitignore 2021-01-02 18:42:56 +08:00
catcherwong f2f6b029ac [wip] real v2 for sdk 2021-01-02 18:38:40 +08:00
catcherwong 6ea6e0399d wip naming 2021-01-02 00:30:22 +08:00
catcherwong 5081329e63 1. config localcache
2. nacos exception
2021-01-01 22:13:39 +08:00
catcherwong 2980ffe2ac wip rpcclient for config 2021-01-01 18:10:24 +08:00
catcherwong 95a19809f8 rpcclient 2021-01-01 14:43:51 +08:00
catcherwong 9a34d827ec config notify with bistream request 2020-12-27 15:12:45 +08:00
catcherwong d56b544430 config listen/unlisten 2020-12-22 20:19:00 +08:00
catcherwong b00d9b28b2 add JsonProperty for ConfigBatchListenRequest 2020-12-21 22:32:34 +08:00
catcherwong 4044d206af netstandard2.1 -> netstandard2.0 2020-12-21 21:48:29 +08:00
catcherwong ba597627a0 [wip] config and rpc client 2020-12-18 20:12:28 +08:00
catcherwong e587aaaa4e [wip] v2 config 2020-12-18 18:09:40 +08:00
catcherwong 8b7eb08e88 wip config crd rpc impl 2020-12-14 22:37:26 +08:00
catcherwong f16eb66cf7 wip support grpc 2020-12-13 23:13:30 +08:00
393 changed files with 19122 additions and 7968 deletions

49
.editorconfig Normal file
View File

@ -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

View File

@ -0,0 +1,40 @@
---
name: nacos-sdk-csharp template
about: Issue Description
title: ''
labels: ''
assignees: ''
---
## Describe what happened (or what feature you want)
A clear and concise description of what happened or what you want.
## Describe what you expected to happen
A clear and concise description of what you expected to happen.
## How to reproduce it (as minimally and precisely as possible)
## Related code
```JSON
{
}
```
```csharp
services.Addxxxxx
builder.Addxxxx
```
## Tell us your environment
- nacos-sdk-csharp version: [e.g. 1.1.0/...]
- modular : [e.g. naming/config/msconfig/....]
- nacos server version: [e.g. 2.0.0/....]
- how to host nacos server : [e.g. docker/k8s/mse/virtual machine/...]
## Anything else we need to know?

View File

@ -1,29 +0,0 @@
name: Build
on: [pull_request]
jobs:
windows:
name: build on windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Build with dotnet
run: dotnet build --configuration Release
linux:
name: build on linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Build with dotnet
run: dotnet build --configuration Release

83
.github/workflows/build_Stable_1x.yml vendored Normal file
View File

@ -0,0 +1,83 @@
name: Build_With_Stable_1x
on:
push:
branches: [ dev, master ]
pull_request:
branches: [ dev, master ]
jobs:
windows:
name: build on windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x
- name: Build with dotnet
run: |
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src\Nacos\Nacos.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src\Nacos.AspNetCore\Nacos.AspNetCore.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src\Nacos.Microsoft.Extensions.Configuration\Nacos.Microsoft.Extensions.Configuration.csproj
dotnet msbuild -p:Configuration=Release -p:RestoreSources=https://api.nuget.org/v3/index.json -r -t:Build src\Nacos.System.Configuration\Nacos.System.Configuration.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests\Nacos.AspNetCore.Tests\Nacos.AspNetCore.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests\Nacos.Microsoft.Extensions.Configuration.Tests\Nacos.Microsoft.Extensions.Configuration.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests\Nacos.Tests\Nacos.Tests.csproj
linux:
name: build on linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x
- name: Setup up JDK 1.8
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 8
- name: Show dotnet Version
run: dotnet --version
- name: Show java Version
run: java -version
- name: Setup Stable 1.x Nacos Server
run: |
wget https://github.com/alibaba/nacos/releases/download/1.4.4/nacos-server-1.4.4.tar.gz
tar -xvf nacos-server-1.4.4.tar.gz
cd nacos/bin
# sed -i 's/nacos.core.auth.enabled=false/nacos.core.auth.enabled=true/g' ../conf/application.properties
chmod 755 startup.sh
nohup ./startup.sh -m standalone 2>&1 &
sleep 30
curl "127.0.0.1:8848/nacos/v1/ns/operator/metrics"
- name: Build with dotnet
run: |
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos/Nacos.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.AspNetCore/Nacos.AspNetCore.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.Microsoft.Extensions.Configuration/Nacos.Microsoft.Extensions.Configuration.csproj
dotnet msbuild -p:Configuration=Release -p:RestoreSources=https://api.nuget.org/v3/index.json -r -t:Build src/Nacos.System.Configuration/Nacos.System.Configuration.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.AspNetCore.Tests/Nacos.AspNetCore.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.Microsoft.Extensions.Configuration.Tests/Nacos.Microsoft.Extensions.Configuration.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.Tests/Nacos.Tests.csproj
- name: Test with dotnet
run: |
dotnet test tests/Nacos.AspNetCore.Tests/Nacos.AspNetCore.Tests.csproj --filter "Category=all|Category=1x" --no-restore
dotnet test tests/Nacos.Microsoft.Extensions.Configuration.Tests/Nacos.Microsoft.Extensions.Configuration.Tests.csproj --filter "Category=all|Category=1x" --no-restore
dotnet test tests/Nacos.Tests/Nacos.Tests.csproj --filter "Category=all|Category=1x" --no-restore
- name: Upload Nacos logs
if: always()
uses: actions/upload-artifact@v3
with:
name: nacos-logs
path: /home/runner/work/nacos-sdk-csharp/nacos-sdk-csharp/nacos/logs

83
.github/workflows/build_Stable_2x.yml vendored Normal file
View File

@ -0,0 +1,83 @@
name: Build_With_Stable_2x
on:
push:
branches: [ dev, master ]
pull_request:
branches: [ dev, master ]
jobs:
windows:
name: build on windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x
- name: Build with dotnet
run: |
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src\Nacos\Nacos.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src\Nacos.AspNetCore\Nacos.AspNetCore.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src\Nacos.Microsoft.Extensions.Configuration\Nacos.Microsoft.Extensions.Configuration.csproj
dotnet msbuild -p:Configuration=Release -p:RestoreSources=https://api.nuget.org/v3/index.json -r -t:Build src\Nacos.System.Configuration\Nacos.System.Configuration.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests\Nacos.AspNetCore.Tests\Nacos.AspNetCore.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests\Nacos.Microsoft.Extensions.Configuration.Tests\Nacos.Microsoft.Extensions.Configuration.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests\Nacos.Tests\Nacos.Tests.csproj
linux:
name: build on linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x
- name: Setup up JDK 1.8
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 8
- name: Show dotnet Version
run: dotnet --version
- name: Show java Version
run: java -version
- name: Setup Stable 2.x Nacos Server
run: |
wget https://github.com/alibaba/nacos/releases/download/2.1.0/nacos-server-2.1.0.tar.gz
tar -xvf nacos-server-2.1.0.tar.gz
cd nacos/bin
# sed -i 's/nacos.core.auth.enabled=false/nacos.core.auth.enabled=true/g' ../conf/application.properties
chmod 755 startup.sh
nohup ./startup.sh -m standalone 2>&1 &
sleep 30
curl "127.0.0.1:8848/nacos/v1/ns/operator/metrics"
- name: Build with dotnet
run: |
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos/Nacos.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.AspNetCore/Nacos.AspNetCore.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.Microsoft.Extensions.Configuration/Nacos.Microsoft.Extensions.Configuration.csproj
dotnet msbuild -p:Configuration=Release -p:RestoreSources=https://api.nuget.org/v3/index.json -r -t:Build src/Nacos.System.Configuration/Nacos.System.Configuration.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.AspNetCore.Tests/Nacos.AspNetCore.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.Microsoft.Extensions.Configuration.Tests/Nacos.Microsoft.Extensions.Configuration.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.Tests/Nacos.Tests.csproj
- name: Test with dotnet
run: |
dotnet test tests/Nacos.AspNetCore.Tests/Nacos.AspNetCore.Tests.csproj --filter "Category=all|Category=1x|Category=2x" --no-restore
dotnet test tests/Nacos.Microsoft.Extensions.Configuration.Tests/Nacos.Microsoft.Extensions.Configuration.Tests.csproj --filter "Category=all|Category=1x|Category=2x" --no-restore
dotnet test tests/Nacos.Tests/Nacos.Tests.csproj --filter "Category=all|Category=1x|Category=2x" --no-restore
- name: Upload Nacos logs
if: always()
uses: actions/upload-artifact@v3
with:
name: nacos-logs
path: /home/runner/work/nacos-sdk-csharp/nacos-sdk-csharp/nacos/logs

65
.github/workflows/build_Unstable.yml vendored Normal file
View File

@ -0,0 +1,65 @@
name: Build_With_Unstable
on:
push:
branches: [ dev, master ]
pull_request:
branches: [ dev, master ]
jobs:
linux:
name: build on linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x
- name: Setup up JDK 1.8
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 8
- name: Show dotnet Version
run: dotnet --version
- name: Show java Version
run: java -version
- name: Setup Unstable Nacos Server
run: |
wget https://github.com/alibaba/nacos/releases/download/2.1.1/nacos-server-2.1.1.tar.gz
tar -xvf nacos-server-2.1.1.tar.gz
cd nacos/bin
# sed -i 's/nacos.core.auth.enabled=false/nacos.core.auth.enabled=true/g' ../conf/application.properties
sed -i 's/Xms512m/Xms1024m/g' startup.sh
sed -i 's/Xmx512m/Xmx1024m/g' startup.sh
sed -i 's/Xmn256m/Xmn512m/g' startup.sh
chmod 755 startup.sh
nohup ./startup.sh -m standalone 2>&1 &
sleep 30
curl "127.0.0.1:8848/nacos/v1/ns/operator/metrics"
- name: Build with dotnet
run: |
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos/Nacos.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.AspNetCore/Nacos.AspNetCore.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.Microsoft.Extensions.Configuration/Nacos.Microsoft.Extensions.Configuration.csproj
dotnet msbuild -p:Configuration=Release -p:RestoreSources=https://api.nuget.org/v3/index.json -r -t:Build src/Nacos.System.Configuration/Nacos.System.Configuration.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.AspNetCore.Tests/Nacos.AspNetCore.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.Microsoft.Extensions.Configuration.Tests/Nacos.Microsoft.Extensions.Configuration.Tests.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json tests/Nacos.Tests/Nacos.Tests.csproj
- name: Test with dotnet
run: |
dotnet test tests/Nacos.AspNetCore.Tests/Nacos.AspNetCore.Tests.csproj --filter "Category=all|Category=1x|Category=2x" --no-restore
dotnet test tests/Nacos.Microsoft.Extensions.Configuration.Tests/Nacos.Microsoft.Extensions.Configuration.Tests.csproj --filter "Category=all|Category=1x|Category=2x" --no-restore
dotnet test tests/Nacos.Tests/Nacos.Tests.csproj --filter "Category=all|Category=1x|Category=2x" --no-restore
- name: Upload Nacos logs
if: always()
uses: actions/upload-artifact@v3
with:
name: nacos-logs
path: /home/runner/work/nacos-sdk-csharp/nacos-sdk-csharp/nacos/logs

View File

@ -1,4 +1,4 @@
name: Release
name: Release_Unstable
on:
push:
@ -11,17 +11,35 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v4
with:
dotnet-version: 5.0.x
dotnet-version: |
8.0.x
7.0.x
6.0.x
- name: Build with dotnet
run: dotnet build --configuration Release
run: |
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos/Nacos.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.AspNetCore/Nacos.AspNetCore.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.Microsoft.Extensions.ServiceDiscovery/Nacos.Microsoft.Extensions.ServiceDiscovery.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.Microsoft.Extensions.Configuration/Nacos.Microsoft.Extensions.Configuration.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json parsers/Nacos.IniParser/Nacos.IniParser.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json parsers/Nacos.YamlParser/Nacos.YamlParser.csproj
dotnet msbuild -p:Configuration=Release -p:RestoreSources=https://api.nuget.org/v3/index.json -r -t:Build src/Nacos.System.Configuration/Nacos.System.Configuration.csproj
- name: Pack with dotnet
run: dotnet pack /home/runner/work/nacos-sdk-csharp/nacos-sdk-csharp/nacos-sdk-csharp.sln --version-suffix alpha`date +%Y%m%d%H%M%S` -o /home/runner/work/nugetpkgs -c Release --no-build
run: |
ver=alpha`date +%Y%m%d%H%M%S`
dotnet pack src/Nacos/Nacos.csproj --version-suffix $ver -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack src/Nacos.AspNetCore/Nacos.AspNetCore.csproj --version-suffix $ver -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack src/Nacos.Microsoft.Extensions.ServiceDiscovery/Nacos.Microsoft.Extensions.ServiceDiscovery.csproj --version-suffix $ver -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack src/Nacos.Microsoft.Extensions.Configuration/Nacos.Microsoft.Extensions.Configuration.csproj --version-suffix $ver -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack parsers/Nacos.IniParser/Nacos.IniParser.csproj --version-suffix $ver -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack parsers/Nacos.YamlParser/Nacos.YamlParser.csproj --version-suffix $ver -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet msbuild -p:Configuration=Release -t:pack -p:PackageOutputPath=/home/runner/work/nugetpkgs -p:VersionSuffix=$ver src/Nacos.System.Configuration/Nacos.System.Configuration.csproj
- name: Upload artifact
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v3
with:
name: nugetpkgs
path: /home/runner/work/nugetpkgs
@ -33,9 +51,10 @@ jobs:
steps:
- name: Download build artifacts
uses: actions/download-artifact@v1
uses: actions/download-artifact@v3
with:
name: nugetpkgs
path: nugetpkgs
- name: list nugetpkgs
run: ls nugetpkgs
- name: Release

View File

@ -11,17 +11,34 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v4
with:
dotnet-version: 5.0.x
dotnet-version: |
8.0.x
7.0.x
6.0.x
- name: Build with dotnet
run: dotnet build --configuration Release
run: |
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos/Nacos.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.AspNetCore/Nacos.AspNetCore.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.Microsoft.Extensions.ServiceDiscovery/Nacos.Microsoft.Extensions.ServiceDiscovery.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json src/Nacos.Microsoft.Extensions.Configuration/Nacos.Microsoft.Extensions.Configuration.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json parsers/Nacos.IniParser/Nacos.IniParser.csproj
dotnet build --configuration Release --source https://api.nuget.org/v3/index.json parsers/Nacos.YamlParser/Nacos.YamlParser.csproj
dotnet msbuild -p:Configuration=Release -p:RestoreSources=https://api.nuget.org/v3/index.json -r -t:Build src/Nacos.System.Configuration/Nacos.System.Configuration.csproj
- name: Pack with dotnet
run: dotnet pack /home/runner/work/nacos-sdk-csharp/nacos-sdk-csharp/nacos-sdk-csharp.sln -o /home/runner/work/nugetpkgs -c Release --no-build
run: |
dotnet pack src/Nacos/Nacos.csproj -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack src/Nacos.AspNetCore/Nacos.AspNetCore.csproj -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack src/Nacos.Microsoft.Extensions.ServiceDiscovery/Nacos.Microsoft.Extensions.ServiceDiscovery.csproj -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack src/Nacos.Microsoft.Extensions.Configuration/Nacos.Microsoft.Extensions.Configuration.csproj -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack parsers/Nacos.IniParser/Nacos.IniParser.csproj -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet pack parsers/Nacos.YamlParser/Nacos.YamlParser.csproj -o /home/runner/work/nugetpkgs -c Release --no-build
dotnet msbuild -p:Configuration=Release -t:pack -p:PackageOutputPath=/home/runner/work/nugetpkgs src/Nacos.System.Configuration/Nacos.System.Configuration.csproj
- name: Upload artifact
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v3
with:
name: nugetpkgs
path: /home/runner/work/nugetpkgs
@ -33,9 +50,10 @@ jobs:
steps:
- name: Download build artifacts
uses: actions/download-artifact@v1
uses: actions/download-artifact@v3
with:
name: nugetpkgs
path: nugetpkgs
- name: list nugetpkgs
run: ls nugetpkgs
- name: Release

9
.gitignore vendored
View File

@ -236,7 +236,7 @@ Generated_Code/
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
# Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
@ -330,4 +330,9 @@ ASALocalRun/
.mfractor/
# Mac OS
.DS_Store
.DS_Store
# Read the docstates
_build/
_static/
_templates/

View File

@ -1,20 +1,22 @@
<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="StyleCop.Analyzers" Version="1.2.0-beta.164">
<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.376">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
</Project>

102
README.md
View File

@ -1,8 +1,8 @@
# nacos-sdk-csharp             [中文](./README.zh-cn.md)
# nacos-sdk-csharp             [中文](./README.zh-cn.md)
csharp(dotnet core) implementation of [nacos](https://nacos.io/) OpenAPI.
![Build](https://github.com/nacos-group/nacos-sdk-csharp/workflows/Build/badge.svg) ![Release](https://github.com/nacos-group/nacos-sdk-csharp/workflows/Release/badge.svg) ![](https://img.shields.io/nuget/v/nacos-sdk-csharp-unofficial.svg) ![](https://img.shields.io/nuget/vpre/nacos-sdk-csharp-unofficial.svg) ![](https://img.shields.io/nuget/dt/nacos-sdk-csharp-unofficial) ![](https://img.shields.io/github/license/nacos-group/nacos-sdk-csharp)
![Build](https://github.com/nacos-group/nacos-sdk-csharp/workflows/Build/badge.svg) ![Release](https://github.com/nacos-group/nacos-sdk-csharp/workflows/Release/badge.svg) ![](https://img.shields.io/nuget/v/nacos-sdk-csharp.svg) ![](https://img.shields.io/nuget/vpre/nacos-sdk-csharp.svg) ![](https://img.shields.io/nuget/dt/nacos-sdk-csharp) ![](https://img.shields.io/github/license/nacos-group/nacos-sdk-csharp)
![](./media/prj.png)
@ -11,21 +11,27 @@ csharp(dotnet core) implementation of [nacos](https://nacos.io/) OpenAPI.
Choose a package that you need.
```bash
dotnet add package nacos-sdk-csharp-unofficial
dotnet add package nacos-sdk-csharp-unofficial.AspNetCore
dotnet add package nacos-sdk-csharp-unofficial.Extensions.Configuration
dotnet add package nacos-sdk-csharp-unofficial.YamlParser
dotnet add package nacos-sdk-csharp-unofficial.IniParser
dotnet add package nacos-sdk-csharp
dotnet add package nacos-sdk-csharp.AspNetCore
dotnet add package nacos-sdk-csharp.Extensions.Configuration
dotnet add package nacos-sdk-csharp.YamlParser
dotnet add package nacos-sdk-csharp.IniParser
```
> NOTE: The packages' name has remove the suffix `unofficial`.
## Features
- Basic OpenApi Usages
- Integrate ASP.NET Core Configuration System
- Service Registration and Discovery With ASP.NET Core
- Integrate With Aliyun ACM
- Integrate With Aliyun MSE/ACM
- ...
Find more information on the documents pages:
https://nacos-sdk-csharp.readthedocs.io/en/latest/
## Basic Usage
### Simple Configuration Usage
@ -33,6 +39,18 @@ dotnet add package nacos-sdk-csharp-unofficial.IniParser
1. Configure in `Program.cs`
```cs
// after v1.3.3, we can use UseNacosConfig to simplify
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseNacosConfig(section: "NacosConfig", parser: null, logAction: null)
// .UseNacosConfig(section: "NacosConfig", parser: Nacos.YamlParser.YamlConfigurationStringParser.Instance logAction: null)
// .UseNacosConfig(section: "NacosConfig", parser: Nacos.IniParser.IniConfigurationStringParser.Instance logAction: null)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
// before v1.3.3
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
@ -41,15 +59,15 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
// read configuration from config files
// it will use default json parser to parse the configuration store in nacos server.
builder.AddNacosConfiguration(c.GetSection("NacosConfig"));
builder.AddNacosV2Configuration(c.GetSection("NacosConfig"));
// you also can specify ini or yaml parser as well.
// builder.AddNacosConfiguration(c.GetSection("NacosConfig"), Nacos.IniParser.IniConfigurationStringParser.Instance);
// builder.AddNacosConfiguration(c.GetSection("NacosConfig"), Nacos.YamlParser.YamlConfigurationStringParser.Instance);
// builder.AddNacosV2Configuration(c.GetSection("NacosConfig"), Nacos.IniParser.IniConfigurationStringParser.Instance);
// builder.AddNacosV2Configuration(c.GetSection("NacosConfig"), Nacos.YamlParser.YamlConfigurationStringParser.Instance);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
});
```
2. Modify `appsettings.json`
@ -57,16 +75,27 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
```JSON
{
"NacosConfig": {
"Optional": false,
"DataId": "msconfigapp",
"Group": "",
"Tenant": "f47e0ae1-982a-4a64-aea3-52506492a3d4",
"Listeners": [
{
"Optional": false,
"DataId": "common",
"Group": "DEFAULT_GROUP"
},
{
"Optional": false,
"DataId": "demo",
"Group": "DEFAULT_GROUP"
}
],
"Namespace": "csharp-demo", // Please set the value of Namespace ID !!!!!!!!
"ServerAddresses": [ "http://localhost:8848/" ],
"UserName": "test2",
"Password": "123456",
"AccessKey": "",
"SecretKey": "",
"EndPoint": "acm.aliyun.com:8080"
"EndPoint": "acm.aliyun.com",
"ConfigFilterAssemblies": ["YouPrefix.AssemblyName"],
"ConfigFilterExtInfo": "some ext infomation"
}
}
```
@ -128,7 +157,7 @@ public class Startup
{
// ...
services.AddNacosAspNetCore(Configuration);
services.AddNacosAspNet(Configuration, "nacos");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@ -142,20 +171,29 @@ Modify `appsettings.json`
```JSON
"nacos": {
"EndPoint": "sub-domain.aliyun.com:8080",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "",
"Namespace": "cs", // Please set the value of Namespace ID !!!!!!!!
"ListenInterval": 1000,
"ServiceName": "App1",
"ClusterName": "",
"GroupName": "",
"Weight": 100,
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Ip": "",
"PreferredNetworks": "", // select an IP that matches the prefix as the service registration IP
"UserName": "test2",
"Password": "123456",
"Port": 0,
"Weight": 100,
"RegisterEnabled": true,
"InstanceEnabled": true,
"Ephemeral": true,
"Secure": false,
"AccessKey": "",
"SecretKey": "",
"EndPoint": "sub-domain.aliyun.com:8080",
"UserName": "",
"Password": "",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": "",
"LBStrategy": "WeightRandom", //WeightRandom WeightRoundRobin
"Metadata": {
"aa": "bb",
@ -171,19 +209,23 @@ Modify `appsettings.json`
[ApiController]
public class ValuesController : ControllerBase
{
private readonly INacosServerManager _serverManager;
private readonly Nacos.V2.INacosNamingService _svc;
public ValuesController(INacosServerManager serverManager)
public ValuesController(Nacos.V2.INacosNamingService svc)
{
_serverManager = serverManager;
_svc = svc;
}
[HttpGet("test")]
public async Task<IActionResult> Test()
{
// need to know the service name.
// support WeightRandom and WeightRoundRobin.
var baseUrl = await _serverManager.GetServerAsync("App2");
var instance = await _svc.SelectOneHealthyInstance("App2", "DEFAULT_GROUP");
var host = $"{instance.Ip}:{instance.Port}";
var baseUrl = instance.Metadata.TryGetValue("secure", out _)
? $"https://{host}"
: $"http://{host}";
if(string.IsNullOrWhiteSpace(baseUrl))
{

View File

@ -1,8 +1,9 @@
# nacos-sdk-csharp             [English](./README.md)
# nacos-sdk-csharp             [English](./README.md)
基于C#(dotnet core)实现 [nacos](https://nacos.io/) OpenAPI 的官方版本
![Build](https://github.com/nacos-group/nacos-sdk-csharp/workflows/Build/badge.svg) ![Release](https://github.com/nacos-group/nacos-sdk-csharp/workflows/Release/badge.svg) ![](https://img.shields.io/nuget/v/nacos-sdk-csharp-unofficial.svg) ![](https://img.shields.io/nuget/vpre/nacos-sdk-csharp-unofficial.svg) ![](https://img.shields.io/nuget/dt/nacos-sdk-csharp-unofficial) ![](https://img.shields.io/github/license/nacos-group/nacos-sdk-csharp)
![Build](https://github.com/nacos-group/nacos-sdk-csharp/workflows/Build/badge.svg) ![Release](https://github.com/nacos-group/nacos-sdk-csharp/workflows/Release/badge.svg) ![](https://img.shields.io/nuget/v/nacos-sdk-csharp.svg) ![](https://img.shields.io/nuget/vpre/nacos-sdk-csharp.svg) ![](https://img.shields.io/nuget/dt/nacos-sdk-csharp) ![](https://img.shields.io/github/license/nacos-group/nacos-sdk-csharp)
![](./media/prj.png)
@ -11,21 +12,28 @@
选择您需要的包。
```bash
dotnet add package nacos-sdk-csharp-unofficial
dotnet add package nacos-sdk-csharp-unofficial.AspNetCore
dotnet add package nacos-sdk-csharp-unofficial.Extensions.Configuration
dotnet add package nacos-sdk-csharp-unofficial.YamlParser
dotnet add package nacos-sdk-csharp-unofficial.IniParser
dotnet add package nacos-sdk-csharp
dotnet add package nacos-sdk-csharp.AspNetCore
dotnet add package nacos-sdk-csharp.Extensions.Configuration
dotnet add package nacos-sdk-csharp.YamlParser
dotnet add package nacos-sdk-csharp.IniParser
```
> 注: 包名里面的`unofficial`后缀已经被移除。
## 功能特性
- 基本的Open Api接口封装
- 集成ASP.NET Core的配置系统
- 简易ASP.NET Core的服务注册和发现
- 和阿里云应用配置管理(Application Configuration Management简称 ACM)集成使用
- 和阿里云微服务引擎(Microservices Engine简称 MSE)集成使用
- ...
更多信息请查阅文档:
https://nacos-sdk-csharp.readthedocs.io/en/latest/
## 简易用法
### 配置
@ -33,6 +41,18 @@ dotnet add package nacos-sdk-csharp-unofficial.IniParser
1. 在 `Program.cs` 进行如下配置
```cs
// v1.3.3 版本之后, 可以用 UseNacosConfig 来简化
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseNacosConfig(section: "NacosConfig", parser: null, logAction: null)
// .UseNacosConfig(section: "NacosConfig", parser: Nacos.YamlParser.YamlConfigurationStringParser.Instance logAction: null)
// .UseNacosConfig(section: "NacosConfig", parser: Nacos.IniParser.IniConfigurationStringParser.Instance logAction: null)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
// v1.3.3 版本之前
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
@ -41,15 +61,15 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
// 从配置文件读取Nacos相关配置
// 默认会使用JSON解析器来解析存在Nacos Server的配置
builder.AddNacosConfiguration(c.GetSection("NacosConfig"));
builder.AddNacosV2Configuration(c.GetSection("NacosConfig"));
// 也可以按需使用ini或yaml的解析器
// builder.AddNacosConfiguration(c.GetSection("NacosConfig"), Nacos.IniParser.IniConfigurationStringParser.Instance);
// builder.AddNacosConfiguration(c.GetSection("NacosConfig"), Nacos.YamlParser.YamlConfigurationStringParser.Instance);
// builder.AddNacosV2Configuration(c.GetSection("NacosConfig"), Nacos.IniParser.IniConfigurationStringParser.Instance);
// builder.AddNacosV2Configuration(c.GetSection("NacosConfig"), Nacos.YamlParser.YamlConfigurationStringParser.Instance);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
});
```
2. 修改 `appsettings.json`
@ -57,16 +77,27 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
```JSON
{
"NacosConfig": {
"Optional": false,
"DataId": "msconfigapp",
"Group": "",
"Tenant": "f47e0ae1-982a-4a64-aea3-52506492a3d4",
"Listeners": [
{
"Optional": false,
"DataId": "common",
"Group": "DEFAULT_GROUP"
},
{
"Optional": false,
"DataId": "demo",
"Group": "DEFAULT_GROUP"
}
],
"Namespace": "csharp-demo", // 这里请设置 Namespace ID 的值!!!!!!!!
"ServerAddresses": [ "http://localhost:8848/" ],
"UserName": "test2",
"Password": "123456",
"AccessKey": "",
"SecretKey": "",
"EndPoint": "acm.aliyun.com"
"EndPoint": "acm.aliyun.com",
"ConfigFilterAssemblies": ["YouPrefix.AssemblyName"],
"ConfigFilterExtInfo": "some ext infomation"
}
}
```
@ -128,7 +159,7 @@ public class Startup
{
// ...
services.AddNacosAspNetCore(Configuration);
services.AddNacosAspNet(Configuration, "nacos");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@ -142,20 +173,29 @@ public class Startup
```JSON
"nacos": {
"EndPoint": "sub-domain.aliyun.com:8080",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "",
"Namespace": "cs", // 这里请设置 Namespace ID 的值!!!!!!!!
"ListenInterval": 1000,
"ServiceName": "App1",
"ClusterName": "",
"GroupName": "",
"Weight": 100,
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Ip": "",
"PreferredNetworks": "", // select an IP that matches the prefix as the service registration IP
"UserName": "test2",
"Password": "123456",
"Port": 0,
"Weight": 100,
"RegisterEnabled": true,
"InstanceEnabled": true,
"Ephemeral": true,
"Secure": false,
"AccessKey": "",
"SecretKey": "",
"EndPoint": "sub-domain.aliyun.com:8080",
"UserName": "",
"Password": "",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": "",
"LBStrategy": "WeightRandom", //WeightRandom WeightRoundRobin
"Metadata": {
"aa": "bb",
@ -171,19 +211,23 @@ public class Startup
[ApiController]
public class ValuesController : ControllerBase
{
private readonly INacosServerManager _serverManager;
private readonly Nacos.V2.INacosNamingService _svc;
public ValuesController(INacosServerManager serverManager)
public ValuesController(Nacos.V2.INacosNamingService svc)
{
_serverManager = serverManager;
_svc = svc;
}
[HttpGet("test")]
public async Task<IActionResult> Test()
{
// 这里需要知道被调用方的服务名
// 支持加权随机和加权轮询
var baseUrl = await _serverManager.GetServerAsync("App2");
var instance = await _svc.SelectOneHealthyInstance("App2", "DEFAULT_GROUP")
var host = $"{instance.Ip}:{instance.Port}";
var baseUrl = instance.Metadata.TryGetValue("secure", out _)
? $"https://{host}"
: $"http://{host}";
if(string.IsNullOrWhiteSpace(baseUrl))
{

View File

@ -53,6 +53,8 @@
<Rule Id="SA1503" Action="None" />
<!-- Code should not contain multiple blank lines in a row -->
<Rule Id="SA1507" Action="None" />
<!-- File is required to end with a single newline character-->
<Rule Id="SA1518" Action="None" />
<!-- Element must be documented -->
<Rule Id="SA1600" Action="None" />
<!-- Parameter documentation mus be in the right order -->

View File

@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<NugetVersion>0.8.5</NugetVersion>
<NugetVersion>1.3.10</NugetVersion>
</PropertyGroup>
</Project>

20
docs/Makefile Normal file
View File

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

37
docs/blogs/info.rst Normal file
View File

@ -0,0 +1,37 @@
一些博客
===============
2022
^^^^^^^^^^^^^
- `微服务 配置中心 Nacos .Net 5 <https://blog.csdn.net/i2blue/article/details/124827269>`_ 【2022-05-17】
- `待挖掘 <https://github.com/nacos-group/nacos-sdk-csharp>`_ 【2022-xx-xx】
2021
^^^^^^^^^^^^^
- `聊一聊Yarp结合Nacos完成服务发现 <https://mp.weixin.qq.com/s/VkGSyqW0jZq4XzrEQTLbOQ>`_ 【2021-12-27】
- `Nacos配置中心+ASP.NET Core <https://www.cnblogs.com/igeekfan/p/nacos-aspnetcore.html>`_ 【2021-12-26】
- `聊一聊基于Nacos的metadata完成服务间的AB测试 <https://mp.weixin.qq.com/s/gm2Pt5WKMYncIWW1tb6N7g>`_ 【2021-12-13】
- `Asp.Net5 WebAPI 使用NacOS作为配置中心的方法 <https://www.cnblogs.com/puzi0315/p/15577888.html>`_ 【2021-11-19】
- `聊一聊声明式接口调用与Nacos的结合使用 <https://mp.weixin.qq.com/s/ySWaEVs-EETe_mvjpqdxQA>`_ 【2021-11-12】
- `聊一聊.NET Core结合Nacos实现配置加解密 <https://mp.weixin.qq.com/s/XAWBGyHkmluC8pkJrsVW8g>`_ 【2021-06-15】
- `聊一聊如何在.NET Core中使用Nacos 2.0 <https://mp.weixin.qq.com/s/iC6lFJJsHUFUveSJhoZxgA>`_ 【2021-03-22】
- `聊一聊和Nacos 2.0.0对接那些事 <https://mp.weixin.qq.com/s/YOasHrZiJlT44RvD67Ayeg>`_ 【2021-03-08】
2020
^^^^^^^^^^^^^
- `ASP.NET Core集成Nacos配置中心之适配多格式配置 <https://mp.weixin.qq.com/s/jAr1pPNXWfdF2QO2dN5sdw>`_ 【2020-10-02】
- `手动造轮子——为Ocelot集成Nacos注册中心 <https://www.cnblogs.com/wucy/p/13353824.html>`_ 【2020-07-21】
- `搭建一套ASP.NET Core+Nacos+Spring Cloud Gateway项目 <https://www.cnblogs.com/wucy/p/13230453.html>`_ 【2020-07-03】
- `ASP.NET Core使用Nacos SDK访问阿里云ACM <https://mp.weixin.qq.com/s/RHXE4WvSne4fulBzPbaH2A>`_ 【2020-06-07】
- `在.NET Core中用最原生的方式读取Nacos的配置 <https://mp.weixin.qq.com/s/CsR1he4UsI6PSujMlwOpyg>`_ 【2020-04-26】
2019
^^^^^^^^^^^^
- `ASP.NET Core使用Nacos作为配置中心的多环境问题 <https://www.cnblogs.com/catcher1994/p/11906556.html>`_ 【2019-11-21】

9
docs/blogs/lib.rst Normal file
View File

@ -0,0 +1,9 @@
一些组件
===============
- `Ocelot.Provider.Nacos <https://github.com/softlgl/Ocelot.Provider.Nacos>`_ 【Ocelot集成Nacos注册中心组件】
- `nacos-csharp-extensions <https://github.com/catcherwong/nacos-csharp-extensions>`_ 【Nacos的一些扩展(声明式接口调用集成YARP集成等)】

174
docs/conf.py Normal file
View File

@ -0,0 +1,174 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
source_suffix = ['.rst']
master_doc = 'index'
# -- Project information -----------------------------------------------------
project = 'nacos-sdk-csharp'
copyright = '2021, Catcher Wong'
author = 'Catcher Wong'
# The full version, including alpha/beta/rc tags
version = '1.0.0'
release = '1.0.0'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'zh_CN'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
import os
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd: # only import and set the theme if we're building docs locally
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'nacos-sdk-csharp.tex', 'nacos-sdk-csharp Documentation',
'Catcher Wong', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#
# latex_use_parts = False
# If true, show page references after internal links.
#
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
#
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
#
# latex_appendices = []
# It false, will not define \strong, \code, itleref, \crossref ... but only
# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
# packages.
#
# latex_keep_old_macro_names = True
# If false, no module index is generated.
#
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'nacos-sdk-csharp', 'nacos-sdk-csharp Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'nacos-sdk-csharp', 'nacos-sdk-csharp Documentation',
author, 'nacos-sdk-csharp', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#
# texinfo_appendices = []
# If false, no module index is generated.
#
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#
# texinfo_no_detailmenu = False

View File

@ -0,0 +1,69 @@
配置加解密
===============
配置加解密这个功能是衍生功能,目前和 nacos 服务端联系还不大,是 SDK 对配置加密后再传输,解密后再使用。
如果需要使用这个功能,需要做下面两件事。
1. 自定义 ConfigFilter
2. 配置 ConfigFilter
自定义 ConfigFilter
^^^^^^^^^^^^^^^^^^^^^^
把配置加解密的逻辑放到自定义的 ConfigFilter 里面。 ConfigFilter 可以有多个,不同 ConfigFilter 的执行顺序是按他们的 Order 属性来决定的。
.. code-block:: csharp
public class MyNacosConfigFilter : IConfigFilter
{
public void DoFilter(IConfigRequest request, IConfigResponse response, IConfigFilterChain filterChain)
{
if (request != null)
{
// 这里是请求的过滤,也就是在这里进行加密操作
// 不要忘了在这里覆盖请求的内容!!!!!
request.PutParameter(Nacos.V2.Config.ConfigConstants.ENCRYPTED_DATA_KEY, encryptedDataKey);
request.PutParameter(Nacos.V2.Config.ConfigConstants.CONTENT, content);
}
if (response != null)
{
// 这里是响应的过滤,也就是在这里进行解密操作
// 不要忘了在这里覆盖响应的内容!!!!!
response.PutParameter(Nacos.V2.Config.ConfigConstants.CONTENT, content);
}
}
public string GetFilterName() => nameof(MyNacosConfigFilter);
public int GetOrder() => 1;
public void Init(NacosSdkOptions options)
{
// 做一些初始化操作
}
}
配置 ConfigFilter
^^^^^^^^^^^^^^^^^^^^^^
这一步主要是告诉 nacos-sdk-csharp 去那个程序集找 ConfigFilter 的实现,以及它的实现需要什么参数。
.. code-block:: JSON
{
"NacosConfig": {
"ConfigFilterAssemblies": [ "XXXX.CusLib" ],
"ConfigFilterExtInfo": "{\"JsonPaths\":[\"ConnectionStrings.Default\"],\"Other\":\"xxxxxx\"}"
}
}
这里主要是两个配置,一个是 `ConfigFilterAssemblies` 指定实现类所在的程序集,一个是 `ConfigFilterExtInfo` 指定实现类可能需要的参数。

View File

@ -0,0 +1,86 @@
配置中心
===============
`nacos-sdk-csharp` 操作 nacos 的配置提供了两个 nuget 包,一个是原生的 sdk 版本, 一个是集成了 ASP.NET Core 配置体系的版本,大家可以根据自己的需要选择不同的版本。
::
注: 请还在使用 nuget 包的名称里面还带有 `unofficial` 的朋友尽快升级到
不带 `unofficial` 的版本,新版本同时支持 nacos server 1.x 和 2.x
原生的 sdk 版本
^^^^^^^^^^^^^^^^^^^
原生 sdk 暴露出了下面几个方法
.. code-block:: csharp
Task<string> GetConfig(string dataId, string group, long timeoutMs);
Task<string> GetConfigAndSignListener(string dataId, string group, long timeoutMs, IListener listener);
Task AddListener(string dataId, string group, IListener listener);
Task<bool> PublishConfig(string dataId, string group, string content);
Task<bool> PublishConfig(string dataId, string group, string content, string type);
Task<bool> RemoveConfig(string dataId, string group);
Task RemoveListener(string dataId, string group, IListener listener);
Task<string> GetServerStatus();
Task ShutDown();
主要就是配置的 CURD 和监听。
监听可以让客户端实时获取 nacos 上面的最新配置,这个对实现配置的热加载/热更新是一个很重要的基石。
实现监听,需要自定义一个实现 `IListener` 的监听者。
.. code-block:: csharp
public class CusConfigListen : Nacos.V2.IListener
{
public void ReceiveConfigInfo(string configInfo)
{
// 这里会有配置变更的回调,在这里处理配置变更之后的逻辑。
System.Console.WriteLine("config cb cb cb " + configInfo);
}
}
添加监听和移除监听,要保证是同一个监听者对象,不然会造成监听一直存在,移除不了的情况。
对于重要配置被修改需要通知到部门群或者其他地方时,通过监听就可以实现一个 webhook 的功能了。
集成 ASP.NET Core 版本
^^^^^^^^^^^^^^^^^^^^^^^^
推出这样一个版本很大程度是为了简化操作,只加几个配置,代码层级的用法几乎零改动,类似于 spring cloud 那样。
SDK 这一块通过实现了自定义的 **ConfigurationProvider****IConfigurationSource** 来达到了这个效果。
对于配置的热加载/热更新, SDK 则是实现了一个默认的监听者,在配置变更之后进行了 `OnReload` 的操作。
使用上需要在 `Program` 里面进行 **ConfigureAppConfiguration** 的设置。
.. code-block:: csharp
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
var c = builder.Build();
builder.AddNacosV2Configuration(c.GetSection("NacosConfig"));
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
::
注: 请注意 `IOptions<T>``IOptionsSnapshot<T>``IOptionsMonitor<T>` 的区别
避免出现配置变更了,应用读取不到最新配置的情况!!!

59
docs/features/mse.rst Normal file
View File

@ -0,0 +1,59 @@
集成微服务引擎MSE
===================
前置条件
^^^^^^^^^^^^^^^^^^^
注册阿里云账号,并开通和购买微服务引擎。
使用 SDK 操作的话,只需要将 ServerAddresses 替换成 mse 实例对应的地址即可。
示例如下:
配置模块
^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: json
{
"NacosConfig": {
"Listeners": [
{
"Optional": false,
"DataId": "common",
"Group": "DEFAULT_GROUP"
},
{
"Optional": false,
"DataId": "demo",
"Group": "DEFAULT_GROUP"
}
],
"Namespace": "0138xxxx-yyyy-zzzz-1111-000000000000",
"ServerAddresses": [ "http://mse-xxxxxxxxxxx-nacos-ans.mse.aliyuncs.com:8848" ]
}
}
服务注册发现模块
^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: json
{
"nacos": {
"ServerAddresses": [ "http://mse-xxxxxxxxxxx-nacos-ans.mse.aliyuncs.com:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "0138xxxx-yyyy-zzzz-1111-000000000000",
"ListenInterval": 1000,
"ServiceName": "App1",
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Weight": 100,
"RegisterEnabled": true,
"InstanceEnabled": true,
"Ephemeral": true
}
}

View File

@ -0,0 +1,134 @@
服务发现
===============
`nacos-sdk-csharp` 操作 nacos 的配置提供了两个 nuget 包,一个是原生的 sdk 版本, 一个是集成了 ASP.NET Core 配置体系的版本,大家可以根据自己的需要选择不同的版本。
::
注: 请还在使用 nuget 包的名称里面还带有 `unofficial` 的朋友尽快升级到
不带 `unofficial` 的版本,新版本同时支持 nacos server 1.x 和 2.x
原生的 sdk 版本
^^^^^^^^^^^^^^^^^^^
原生 sdk 暴露出了下面几个方法
.. code-block:: csharp
Task RegisterInstance(string serviceName, string ip, int port);
Task RegisterInstance(string serviceName, string groupName, string ip, int port);
Task RegisterInstance(string serviceName, string ip, int port, string clusterName);
Task RegisterInstance(string serviceName, string groupName, string ip, int port, string clusterName);
Task RegisterInstance(string serviceName, Instance instance);
Task RegisterInstance(string serviceName, string groupName, Instance instance);
Task DeregisterInstance(string serviceName, string ip, int port);
Task DeregisterInstance(string serviceName, string groupName, string ip, int port);
Task DeregisterInstance(string serviceName, string ip, int port, string clusterName);
Task DeregisterInstance(string serviceName, string groupName, string ip, int port, string clusterName);
Task DeregisterInstance(string serviceName, Instance instance);
Task DeregisterInstance(string serviceName, string groupName, Instance instance);
Task<List<Instance>> GetAllInstances(string serviceName);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName);
Task<List<Instance>> GetAllInstances(string serviceName, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, List<string> clusters);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, List<string> clusters);
Task<List<Instance>> GetAllInstances(string serviceName, List<string> clusters, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, List<string> clusters, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, List<string> clusters, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, List<string> clusters, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, List<string> clusters, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, List<string> clusters, bool healthy, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName);
Task<Instance> SelectOneHealthyInstance(string serviceName, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, List<string> clusters);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, List<string> clusters);
Task<Instance> SelectOneHealthyInstance(string serviceName, List<string> clusters, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, List<string> clusters, bool subscribe);
Task Subscribe(string serviceName, IEventListener listener);
Task Subscribe(string serviceName, string groupName, IEventListener listener);
Task Subscribe(string serviceName, List<string> clusters, IEventListener listener);
Task Subscribe(string serviceName, string groupName, List<string> clusters, IEventListener listener);
Task Unsubscribe(string serviceName, IEventListener listener);
Task Unsubscribe(string serviceName, string groupName, IEventListener listener);
Task Unsubscribe(string serviceName, List<string> clusters, IEventListener listener);
Task Unsubscribe(string serviceName, string groupName, List<string> clusters, IEventListener listener);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, string groupName);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, AbstractSelector selector);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, string groupName, AbstractSelector selector);
Task<List<ServiceInfo>> GetSubscribeServices();
Task<string> GetServerStatus();
Task ShutDown();
可以看到有很多重载的方法,主要也是离不开服务的 CURD 和监听。
集成 ASP.NET Core 版本
^^^^^^^^^^^^^^^^^^^^^^^^
推出这样一个版本很大程度是为了简化操作,可以在应用启动的时候注册到 nacos 的注册中心,应用停止的时候可以注销。
SDK 内部是通过实现了一个后台服务 (IHostedService) 来达到这个效果的。
无论是注册还是注销,都会有重试的机制,目前最多重试 3 次。
查询服务实例则需要通过上面 **INacosNamingService** 提供的方法来实现。

41
docs/guide/faq.rst Normal file
View File

@ -0,0 +1,41 @@
常见问题
===============
这个文档记录了一些 SDK 和 nacos server 对接使用上的常见问题。
1. 命名空间问题
^^^^^^^^^^^^^^^^^^^^^^
命名空间可以说是第一要素,如果这个没有设置对,那么在控制台里面会看不到对应命名空间下面的数据。
在新建命名空间时是可以指定命名空间Id的不指定的话会自动生成一个UUID。
在SDK的配置里面配置的一定是命名空间Id。如果是 public 命名空间,配置的是一个空字符串。
2. nacos server 端口开放问题
^^^^^^^^^^^^^^^^^^^^^^^^^^
SDK 在 v1.x 版本之后,就是默认用 grpc 的方式和 nacos server 对接,这个时候会出现下面几种情况。
- a. nacos server 是 1.x 版本SDK 版本 >= 1.0
- b. nacos server 是 2.x 版本,基于 docker/k8s 部署,只暴露了默认的 8848 端口,没有暴露 grpc 的端口, SDK版本 >= 1.0
这个时候会出现 `Client not connected,current status: STARTING` 的错误
针对 a 的情况,需要把 xxxUseRpc 设置为 false。
针对 b 的情况,需要把 9848 暴露出来。
如果修改了默认端口或者是通过环境变量设置了偏移,自行调整对应端口,参考 https://nacos.io/zh-cn/docs/2.0.0-compatibility.html
3. nacos-sdk-csharp 版本与 nacos server 版本关系
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nacos server 目前主要有 1.x 版本和 2.x 版本
nacos-sdk-csharp 有 0.x unofficial 版本 和 1.x 版本
nacos-sdk-csharp 0.x unofficial 版本 只能应用于 nacos server 1.x 版本
nacos-sdk-csharp 1.x 版本 可以同时应用于 nacos server 1.x 版本 和 2.x 版本

View File

@ -0,0 +1,248 @@
升级到1.0版本指引
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
背景
---------------
`nacos-sdk-csharp` v1.0.0 版本之前主要是对接 nacos server 1.x。
随着 nacos server 2.0.0 即将发布,`nacos-sdk-csharp` 也已经进行了一次重构和适配来对接。
由于 nacos server 从 1.x 到 2.x 客户端对接的协议有所变更1.x主要是HTTP 2.x主要是gRPC。
之前 sdk 主要是对 Open Api 进行了封装和补充了部分内容。
在 1.0.0 版本sdk 的方法会对齐 java版的 sdk 这里的调整会比较大,但是之前用的方法还会保留几个版本。
升级
---------------
大前提是 nacos server 版本已经是 2.0.0或更高版本。
修改引用的 nuget 包
.. code-block:: diff
<ItemGroup>
- <PackageReference Include="nacos-sdk-csharp-unofficial" Version="0.8.5" />
+ <PackageReference Include="nacos-sdk-csharp" Version="1.0.0-alphaxxxx" />
</ItemGroup>
..
注: 包名已经移除了 `unofficial` 的后缀1.0.0的版本目前还是prerelease所以会有alpha的字样
正式发布后是没有的。如果依赖了扩展包,也需要做对应的处理。
核心的基础配置如下:
.. code-block:: json
{
"EndPoint": "",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "cs",
"ListenInterval": 1000,
"AccessKey": "",
"SecretKey": "",
"UserName": "",
"Password": "",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": ""
}
只有当 `ConfigUseRpc``NamingUseRpc` 设置为true的时候才会用 gRPC 去和 nacos server 交互, 反之还是 HTTP。
另外Namespace 字段填写的值是控制台中的 命名空间Id不是命名空间名称
配置变化
---------------
**SDK**
代码层使用的 `INacosConfigClient` 需要调整成 `INacosConfigService` 提供了如下的方法。
.. code-block:: csharp
Task<string> GetConfig(string dataId, string group, long timeoutMs);
Task<string> GetConfigAndSignListener(string dataId, string group, long timeoutMs, IListener listener);
Task AddListener(string dataId, string group, IListener listener);
Task<bool> PublishConfig(string dataId, string group, string content);
Task<bool> PublishConfig(string dataId, string group, string content, string type);
Task<bool> RemoveConfig(string dataId, string group);
Task RemoveListener(string dataId, string group, IListener listener);
Task<string> GetServerStatus();
Task ShutDown();
**集成ASP.NET Core**
主要是变更 `ConfigureAppConfiguration` 里面的 AddNacosConfiguration其余的不需要变化。
.. code-block:: diff
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
var c = builder.Build();
- builder.AddNacosConfiguration(c.GetSection("NacosConfig"));
+ builder.AddNacosV2Configuration(c.GetSection("NacosConfig"));
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
服务变化
---------------
**SDK**
代码层使用的 `INacosNamingClient` 需要调整成 `INacosNamingService` 提供了如下的方法。
.. code-block:: csharp
Task RegisterInstance(string serviceName, string ip, int port);
Task RegisterInstance(string serviceName, string groupName, string ip, int port);
Task RegisterInstance(string serviceName, string ip, int port, string clusterName);
Task RegisterInstance(string serviceName, string groupName, string ip, int port, string clusterName);
Task RegisterInstance(string serviceName, Instance instance);
Task RegisterInstance(string serviceName, string groupName, Instance instance);
Task DeregisterInstance(string serviceName, string ip, int port);
Task DeregisterInstance(string serviceName, string groupName, string ip, int port);
Task DeregisterInstance(string serviceName, string ip, int port, string clusterName);
Task DeregisterInstance(string serviceName, string groupName, string ip, int port, string clusterName);
Task DeregisterInstance(string serviceName, Instance instance);
Task DeregisterInstance(string serviceName, string groupName, Instance instance);
Task<List<Instance>> GetAllInstances(string serviceName);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName);
Task<List<Instance>> GetAllInstances(string serviceName, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, List<string> clusters);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, List<string> clusters);
Task<List<Instance>> GetAllInstances(string serviceName, List<string> clusters, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, List<string> clusters, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, List<string> clusters, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, List<string> clusters, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, List<string> clusters, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, List<string> clusters, bool healthy, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName);
Task<Instance> SelectOneHealthyInstance(string serviceName, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, List<string> clusters);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, List<string> clusters);
Task<Instance> SelectOneHealthyInstance(string serviceName, List<string> clusters, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, List<string> clusters, bool subscribe);
Task Subscribe(string serviceName, IEventListener listener);
Task Subscribe(string serviceName, string groupName, IEventListener listener);
Task Subscribe(string serviceName, List<string> clusters, IEventListener listener);
Task Subscribe(string serviceName, string groupName, List<string> clusters, IEventListener listener);
Task Unsubscribe(string serviceName, IEventListener listener);
Task Unsubscribe(string serviceName, string groupName, IEventListener listener);
Task Unsubscribe(string serviceName, List<string> clusters, IEventListener listener);
Task Unsubscribe(string serviceName, string groupName, List<string> clusters, IEventListener listener);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, string groupName);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, AbstractSelector selector);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, string groupName, AbstractSelector selector);
Task<List<ServiceInfo>> GetSubscribeServices();
Task<string> GetServerStatus();
Task ShutDown();
**集成ASP.NET Core**
调整 `Startup`
.. code-block:: diff
public void ConfigureServices(IServiceCollection services)
{
- services.AddNacosAspNetCore(Configuration);
+ services.AddNacosAspNet(Configuration);
services.AddControllers();
}
用到 `INacosServerManager` 的地方需要换成 `INacosNamingService`
具体使用如下:
.. code-block:: diff
- var baseUrl = await _serverManager.GetServerAsync("App2");
+ var instance = await _svc.SelectOneHealthyInstance("App2", "DEFAULT_GROUP");
+ var host = $"{instance.Ip}:{instance.Port}";
+ var baseUrl = instance.Metadata.TryGetValue("secure", out _)
+ ? $"https://{host}"
+ : $"http://{host}";
服务的配置,在原先的基础上添加了, **InstanceEnabled** **Ephemeral** **Secure** 三个内容。

251
docs/guide/v1.0.1/guide.rst Normal file
View File

@ -0,0 +1,251 @@
Guidelines for upgrading to version 1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Background
---------------
Before `nacos-sdk-csharp` v1.0.0, it was mainly connected to Nacos server 1. X.
With the release of Nacos server 2.0.0, `nacos-sdk-csharp` has been reconstructed and adapted to dock.
Because the protocol of Nacos server from 1.X to 2.X is changed, 1.X is mainly HTTP, 2.X is mainly grpc.
Before, the SDK mainly encapsulated and supplemented some contents of open API.
In version 1.0.0, the SDK method will align with the Java version of the SDK. The adjustment here will be relatively large, but several versions of the previous method will be retained.
Upgrade
------------
The premise is that the version of nacos server is 2.0.0 or higher.
Modify the referenced nuget package
.. code-block:: diff
<ItemGroup>
- <PackageReference Include="nacos-sdk-csharp-unofficial" Version="0.8.5" />
+ <PackageReference Include="nacos-sdk-csharp" Version="1.0.0-alphaxxxx" />
</ItemGroup>
..
NOTE The suffix "unofficial" has been removed from the package name. The version 1.0.0 is still prereleased,
so there will be alpha, which will not be available after the official release.
If you depend on the extension package, you need to do the corresponding processing.
The basic configuration is as follows:
.. code-block:: json
{
"EndPoint": "",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "cs",
"ListenInterval": 1000,
"AccessKey": "",
"SecretKey": "",
"UserName": "",
"Password": "",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": ""
}
Only when 'ConfigUseRpc' and 'NamingUseRpc' are set to true, gPRC will be used to interact with Nacos server, otherwise HTTP will be used.
And `Namespace` should be set to the Namespace Id in the nacos console, not the Namespace name!!!!!!
Configuration changes
--------------------------
**SDK**
Adjust `INacosConfigClient` to `INacosConfigService` and it providers the following methods.
.. code-block:: csharp
Task<string> GetConfig(string dataId, string group, long timeoutMs);
Task<string> GetConfigAndSignListener(string dataId, string group, long timeoutMs, IListener listener);
Task AddListener(string dataId, string group, IListener listener);
Task<bool> PublishConfig(string dataId, string group, string content);
Task<bool> PublishConfig(string dataId, string group, string content, string type);
Task<bool> RemoveConfig(string dataId, string group);
Task RemoveListener(string dataId, string group, IListener listener);
Task<string> GetServerStatus();
Task ShutDown();
**Integrate ASP.NET Core**
.. code-block:: diff
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
var c = builder.Build();
- builder.AddNacosConfiguration(c.GetSection("NacosConfig"));
+ builder.AddNacosV2Configuration(c.GetSection("NacosConfig"));
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
Service changes
--------------------------
**SDK**
Adjust `INacosNamingClient` to `INacosNamingService` and it providers the following methods.
.. code-block:: csharp
Task RegisterInstance(string serviceName, string ip, int port);
Task RegisterInstance(string serviceName, string groupName, string ip, int port);
Task RegisterInstance(string serviceName, string ip, int port, string clusterName);
Task RegisterInstance(string serviceName, string groupName, string ip, int port, string clusterName);
Task RegisterInstance(string serviceName, Instance instance);
Task RegisterInstance(string serviceName, string groupName, Instance instance);
Task DeregisterInstance(string serviceName, string ip, int port);
Task DeregisterInstance(string serviceName, string groupName, string ip, int port);
Task DeregisterInstance(string serviceName, string ip, int port, string clusterName);
Task DeregisterInstance(string serviceName, string groupName, string ip, int port, string clusterName);
Task DeregisterInstance(string serviceName, Instance instance);
Task DeregisterInstance(string serviceName, string groupName, Instance instance);
Task<List<Instance>> GetAllInstances(string serviceName);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName);
Task<List<Instance>> GetAllInstances(string serviceName, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, List<string> clusters);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, List<string> clusters);
Task<List<Instance>> GetAllInstances(string serviceName, List<string> clusters, bool subscribe);
Task<List<Instance>> GetAllInstances(string serviceName, string groupName, List<string> clusters, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, List<string> clusters, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, List<string> clusters, bool healthy);
Task<List<Instance>> SelectInstances(string serviceName, List<string> clusters, bool healthy, bool subscribe);
Task<List<Instance>> SelectInstances(string serviceName, string groupName, List<string> clusters, bool healthy, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName);
Task<Instance> SelectOneHealthyInstance(string serviceName, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, List<string> clusters);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, List<string> clusters);
Task<Instance> SelectOneHealthyInstance(string serviceName, List<string> clusters, bool subscribe);
Task<Instance> SelectOneHealthyInstance(string serviceName, string groupName, List<string> clusters, bool subscribe);
Task Subscribe(string serviceName, IEventListener listener);
Task Subscribe(string serviceName, string groupName, IEventListener listener);
Task Subscribe(string serviceName, List<string> clusters, IEventListener listener);
Task Subscribe(string serviceName, string groupName, List<string> clusters, IEventListener listener);
Task Unsubscribe(string serviceName, IEventListener listener);
Task Unsubscribe(string serviceName, string groupName, IEventListener listener);
Task Unsubscribe(string serviceName, List<string> clusters, IEventListener listener);
Task Unsubscribe(string serviceName, string groupName, List<string> clusters, IEventListener listener);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, string groupName);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, AbstractSelector selector);
Task<ListView<string>> GetServicesOfServer(int pageNo, int pageSize, string groupName, AbstractSelector selector);
Task<List<ServiceInfo>> GetSubscribeServices();
Task<string> GetServerStatus();
Task ShutDown();
**Integrate ASP.NET Core**
Modify `Startup`
.. code-block:: diff
public void ConfigureServices(IServiceCollection services)
{
- services.AddNacosAspNetCore(Configuration);
+ services.AddNacosAspNet(Configuration);
services.AddControllers();
}
From `INacosServerManager` to `INacosNamingService`
Details
.. code-block:: diff
- var baseUrl = await _serverManager.GetServerAsync("App2");
+ var instance = await _svc.SelectOneHealthyInstance("App2", "DEFAULT_GROUP");
+ var host = $"{instance.Ip}:{instance.Port}";
+ var baseUrl = instance.Metadata.TryGetValue("secure", out _)
+ ? $"https://{host}"
+ : $"http://{host}";
On the basis of the original service configuration, three options are added: **InstanceEnabled**, **Ephemeral**, **Secure**.

BIN
docs/images/prj.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

56
docs/index.rst Normal file
View File

@ -0,0 +1,56 @@
.. nacos-sdk-csharp documentation master file, created by
sphinx-quickstart on Sat Sep 4 10:44:58 2021.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
欢迎查阅 nacos-sdk-csharp 的文档!
=================================================
`nacos-sdk-csharp` 是基于 C# ( dotnet core ) 实现 `nacos <https://nacos.io/>`_ 的版本
.. image:: ./images/prj.png
.. toctree::
:maxdepth: 2
:caption: Introduction
introduction/gettingstarted
introduction/sdkenvvar
.. toctree::
:maxdepth: 2
:hidden:
:caption: Features
features/configuration
features/cfg-encrypt
features/servicediscovery
features/mse
.. toctree::
:maxdepth: 2
:hidden:
:caption: Blogs
blogs/info
blogs/lib
.. toctree::
:maxdepth: 2
:hidden:
:caption: Release Note
releasenote/v1.2.2
releasenote/v1.3.0
releasenote/v1.3.1
releasenote/v1.3.2
releasenote/v1.3.3
.. toctree::
:maxdepth: 2
:hidden:
:caption: Guidelines
guide/v1.0.1/guide
guide/v1.0.1/guide-zh
guide/faq

View File

@ -0,0 +1,239 @@
快速上手
===============
`nacos-sdk-csharp` 是基于 C# ( dotnet core ) 实现 `nacos <https://nacos.io/>`_ 的版本
安装Nuget包
^^^^^^^^^^^^^
选择您需要的包。
.. code-block:: bash
dotnet add package nacos-sdk-csharp
dotnet add package nacos-sdk-csharp.AspNetCore
dotnet add package nacos-sdk-csharp.Extensions.Configuration
dotnet add package nacos-sdk-csharp.YamlParser
dotnet add package nacos-sdk-csharp.IniParser
::
注: 从1.0.0版本之后,包名里面的 `unofficial` 后缀已经被移除,
`unofficial` 的包已经不再维护更新,请尽早更新到最新版本。
功能特性
^^^^^^^^^^^^^
- 基本的Open Api接口封装
- 集成ASP.NET Core的配置系统
- 简易ASP.NET Core的服务注册和发现
- 和阿里云应用配置管理(Application Configuration Management简称 ACM)集成使用
- ...
简易用法
^^^^^^^^^^^^^
配置
---------
1. 在 `Program.cs` 进行如下配置
.. code-block:: csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
var c = builder.Build();
// 从配置文件读取Nacos相关配置
// 默认会使用JSON解析器来解析存在Nacos Server的配置
builder.AddNacosV2Configuration(c.GetSection("NacosConfig"));
// 也可以按需使用ini或yaml的解析器
// builder.AddNacosV2Configuration(c.GetSection("NacosConfig"), Nacos.IniParser.IniConfigurationStringParser.Instance);
// builder.AddNacosV2Configuration(c.GetSection("NacosConfig"), Nacos.YamlParser.YamlConfigurationStringParser.Instance);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
2. 修改 `appsettings.json`
.. code-block:: json
{
"NacosConfig": {
"Listeners": [
{
"Optional": false,
"DataId": "common",
"Group": "DEFAULT_GROUP"
},
{
"Optional": false,
"DataId": "demo",
"Group": "DEFAULT_GROUP"
}
],
"Namespace": "csharp-demo",
"ServerAddresses": [ "http://localhost:8848/" ],
"UserName": "test2",
"Password": "123456",
"AccessKey": "",
"SecretKey": "",
"EndPoint": "acm.aliyun.com",
"ConfigFilterAssemblies": ["YouPrefix.AssemblyName"],
"ConfigFilterExtInfo": "some ext infomation"
}
}
3. 用原生的.NET Core方式来读取Nacos配置
.. code-block:: csharp
[ApiController]
[Route("api/[controller]")]
public class ConfigController : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly AppSettings _settings;
private readonly AppSettings _sSettings;
private readonly AppSettings _mSettings;
public ConfigController(
IConfiguration configuration,
IOptions<AppSettings> options,
IOptionsSnapshot<AppSettings> sOptions,
IOptionsMonitor<AppSettings> _mOptions
)
{
_logger = logger;
_configuration = configuration;
_settings = options.Value;
_sSettings = sOptions.Value;
_mSettings = _mOptions.CurrentValue;
}
[HttpGet]
public string Get()
{
// ....
return "ok";
}
}
服务注册和发现
------------------
1. 服务注册
`Program.cs` 中配置
.. code-block:: csharp
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddNacosAspNet(Configuration, "nacos");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
}
}
修改 `appsettings.json`
.. code-block:: json
"nacos": {
"EndPoint": "sub-domain.aliyun.com:8080",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "cs",
"ListenInterval": 1000,
"ServiceName": "App1",
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Ip": "",
"PreferredNetworks": "", // select an IP that matches the prefix as the service registration IP
"Port": 0,
"Weight": 100,
"RegisterEnabled": true,
"InstanceEnabled": true,
"Ephemeral": true,
"Secure": false,
"AccessKey": "",
"SecretKey": "",
"UserName": "",
"Password": "",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": "",
"LBStrategy": "WeightRandom", //WeightRandom WeightRoundRobin
"Metadata": {
"aa": "bb",
"cc": "dd"
}
}
2. 服务发现
.. code-block:: csharp
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly Nacos.V2.INacosNamingService _svc;
public ValuesController(Nacos.V2.INacosNamingService svc)
{
_svc = svc;
}
[HttpGet("test")]
public async Task<IActionResult> Test()
{
// 这里需要知道被调用方的服务名
var instance = await _svc.SelectOneHealthyInstance("App2", "DEFAULT_GROUP")
var host = $"{instance.Ip}:{instance.Port}";
var baseUrl = instance.Metadata.TryGetValue("secure", out _)
? $"https://{host}"
: $"http://{host}";
if(string.IsNullOrWhiteSpace(baseUrl))
{
return "empty";
}
var url = $"{baseUrl}/api/values";
using (HttpClient client = new HttpClient())
{
var result = await client.GetAsync(url);
return await result.Content.ReadAsStringAsync();
}
}
}

View File

@ -0,0 +1,15 @@
SDK环境变量说明
===============
============================================ ====================== ======================
环境变量Key 默认值 说明
============================================ ====================== ======================
nacos.client.appKey 无 设定 sdk 的 AppKey
JM.SNAPSHOT.PATH 无 Naming 模块的缓存目录
push.receiver.udp.port 无 设定 client 的 udp 端口,针对服务端是 1.x
com.alibaba.nacos.client.naming.local.ip 无 已经废弃请使用com.alibaba.nacos.client.local.ip
com.alibaba.nacos.client.local.ip 无 设置sdk的local ip
nacos.server.grpc.port.offset 1000 nacos服务端grpc端口偏移值
nacos.server.port 8848 nacos服务端的端口
============================================ ====================== ======================

35
docs/make.bat Normal file
View File

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

View File

@ -0,0 +1,13 @@
v1.0.1 (Mar 20th, 2021) 发布记录
=============================================
1. Adapt to nacos 2.0.
#. FIxed some known bugs.
#. Add log for SecurityProxy.
------------
1. 适配 nacos 2.0
#. 修复部分已知bug
#. SecurityProxy 添加日志

View File

@ -0,0 +1,9 @@
v1.0.2 (Mar 21th, 2021) 发布记录
=============================================
1. Fixed Grpc request bi stream,payload parse error
------------
1. 修复Grpc双向流部分payload不能解析问题

View File

@ -0,0 +1,19 @@
v1.0.3 (Apr 18th, 2021) 发布记录
=============================================
1. Fix http with ACM
#. Update proto file
#. Support logging for Nacos.Microsoft.Extensions.Configuration
#. Try to adapt SAE
#. Publish config support type
#. Fix some known issues.
------------
1. 修复 HTTP 协议访问 ACM 问题
#. 更新 proto 文件
#. Nacos.Microsoft.Extensions.Configuration 支持日志
#. 尝试适配 SAE
#. 发布配置支持类型
#. 修复部分已知问题

View File

@ -0,0 +1,29 @@
v1.1.0 (Jun 14th, 2021) 发布记录
=============================================
1. [NAMING] Fixed naming update task error
#. [NAMING] Support naming push empty protection
#. [NAMING] Support read UDP port from the environment variable
#. [NAMING] Fixed services.AddNacosAspNet with action mode error
#. [NAMING] Add/Remove cache before call server
#. [NAMING] Support fetching server list from an endpoint with namespace
#. [CONFIG] Fixed publish will trigger call back twice
#. [CONFIG] Support CAS md5
#. [CONFIG] Support config filter
#. [CONFIG] Support .NET Framework 4.7.1
#. Fixed and enhanced some known issues
------------
1. [NAMING] 修复服务更新任务异常
#. [NAMING] 支持服务为空的推送保护
#. [NAMING] 支持从环境变量读取UDP的端口
#. [NAMING] 修复services.AddNacosAspNet用action方式的异常
#. [NAMING] 在调用服务端之前先添加/移除缓存
#. [NAMING] 支持根据namespace从endpoint获取服务列表
#. [CONFIG] 修复发布配置触发两次回调问题
#. [CONFIG] 支持 CAS md5
#. [CONFIG] 支持 config filter
#. [CONFIG] 支持 .NET Framework 4.7.1
#. 修复和加强部分已知问题

View File

@ -0,0 +1,19 @@
v1.1.1 (Aug 9th, 2021) 发布记录
=============================================
1. [NAMING] Fixed v2 ServerHttpAgent (#117 )
#. [NAMING] Add redo feature for naming client (#122 )
#. [NAMING] Add failover of naming (#123 )
#. [NAMING] Improve weight round robin of v1 naming aspnetcore (#121 #124 )
#. [NAMING] Improve create NamingGrpcClientProxy and PushReveiver (#127 )
#. [CONFIG] Fixed key has already been added of msconfig (#119 #120 )
------------
1. [NAMING] 修复 v2 版本 ServerHttpAgent 请求问题 (#117 )
#. [NAMING] naming client 支持 redo (#122 )
#. [NAMING] naming client 支持 failover (#123 )
#. [NAMING] 优化 v1 版本的加权轮询算法 (#121 #124 )
#. [NAMING] 优化 创建 NamingGrpcClientProxy 和 PushReveiver (#127 )
#. [CONFIG] 修复集成ASP.NET Core时出现重复配置key时的异常 (#119 #120 )

View File

@ -0,0 +1,15 @@
v1.2.0 (Sept 5th, 2021) 发布记录
=============================================
1. [NAMING] Fixed not pass section for AddNacosV2Naming (#131)
#. [AUTH] Fixed request login interface too frequently (#137)
#. [CORE] improve: make rpcstatus error message readable
#. [DOCS] improve: host documentation website on `readthedocs <https://nacos-sdk-csharp.readthedocs.io/en/latest/>`_
------------
1. [NAMING] 修复 AddNacosV2Naming 没有传递 section 的 bug (#131)
#. [AUTH] 修复请求登录接口过于频繁的 bug (#137)
#. [CORE] 优化 rpc 状态错误的提示语
#. [DOCS] 托管文档网站到 `readthedocs <https://nacos-sdk-csharp.readthedocs.io/en/latest/>`_

View File

@ -0,0 +1,16 @@
v1.2.1 (Oct 7th, 2021) 发布记录
=============================================
1. [CORE] Update ResolveServerInfo (#143 #145)
#. [ALL] Remove old v1 version code (#146 #148)
#. [CONFIG] Fixed overwrite configuration problem when listening multi dataid with same key (#149 #151)
#. [NAMING] Fixed v1 naming subscribe do not trigger OnEvent (#154 #157)
#. [TEST] Add more unit tests
------------
1. [CORE] 更新 ResolveServerInfo 方法 (#143 #145)
#. [ALL] 移除老版本 v1 相关代码 (#146 #148)
#. [CONFIG] 修复同时监听多个 DataId 并且包含相同配置项出现覆盖的问题 (#149 #151)
#. [NAMING] 修复 udp 方式订阅时不触发 OnEvent 的问题 (#154 #157)
#. [TEST] 添加更多的单元测试

View File

@ -0,0 +1,10 @@
v1.2.2 (Nov 7th, 2021) 发布记录
=============================================
1. [NAMING] Improve server push empty pretection (#155)
#. [NAMING] Fixed gzip compression (#161 #162)
------------
1. [NAMING] 优化服务端推空保护 (#155)
#. [NAMING] 修复gzip压缩问题 (#161 #162)

View File

@ -0,0 +1,12 @@
v1.3.0 (Dec 9th, 2021) 发布记录
=============================================
1. [ALL] Support net6 for TargetFrameworks (#164)
#. [NAMING] Support reading nacos server port offset from environment variable (#167)
#. [ALL] remove RequestStream in proto file (#169)
------------
1. [ALL] TargetFrameworks添加net6支持 (#164)
#. [NAMING] 支持从环境变量读取nacos server的端口偏移 (#167)
#. [ALL] 从 proto 文件移除 RequestStream 方法 (#169)

View File

@ -0,0 +1,14 @@
v1.3.1 (Jan 20th, 2022) 发布记录
=============================================
1. [NAMING] Fix ServiceListRequest pageSize error
#. [NAMING] Fix service push when new data lastRefTime lessthan old data lastRefTime
#. [NAMING] Fix judgement for is subscribe services.
#. [CONFIG] Fix thread safe issue of yaml and ini parser.
------------
1. [NAMING] 修复分页请求 pageSize 参数传递问题
#. [NAMING] 修复服务推送时lastRefTime 新数据比老数据的小的情况
#. [NAMING] 修复是否订阅服务的判断
#. [CONFIG] 修复 yaml 和 ini 解析器的线程安全问题

View File

@ -0,0 +1,10 @@
v1.3.2 (Mar 15th, 2022) 发布记录
=============================================
1. [NAMING] Fix QueryInstancesOfService error cluster param (#180 #181)
#. [NAMING] Fix Empty namespace issue (#187 #189)
------------
1. [NAMING] 修复 QueryInstancesOfService 请求参数错误 (#180 #181)
#. [NAMING] 修复空命名空间默认值问题 (#187 #189)

View File

@ -0,0 +1,18 @@
v1.3.3 (May 30th, 2022) 发布记录
=============================================
1. [NAMING] Fix IsSubscribed exception when NamingUseRpc is false (#194 #196)
#. [CONFIG] Fix ReceiveConfigInfo dict get item error in startup (#200 #201)
#. [CONFIG] Improve Microsoft.Extensions.Configuration Integration (#203 #204)
#. [CONFIG] Config cache path from JM.SNAPSHOT.PATH env at first (#205 #206)
#. [CORE] Add package readme file (#207)
#. [CI] Update version of Nacos Server
------------
1. [NAMING] 修复 NamingUseRpc 设置成 false 是 IsSubscribed 抛异常的问题 (#194 #196)
#. [CONFIG] 修复启动时 ReceiveConfigInfo 字典操作异常问题 (#200 #201)
#. [CONFIG] 优化 Microsoft.Extensions.Configuration 的集成 (#203 #204)
#. [CONFIG] 优化配置缓存的路径读取方式 (#205 #206)
#. [CORE] 添加nuget包说明文件 (#207)
#. [CI] 更新 Nacos Server 版本

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.156
# Visual Studio Version 17
VisualStudioVersion = 17.11.35303.130
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C473C3A7-1B44-4E1F-83C0-745AD0566FE9}"
EndProject
@ -31,9 +31,23 @@ 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
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nacos.Microsoft.Extensions.ServiceDiscovery", "src\Nacos.Microsoft.Extensions.ServiceDiscovery\Nacos.Microsoft.Extensions.ServiceDiscovery.csproj", "{46FDA099-A266-4E7B-9B5B-496575A54CCD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -89,6 +103,18 @@ 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
{46FDA099-A266-4E7B-9B5B-496575A54CCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{46FDA099-A266-4E7B-9B5B-496575A54CCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{46FDA099-A266-4E7B-9B5B-496575A54CCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{46FDA099-A266-4E7B-9B5B-496575A54CCD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -106,6 +132,9 @@ 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}
{46FDA099-A266-4E7B-9B5B-496575A54CCD} = {C473C3A7-1B44-4E1F-83C0-745AD0566FE9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A1C5215E-0E70-4C04-B21E-5209BCF32472}

View File

@ -1,19 +1,26 @@
namespace Nacos.IniParser
namespace Nacos.IniParser
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.Extensions.Configuration;
using Nacos.Config;
using Nacos.V2;
public class IniConfigurationStringParser : INacosConfigurationParser
{
public IniConfigurationStringParser()
{
}
private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public static IniConfigurationStringParser Instance = new IniConfigurationStringParser();
public IDictionary<string, string> Parse(string input)
=> new IniConfigurationStringParser().ParseString(input);
public IDictionary<string, string> ParseString(string input)
{
_data.Clear();

View File

@ -2,8 +2,8 @@
<Import Project="../../build/version.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
<PackageId>nacos-sdk-csharp-unofficial.IniParser</PackageId>
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
<PackageId>nacos-sdk-csharp.IniParser</PackageId>
<VersionPrefix>$(NugetVersion)</VersionPrefix>
<VersionSuffix></VersionSuffix>
<Authors>nacos-sdk-csharp Contributors</Authors>
@ -13,6 +13,7 @@
<RepositoryUrl>https://github.com/nacos-group/nacos-sdk-csharp</RepositoryUrl>
<ProjectUrl>https://github.com/nacos-group/nacos-sdk-csharp</ProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>
</PackageReleaseNotes>
</PropertyGroup>
@ -24,10 +25,15 @@
<ItemGroup>
<None Include="../../LICENSE" Pack="true" Visible="false" PackagePath="" />
<None Include="README.md" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">

View File

@ -0,0 +1,21 @@
# nacos-sdk-csharp.IniParser
nacos-sdk-csharp.IniParser provides ini format config parser.
```csharp
builder.Host.UseNacosConfig(section: "NacosConfig", parser: Nacos.IniParser.IniConfigurationStringParser.Instance);
// or
builder.Host.ConfigureAppConfiguration((c, b) =>
{
var config = b.Build();
b.AddNacosV2Configuration(config.GetSection("NacosConfig"), parser: Nacos.IniParser.IniConfigurationStringParser.Instance);
});
```
## Links
* [Documentation](https://nacos-sdk-csharp.readthedocs.io/en/latest/)
* [nacos-sdk-csharp GitHub](https://github.com/nacos-group/nacos-sdk-csharp)

View File

@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../../build/version.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
<PackageId>nacos-sdk-csharp-unofficial.YamlParser</PackageId>
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
<PackageId>nacos-sdk-csharp.YamlParser</PackageId>
<VersionPrefix>$(NugetVersion)</VersionPrefix>
<VersionSuffix></VersionSuffix>
<Authors>nacos-sdk-csharp Contributors</Authors>
@ -13,6 +13,7 @@
<RepositoryUrl>https://github.com/nacos-group/nacos-sdk-csharp</RepositoryUrl>
<ProjectUrl>https://github.com/nacos-group/nacos-sdk-csharp</ProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>
</PackageReleaseNotes>
</PropertyGroup>
@ -24,10 +25,15 @@
<ItemGroup>
<None Include="../../LICENSE" Pack="true" Visible="false" PackagePath="" />
<None Include="README.md" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
@ -35,7 +41,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="YamlDotNet" Version="8.1.2" />
<PackageReference Include="YamlDotNet" Version="11.2.1" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,21 @@
# nacos-sdk-csharp.YamlParser
nacos-sdk-csharp.YamlParser provides yaml/yml format config parser.
```csharp
builder.Host.UseNacosConfig(section: "NacosConfig", parser: Nacos.YamlParser.YamlConfigurationStringParser.Instance);
// or
builder.Host.ConfigureAppConfiguration((c, b) =>
{
var config = b.Build();
b.AddNacosV2Configuration(config.GetSection("NacosConfig"), parser: Nacos.YamlParser.YamlConfigurationStringParser.Instance);
});
```
## Links
* [Documentation](https://nacos-sdk-csharp.readthedocs.io/en/latest/)
* [nacos-sdk-csharp GitHub](https://github.com/nacos-group/nacos-sdk-csharp)

View File

@ -1,7 +1,7 @@
namespace Nacos.YamlParser
{
using Microsoft.Extensions.Configuration;
using Nacos.Config;
using Nacos.V2;
using System;
using System.Collections.Generic;
using System.IO;
@ -10,6 +10,10 @@
public class YamlConfigurationStringParser : INacosConfigurationParser
{
public YamlConfigurationStringParser()
{
}
private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private readonly Stack<string> _context = new Stack<string>();
private string _currentPath;
@ -17,6 +21,9 @@
public static YamlConfigurationStringParser Instance = new YamlConfigurationStringParser();
public IDictionary<string, string> Parse(string input)
=> new YamlConfigurationStringParser().ParseString(input);
private IDictionary<string, string> ParseString(string input)
{
_data.Clear();
_context.Clear();

View File

@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>

View File

@ -9,11 +9,12 @@
[ApiController]
public class ValuesController : ControllerBase
{
private readonly INacosServerManager _serverManager;
// nacos server 1.x and 2.x
private readonly Nacos.V2.INacosNamingService _svc;
public ValuesController(INacosServerManager serverManager)
public ValuesController(Nacos.V2.INacosNamingService svc)
{
_serverManager = serverManager;
_svc = svc;
}
// GET api/values
@ -27,7 +28,12 @@
[HttpGet("test")]
public ActionResult<string> Test()
{
var baseUrl = _serverManager.GetServerAsync("App2").GetAwaiter().GetResult();
var instance = _svc.SelectOneHealthyInstance("App2", "DEFAULT_GROUP").GetAwaiter().GetResult();
var host = $"{instance.Ip}:{instance.Port}";
var baseUrl = instance.Metadata.TryGetValue("secure", out _)
? $"https://{host}"
: $"http://{host}";
if (string.IsNullOrWhiteSpace(baseUrl))
{

View File

@ -1,18 +1,24 @@
namespace App1
using Nacos.AspNetCore.V2;
var builder = WebApplication.CreateBuilder(args);
// nacos server v1.x or v2.x
builder.Services.AddNacosAspNet(builder.Configuration);
builder.Services.AddControllers();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:9876")
.UseStartup<Startup>();
}
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.Run("http://*:9876");

View File

@ -1,39 +0,0 @@
namespace App1
{
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddNacosAspNetCore(Configuration);
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

View File

@ -6,11 +6,28 @@
},
"AllowedHosts": "*",
"nacos": {
"EndPoint": "",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "",
"Namespace": "cs",
"ListenInterval": 1000,
"ServiceName": "App1",
"RegisterEnabled": false
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Ip": "",
"PreferredNetworks": "",
"Port": 0,
"Weight": 100,
"RegisterEnabled": true,
"InstanceEnabled": true,
"Ephemeral": true,
"Secure": false,
"AccessKey": "",
"SecretKey": "",
"UserName": "",
"Password": "",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": ""
}
}

View File

@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>

View File

@ -1,19 +1,19 @@
namespace App2.Controllers
{
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Net.Http;
using Microsoft.AspNetCore.Mvc;
using Nacos.AspNetCore;
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly INacosServerManager _serverManager;
// nacos server 1.x and 2.x
private readonly Nacos.V2.INacosNamingService _svc;
public ValuesController(INacosServerManager serverManager)
public ValuesController(Nacos.V2.INacosNamingService svc)
{
_serverManager = serverManager;
_svc = svc;
}
// GET api/values
@ -27,7 +27,12 @@
[HttpGet("test")]
public ActionResult<string> Test()
{
var baseUrl = _serverManager.GetServerAsync("App1").GetAwaiter().GetResult();
var instance = _svc.SelectOneHealthyInstance("App1", "DEFAULT_GROUP").GetAwaiter().GetResult();
var host = $"{instance.Ip}:{instance.Port}";
var baseUrl = instance.Metadata.TryGetValue("secure", out _)
? $"https://{host}"
: $"http://{host}";
if (string.IsNullOrWhiteSpace(baseUrl))
{

View File

@ -1,18 +1,43 @@
namespace App2
using Nacos.AspNetCore.V2;
var builder = WebApplication.CreateBuilder(args);
// nacos server v1.x or v2.x
builder.Services.AddNacosAspNet(x =>
{
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
x.ServerAddresses = new List<string> { "http://localhost:8848/" };
x.EndPoint = "";
x.Namespace = "cs";
x.ServiceName = "App2";
x.GroupName = "DEFAULT_GROUP";
x.ClusterName = "DEFAULT";
x.Ip = "";
x.PreferredNetworks = "";
x.Port = 0;
x.Weight = 100;
x.RegisterEnabled = true;
x.InstanceEnabled = true;
x.Ephemeral = true;
x.Secure = false;
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
// swich to use http or rpc
x.NamingUseRpc = true;
});
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:9877")
.UseStartup<Startup>();
}
builder.Services.AddControllers();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.Run("http://*:9877");

View File

@ -1,41 +0,0 @@
namespace App2
{
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddNacosAspNetCore(Configuration);
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
/*app.UseNacosAspNetCore();*/
}
}
}

View File

@ -6,11 +6,29 @@
},
"AllowedHosts": "*",
"nacos": {
"EndPoint": "",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "",
"Namespace": "cs",
"ListenInterval": 1000,
"ServiceName": "App2",
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Ip": "",
"PreferredNetworks": "",
"Port": 0,
"Weight": 100,
"RegisterEnabled": true,
"InstanceEnabled": true,
"Ephemeral": true,
"Secure": false,
"AccessKey": "",
"SecretKey": "",
"UserName": "",
"Password": "",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": "",
"Metadata": {
"preserved.register.source": "Test",
"aa": "bb",

View File

@ -1,11 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Nacos.AspNetCore\Nacos.AspNetCore.csproj" />
<ProjectReference Include="..\..\src\Nacos.Microsoft.Extensions.ServiceDiscovery\Nacos.Microsoft.Extensions.ServiceDiscovery.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,122 @@
namespace App3.ConfigFilters
{
using Nacos.V2;
using Nacos.V2.Config.Abst;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class MyNacosConfigFilter : IConfigFilter
{
private static readonly string DefaultKey = "catcherwong00000";
public void DoFilter(IConfigRequest request, IConfigResponse response, IConfigFilterChain filterChain)
{
if (request != null)
{
var encryptedDataKey = DefaultKey;
var raw_content = request.GetParameter(Nacos.V2.Config.ConfigConstants.CONTENT);
var content = AESEncrypt((string)raw_content, encryptedDataKey);
// after encrypt the content, don't forget to update the request!!!
request.PutParameter(Nacos.V2.Config.ConfigConstants.ENCRYPTED_DATA_KEY, encryptedDataKey);
request.PutParameter(Nacos.V2.Config.ConfigConstants.CONTENT, content);
}
if (response != null)
{
var resp_content = response.GetParameter(Nacos.V2.Config.ConfigConstants.CONTENT);
var resp_encryptedDataKey = response.GetParameter(Nacos.V2.Config.ConfigConstants.ENCRYPTED_DATA_KEY);
// nacos 2.0.2 still do not return the encryptedDataKey yet
// but we can use a const key here.
// after nacos server return the encryptedDataKey, we can keep one dataid with one encryptedDataKey
var encryptedDataKey = (resp_encryptedDataKey == null || string.IsNullOrWhiteSpace((string)resp_encryptedDataKey)) ? DefaultKey : (string)resp_encryptedDataKey;
var content = AESDecrypt((string)resp_content, encryptedDataKey);
response.PutParameter(Nacos.V2.Config.ConfigConstants.CONTENT, content);
}
}
public string GetFilterName() => nameof(MyNacosConfigFilter);
public int GetOrder() => 1;
public void Init(NacosSdkOptions options)
{
Console.WriteLine("Assemblies = " + string.Join(",", options.ConfigFilterAssemblies));
Console.WriteLine("Ext Info = " + string.Join(",", options.ConfigFilterExtInfo));
Console.WriteLine("Init");
}
public static string? AESEncrypt(string data, string key)
{
using (MemoryStream memory = new MemoryStream())
{
using (Aes aes = Aes.Create())
{
byte[] plainBytes = Encoding.UTF8.GetBytes(data);
byte[] bKey = new byte[32];
Array.Copy(Encoding.UTF8.GetBytes(key.PadRight(bKey.Length)), bKey, bKey.Length);
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = 256;
aes.Key = bKey;
using (CryptoStream cryptoStream = new CryptoStream(memory, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
try
{
cryptoStream.Write(plainBytes, 0, plainBytes.Length);
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(memory.ToArray());
}
catch (Exception)
{
return null;
}
}
}
}
}
public static string? AESDecrypt(string data, string key)
{
if (string.IsNullOrEmpty(data))
return null;
byte[] encryptedBytes = Convert.FromBase64String(data);
byte[] bKey = new byte[32];
Array.Copy(Encoding.UTF8.GetBytes(key.PadRight(bKey.Length)), bKey, bKey.Length);
using (MemoryStream memory = new MemoryStream(encryptedBytes))
{
using (Aes aes = Aes.Create())
{
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = 256;
aes.Key = bKey;
using (CryptoStream cryptoStream = new CryptoStream(memory, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
try
{
byte[] tmp = new byte[encryptedBytes.Length];
int len = cryptoStream.Read(tmp, 0, encryptedBytes.Length);
byte[] ret = new byte[len];
Array.Copy(tmp, 0, ret, 0, len);
return Encoding.UTF8.GetString(ret, 0, len);
}
catch (Exception)
{
return null;
}
}
}
}
}
}
}

View File

@ -0,0 +1,72 @@
namespace App3.Controllers
{
using Microsoft.AspNetCore.Mvc;
using Nacos.V2;
using System.Threading.Tasks;
[ApiController]
[Route("c")]
public class ConfigController : ControllerBase
{
private readonly INacosConfigService _svc;
public ConfigController(INacosConfigService svc)
{
_svc = svc;
}
// GET c/g?d=123
[HttpGet("g")]
public async Task<string> Get(string d)
{
var res = await _svc.GetConfig(d, "g", 3000).ConfigureAwait(false);
return res ?? "empty config";
}
// GET c/d?d=123
[HttpGet("d")]
public async Task<string> Delete(string d)
{
var res = await _svc.RemoveConfig(d, "g").ConfigureAwait(false);
return "d ok" + res;
}
// GET c/p?d=123
[HttpGet("p")]
public async Task<string> Publish(string d)
{
var res = await _svc.PublishConfig(d, "g", new System.Random().Next(1, 9999999).ToString()).ConfigureAwait(false);
return "p ok" + res;
}
// GET c/al?d=123
[HttpGet("a")]
public async Task<string> Listen(string d)
{
await _svc.AddListener(d, "g", _configListen).ConfigureAwait(false);
return "al ok";
}
// GET c/rl?d=123
[HttpGet("r")]
public async Task<string> UnListen(string d)
{
await _svc.RemoveListener(d, "g", _configListen).ConfigureAwait(false);
return "rl ok";
}
private static CusConfigListen _configListen = new CusConfigListen();
public class CusConfigListen : Nacos.V2.IListener
{
public void ReceiveConfigInfo(string configInfo)
{
System.Console.WriteLine("config cb cb cb " + configInfo);
}
}
}
}

View File

@ -0,0 +1,155 @@
namespace App3.Controllers
{
using Microsoft.AspNetCore.Mvc;
using Nacos.V2.Utils;
using System.Threading.Tasks;
[ApiController]
[Route("n")]
public class NamingController : ControllerBase
{
private readonly Nacos.V2.INacosNamingService _client;
private readonly IHttpClientFactory _httpClientFactory;
public NamingController(Nacos.V2.INacosNamingService client, IHttpClientFactory httpClientFactory)
{
_client = client;
_httpClientFactory = httpClientFactory;
}
// GET n/g
[HttpGet("g")]
public async Task<string> GetAllInstances()
{
var list = await _client.GetAllInstances("mysvc2", false).ConfigureAwait(false);
var res = list.ToJsonString();
return res ?? "GetAllInstances";
}
// GET n/r
[HttpGet("r")]
public async Task<string> RegisterInstance()
{
// await _client.RegisterInstance("mysvc", "127.0.0.1", 9635);
var instance = new Nacos.V2.Naming.Dtos.Instance
{
Ip = "127.0.0.1",
Ephemeral = true,
Port = 9562,
ServiceName = "mysvc2"
};
await _client.RegisterInstance("mysvc2", instance).ConfigureAwait(false);
return "RegisterInstance ok";
}
// GET n/r2
[HttpGet("r2")]
public async Task<string> RegisterInstance2()
{
// await _client.RegisterInstance("mysvc", "127.0.0.1", 9635);
var instance = new Nacos.V2.Naming.Dtos.Instance
{
Ip = "127.0.0.1",
Ephemeral = true,
Port = 9563,
ServiceName = "mysvc2"
};
await _client.RegisterInstance("mysvc2", instance).ConfigureAwait(false);
return "RegisterInstance ok";
}
// GET n/dr
[HttpGet("dr")]
public async Task<string> DeregisterInstance()
{
// await _client.RegisterInstance("mysvc", "127.0.0.1", 9635);
var instance = new Nacos.V2.Naming.Dtos.Instance
{
Ip = "127.0.0.1",
Ephemeral = true,
Port = 9562,
ServiceName = "mysvc2"
};
await _client.DeregisterInstance("mysvc2", instance).ConfigureAwait(false);
return "DeregisterInstance ok";
}
// GET n/si
[HttpGet("si")]
public async Task<string> SelectInstances()
{
var list = await _client.SelectInstances("mysvc2", true, false).ConfigureAwait(false);
var res = list.ToJsonString();
return res ?? "SelectInstances ok";
}
// GET n/gs
[HttpGet("gs")]
public async Task<string> GetServicesOfServer()
{
var list = await _client.GetServicesOfServer(1, 10).ConfigureAwait(false);
var res = list.ToJsonString();
return res ?? "GetServicesOfServer";
}
// GET n/sd
[HttpGet("sd")]
public async Task<string> ServiceDiscovery()
{
var client = _httpClientFactory.CreateClient("app1");
var response = await client.GetAsync("/api/values").ConfigureAwait(false);
var res = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return res;
}
// GET n/sub
[HttpGet("sub")]
public async Task<string> Subscribe()
{
await _client.Subscribe("mysvc2", listener).ConfigureAwait(false);
return "Subscribe";
}
// GET n/unsub
[HttpGet("unsub")]
public async Task<string> Unsubscribe()
{
await _client.Unsubscribe("mysvc2", listener).ConfigureAwait(false);
return "UnSubscribe";
}
// NOTE: MUST keep Subscribe and Unsubscribe to use one instance of the listener!!!
// DO NOT create new instance for each opreation!!!
private static CusListener listener = new CusListener();
public class CusListener : Nacos.V2.IEventListener
{
public Task OnEvent(Nacos.V2.IEvent @event)
{
if (@event is Nacos.V2.Naming.Event.InstancesChangeEvent e)
{
System.Console.WriteLine("CusListener");
System.Console.WriteLine("ServiceName" + e.ServiceName);
System.Console.WriteLine("GroupName" + e.GroupName);
System.Console.WriteLine("Clusters" + e.Clusters);
System.Console.WriteLine("Hosts" + e.Hosts.ToJsonString());
}
return Task.CompletedTask;
}
}
}
}

View File

@ -0,0 +1,65 @@
namespace App3.Controllers
{
using Microsoft.AspNetCore.Mvc;
using Nacos.V2.Utils;
using System.Threading.Tasks;
[ApiController]
[Route("o")]
public class OpenApiController : ControllerBase
{
private readonly Nacos.OpenApi.INacosOpenApi _api;
public OpenApiController(Nacos.OpenApi.INacosOpenApi api)
{
_api = api;
}
// GET o/n-g
[HttpGet("n-g")]
public async Task<string> NamespaceGetAll()
{
var list = await _api.GetNamespacesAsync().ConfigureAwait(false);
var res = list.ToJsonString();
return res ?? "GetAllInstances";
}
// GET o/n-g
[HttpGet("n-c")]
public async Task<string> NamespaceCreate(string i, string n)
{
var flag = await _api.CreateNamespaceAsync(i, n, "").ConfigureAwait(false);
return flag.ToString();
}
// GET o/n-u
[HttpGet("n-u")]
public async Task<string> NamespaceUpdate(string i, string n)
{
var flag = await _api.UpdateNamespaceAsync(i, n, "").ConfigureAwait(false);
return flag.ToString();
}
// GET o/n-u
[HttpGet("n-d")]
public async Task<string> NamespaceDelete(string i)
{
var flag = await _api.DeleteNamespaceAsync(i).ConfigureAwait(false);
return flag.ToString();
}
// GET o/metrics
[HttpGet("metrics")]
public async Task<string> GetMetrics()
{
var flag = await _api.GetMetricsAsync(false).ConfigureAwait(false);
return flag.ToJsonString();
}
}
}

View File

@ -1,46 +0,0 @@
namespace App3.Controllers
{
using Microsoft.AspNetCore.Mvc;
using Nacos.AspNetCore;
using System.Collections.Generic;
using System.Net.Http;
[ApiController]
[Route("[controller]")]
public class ValuesController : ControllerBase
{
private readonly INacosServerManager _serverManager;
public ValuesController(INacosServerManager serverManager)
{
_serverManager = serverManager;
}
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2", "App3" };
}
// GET api/values/test
[HttpGet("test")]
public ActionResult<string> Test()
{
var baseUrl = _serverManager.GetServerAsync("App1").GetAwaiter().GetResult();
if (string.IsNullOrWhiteSpace(baseUrl))
{
return "empty";
}
var url = $"{baseUrl}/api/values";
using (HttpClient client = new HttpClient())
{
var result = client.GetAsync(url).GetAwaiter().GetResult();
return result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
}
}
}
}

View File

@ -1,20 +1,70 @@
namespace App3
using Nacos.V2.DependencyInjection;
using Nacos.OpenApi;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddNacosV2Config(x =>
{
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
x.ServerAddresses = new System.Collections.Generic.List<string> { "http://localhost:8848/" };
x.EndPoint = "";
x.Namespace = "cs";
x.UserName = "nacos";
x.Password = "nacos";
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
// this sample will add the filter to encrypt the config with AES.
x.ConfigFilterAssemblies = new System.Collections.Generic.List<string> { "App3" };
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
// swich to use http or rpc
x.ConfigUseRpc = true;
});
builder.Services.AddNacosV2Naming(x =>
{
x.ServerAddresses = new System.Collections.Generic.List<string> { "http://localhost:8848/" };
x.EndPoint = "";
x.Namespace = "cs";
// swich to use http or rpc
x.NamingUseRpc = true;
});
builder.Services.AddNacosOpenApi(x =>
{
x.ServerAddresses = new System.Collections.Generic.List<string> { "http://localhost:8848/" };
x.EndPoint = "";
x.Namespace = "cs";
});
// Microsoft.Extensions.ServiceDiscovery
builder.Services.AddServiceDiscovery(o =>
{
o.RefreshPeriod = TimeSpan.FromSeconds(60);
})
.AddConfigurationServiceEndpointProvider()
.AddNacosServiceEndpointProvider();
builder.Services.ConfigureHttpClientDefaults(static http =>
{
http.AddServiceDiscovery();
});
// use IHttpClientFactory
builder.Services.AddHttpClient("app1", cfg =>
{
cfg.BaseAddress = new Uri("http://app1");
});
builder.Services.AddControllers();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.MapControllers();
app.Run("http://*:9632");

View File

@ -1,39 +0,0 @@
namespace App3
{
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddNacosAspNetCore(Configuration);
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

View File

@ -1,9 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@ -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>

View File

@ -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");
});
}
}
}

View File

@ -0,0 +1,117 @@
<?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="Newtonsoft.Json" publicKeyToken="30AD4FE6B2A6AEED" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>
</dependentAssembly>
<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>

View File

@ -21,14 +21,35 @@
}
*/
public string Str { get; set; }
/*
{
"ConnectionStrings": {
"Default": "U2VydmVyPTEyNy4wLjAuMTtQb3J0PTMzMDY7RGF0YWJhc2U9ZGVtbztVc2VyIElkPXJvb3Q7UGFzc3dvcmQ9MTIzNDU2Ow=="
},
"version": "测试version",
"AppSettings": {
"Str": "val",
"num": 1,
"arr": [
1,
2,
3
],
"subobj": {
"a": "b"
}
}
}
*/
public string? Str { get; set; }
#pragma warning disable SA1300 // Element should begin with upper-case letter
public int num { get; set; }
public List<int> arr { get; set; }
public List<int>? arr { get; set; }
public SubObj subobj { get; set; }
public SubObj? subobj { get; set; }
#pragma warning restore SA1300 // Element should begin with upper-case letter
}
}

View File

@ -1,12 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,92 @@
namespace MsConfigApp
{
using Nacos.V2;
using Nacos.V2.Config.Abst;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Text;
public class MyNacosConfigFilter : IConfigFilter
{
public void DoFilter(IConfigRequest request, IConfigResponse response, IConfigFilterChain filterChain)
{
if (request != null)
{
var raw_content = request.GetParameter(Nacos.V2.Config.ConfigConstants.CONTENT);
// 部分配置加密后的 content
var content = ReplaceJsonNode((string)raw_content, true);
// after encrypt the content, don't forget to update the request!!!
request.PutParameter(Nacos.V2.Config.ConfigConstants.ENCRYPTED_DATA_KEY, "");
request.PutParameter(Nacos.V2.Config.ConfigConstants.CONTENT, content);
}
if (response != null)
{
var resp_content = response.GetParameter(Nacos.V2.Config.ConfigConstants.CONTENT);
var resp_encryptedDataKey = response.GetParameter(Nacos.V2.Config.ConfigConstants.ENCRYPTED_DATA_KEY);
// nacos 2.0.2 still do not return the encryptedDataKey yet
// but we can use a const key here.
// after nacos server return the encryptedDataKey, we can keep one dataid with one encryptedDataKey
var encryptedDataKey = (resp_encryptedDataKey == null || string.IsNullOrWhiteSpace((string)resp_encryptedDataKey)) ? string.Empty : (string)resp_encryptedDataKey;
var content = ReplaceJsonNode((string)resp_content, false);
response.PutParameter(Nacos.V2.Config.ConfigConstants.CONTENT, content);
}
}
private string ReplaceJsonNode(string src, bool isEnc = true)
{
var jObj = JObject.Parse(src);
if (_jsonPaths != null)
{
foreach (var item in _jsonPaths)
{
var t = jObj.SelectToken(item);
if (t != null)
{
var r = t.ToString();
// 加解密,示例用 base64
var newToken = isEnc
? Convert.ToBase64String(Encoding.UTF8.GetBytes(r))
: Encoding.UTF8.GetString(Convert.FromBase64String(r));
t.Replace(newToken);
}
}
}
Console.WriteLine(jObj.ToString());
return jObj.ToString();
}
public string GetFilterName() => nameof(MyNacosConfigFilter);
public int GetOrder() => 1;
private List<string>? _jsonPaths;
public void Init(NacosSdkOptions options)
{
// 从拓展信息里面获取需要加密的 json path
// 这里只是示例,根据具体情况调整成自己合适的!!!!
var extInfo = JObject.Parse(options.ConfigFilterExtInfo);
if (extInfo.ContainsKey("JsonPaths"))
{
_jsonPaths = extInfo?.GetValue("JsonPaths")?.ToObject<List<string>>();
}
Console.WriteLine("Assemblies = " + string.Join(",", options.ConfigFilterAssemblies));
Console.WriteLine("Ext Info = " + string.Join(",", options.ConfigFilterExtInfo));
Console.WriteLine("Init");
}
}
}

View File

@ -1,84 +1,77 @@
namespace MsConfigApp
using Serilog;
using Serilog.Events;
var outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] {Message}{NewLine}{Exception}";
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.MinimumLevel.Debug()
.WriteTo.Console(
outputTemplate: outputTemplate)
.CreateLogger();
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<MsConfigApp.AppSettings>(builder.Configuration.GetSection("AppSettings"));
builder.Services.AddControllers();
// NOTE: after v1.3.3
// read configuration from config files
// default parser is json
builder.Host.UseNacosConfig(section: "NacosConfig");
// specify ini or yaml parser
// builder.Host.UseNacosConfig(section: "NacosConfig", parser: Nacos.IniParser.IniConfigurationStringParser.Instance);
// builder.Host.UseNacosConfig(section: "NacosConfig", parser: Nacos.YamlParser.YamlConfigurationStringParser.Instance);
/*
NOTE: before v1.3.3
builder.Host.ConfigureAppConfiguration((c, b) =>
{
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
var config = b.Build();
public class Program
{
public static void Main(string[] args)
{
var outputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] {Message}{NewLine}{Exception}";
// read configuration from config files
// default is json
// b.AddNacosV2Configuration(config.GetSection("NacosConfig"));
b.AddNacosV2Configuration(config.GetSection("NacosConfig"));
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.MinimumLevel.Debug()
.WriteTo.Console(
outputTemplate: outputTemplate)
/*.WriteTo.File(
path: "logs/ApiTpl.log",
outputTemplate: outputTemplate,
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 5,
encoding: System.Text.Encoding.UTF8)*/
.CreateLogger();
// specify ini or yaml
b.AddNacosV2Configuration(config.GetSection("NacosConfig"), parser: Nacos.IniParser.IniConfigurationStringParser.Instance);
b.AddNacosV2Configuration(config.GetSection("NacosConfig"), parser: Nacos.YamlParser.YamlConfigurationStringParser.Instance);
});
*/
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
builder.Host.UseSerilog();
try
{
Log.ForContext<Program>().Information("Application starting...");
CreateHostBuilder(args).Build().Run();
}
catch (System.Exception ex)
{
Log.ForContext<Program>().Fatal(ex, "Application start-up failed!!");
}
finally
{
Log.CloseAndFlush();
}
}
var app = builder.Build();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
var c = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
var dataId = c.GetValue<string>("NacosConfig:DataId");
var group = c.GetValue<string>("NacosConfig:Group");
var tenant = c.GetValue<string>("NacosConfig:Tenant");
var optional = c.GetValue<bool>("NacosConfig:Optional");
var serverAddresses = c.GetSection("NacosConfig:ServerAddresses").Get<List<string>>();
app.UseRouting();
// read configuration from config files
// default is json
builder.AddNacosConfiguration(c.GetSection("NacosConfig"));
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
// specify ini or yaml
// builder.AddNacosConfiguration(c.GetSection("NacosConfig"), Nacos.IniParser.IniConfigurationStringParser.Instance);
// builder.AddNacosConfiguration(c.GetSection("NacosConfig"), Nacos.YamlParser.YamlConfigurationStringParser.Instance);
// hard code here
/*builder.AddNacosConfiguration(x =>
{
x.DataId = dataId;
x.Group = group;
x.Tenant = tenant;
x.Optional = optional;
x.ServerAddresses = serverAddresses;
});*/
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseSerilog();
}
}
try
{
Log.ForContext<Program>().Information("Application starting...");
app.Run("http://*:8787");
}
catch (Exception ex)
{
Log.ForContext<Program>().Fatal(ex, "Application start-up failed!!");
}
finally
{
Log.CloseAndFlush();
}

View File

@ -1,4 +1,4 @@
# MsConfigApp
# MsConfigApp
This sample shows how to integrate ASP.NET Core Configuration System.
@ -37,7 +37,9 @@ https://nacos.io/en-us/docs/quick-start-docker.html
"Password": "123456",
"AccessKey": "",
"SecretKey": "",
"EndPoint": "acm.aliyun.com"
"EndPoint": "acm.aliyun.com",
"ConfigFilterAssemblies": [ "MsConfigApp" ],
"ConfigFilterExtInfo": "{\"JsonPaths\":[\"ConnectionStrings.Default\"],\"Other\":\"xxxxxx\"}"
}
}
```
@ -69,10 +71,30 @@ The first one, its dataid is demo, group is DFAULT_GROUP and the value is as fol
}
```
> NOTE: If **ConfigFilterAssemblies** is not empty, using the following config value.
```JSON
{
"ConnectionStrings": {
"Default": "U2VydmVyPTEyNy4wLjAuMTtQb3J0PTMzMDY7RGF0YWJhc2U9ZGVtbztVc2VyIElkPXJvb3Q7UGFzc3dvcmQ9MTIzNDU2Ow=="
},
"version": "测试version",
"AppSettings": {
"Str": "val",
"num": 1,
"arr": [1, 2, 3],
"subobj": {
"a": "b"
}
}
}
```
The second one, its dataid is common, group is DFAULT_GROUP and the value is as following.
```JSON
{
"all": "test"
}
```
```

View File

@ -1,41 +0,0 @@
namespace MsConfigApp
{
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

View File

@ -3,7 +3,7 @@
public class SubObj
{
#pragma warning disable SA1300 // Element should begin with upper-case letter
public string a { get; set; }
public string? a { get; set; }
#pragma warning restore SA1300 // Element should begin with upper-case letter
}
}

View File

@ -1,26 +1,26 @@
{
{
"NacosConfig": {
"Listeners": [
{
"Optional": false,
"DataId": "common",
"Group": ""
"Group": "DEFAULT_GROUP"
},
{
"Optional": false,
"DataId": "demo",
"Group": ""
"Group": "DEFAULT_GROUP"
}
],
"Optional": false,
"DataId": "demo",
"Group": "group1",
"Tenant": "9a760099-7724-4505-bb3d-e80028d53b35",
"Namespace": "cs",
"ServerAddresses": [ "http://localhost:8848/" ],
"UserName": "test2",
"Password": "123456",
"UserName": "",
"Password": "",
"AccessKey": "",
"SecretKey": "",
"EndPoint": "acm.aliyun.com"
"EndPoint": "acm.aliyun.com",
"ConfigFilterAssemblies": [ "MsConfigApp" ],
"ConfigFilterExtInfo": "{\"JsonPaths\":[\"ConnectionStrings.Default\"],\"Other\":\"xxxxxx\"}"
}
}
}

View File

@ -1,110 +0,0 @@
namespace Nacos.AspNetCore
{
using System.Collections.Generic;
using System.Threading.Tasks;
public interface INacosServerManager
{
/// <summary>
/// Get the server URL with specify load balance strategy.
/// </summary>
/// <param name="serviceName">service name</param>
/// <returns>A URL string</returns>
Task<string> GetServerAsync(string serviceName);
/// <summary>
/// Get the server URL with specify load balance strategy.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <returns>A URL string</returns>
Task<string> GetServerAsync(string serviceName, string groupName);
/// <summary>
/// Get the server URL with specify load balance strategy.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <param name="clusters">clusters</param>
/// <returns>A URL string</returns>
Task<string> GetServerAsync(string serviceName, string groupName, string clusters);
/// <summary>
/// Get the server URL with specify load balance strategy.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <param name="clusters">clusters</param>
/// <param name="namespaceId">namespace id</param>
/// <returns>A URL string</returns>
Task<string> GetServerAsync(string serviceName, string groupName, string clusters, string namespaceId);
/// <summary>
/// Get the HOST information with specify load balance strategy.
/// </summary>
/// <param name="serviceName">service name</param>
/// <returns>The HOST information</returns>
Task<Host> GetServerInfoAsync(string serviceName);
/// <summary>
/// Get the HOST information with specify load balance strategy.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <returns>The HOST information</returns>
Task<Host> GetServerInfoAsync(string serviceName, string groupName);
/// <summary>
/// Get the HOST information with specify load balance strategy.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <param name="clusters">clusters</param>
/// <returns>The HOST information</returns>
Task<Host> GetServerInfoAsync(string serviceName, string groupName, string clusters);
/// <summary>
/// Get the HOST information with specify load balance strategy.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <param name="clusters">clusters</param>
/// <param name="namespaceId">namespace id</param>
/// <returns>The HOST information</returns>
Task<Host> GetServerInfoAsync(string serviceName, string groupName, string clusters, string namespaceId);
/// <summary>
/// Get a list of HOST information.
/// </summary>
/// <param name="serviceName">service name</param>
/// <returns>A list of HOST information</returns>
Task<List<Host>> GetServerListAsync(string serviceName);
/// <summary>
/// Get a list of HOST information.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <returns>A list of HOST information</returns>
Task<List<Host>> GetServerListAsync(string serviceName, string groupName);
/// <summary>
/// Get a list of HOST information.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <param name="clusters">clusters</param>
/// <returns>A list of HOST information</returns>
Task<List<Host>> GetServerListAsync(string serviceName, string groupName, string clusters);
/// <summary>
/// Get a list of HOST information.
/// </summary>
/// <param name="serviceName">service name</param>
/// <param name="groupName">group name</param>
/// <param name="clusters">clusters</param>
/// <param name="namespaceId">namespace id</param>
/// <returns>A list of HOST information</returns>
Task<List<Host>> GetServerListAsync(string serviceName, string groupName, string clusters, string namespaceId);
}
}

View File

@ -1,19 +0,0 @@
namespace Nacos.AspNetCore
{
using System.Collections.Generic;
public interface ILBStrategy
{
/// <summary>
/// Strategy Name
/// </summary>
LBStrategyName Name { get; }
/// <summary>
/// Get host
/// </summary>
/// <param name="list">host list</param>
/// <returns>The Host</returns>
Host GetHost(List<Host> list);
}
}

View File

@ -1,20 +0,0 @@
namespace Nacos.AspNetCore
{
public enum LBStrategyName
{
/// <summary>
/// Weight Round Robin
/// </summary>
WeightRoundRobin,
/// <summary>
/// Weight Random
/// </summary>
WeightRandom,
/// <summary>
/// Ext1
/// </summary>
Ext1
}
}

View File

@ -1,9 +0,0 @@
namespace Nacos.AspNetCore
{
public class LbKv
{
public string InstanceId { get; set; }
public double Weight { get; set; }
}
}

View File

@ -1,71 +0,0 @@
namespace Nacos.AspNetCore
{
using Nacos;
using System;
using System.Collections.Generic;
using System.Linq;
public class WeightRandomLBStrategy : ILBStrategy
{
public LBStrategyName Name => LBStrategyName.WeightRandom;
public Host GetHost(List<Host> list)
{
var dict = BuildScore(list);
Host instance = null;
var rd = new Random().NextDouble();
foreach (var item in dict)
{
if (item.Value >= rd)
{
instance = list.FirstOrDefault(x => x.InstanceId.Equals(item.Key));
if (instance == null)
{
var arr = item.Key.Split("#");
var ip = arr[0];
int.TryParse(arr[1], out var port);
var cluster = arr[2];
instance = list.First(x => x.Ip.Equals(ip) && x.Port == port && x.ClusterName.Equals(cluster));
}
break;
}
}
return instance;
}
private Dictionary<string, double> BuildScore(List<Host> list)
{
var dict = new Dictionary<string, double>();
var tmp = list.Select(x => new LbKv
{
// aliyun sae, the instanceid returns empty string
// when the instanceid is empty, create a new one, but the group was missed.
InstanceId = string.IsNullOrWhiteSpace(x.InstanceId) ? $"{x.Ip}#{x.Port}#{x.ClusterName}#{x.ServiceName}" : x.InstanceId,
Weight = x.Weight
}).GroupBy(x => x.InstanceId).Select(x => new LbKv
{
InstanceId = x.Key,
Weight = x.Max(y => y.Weight)
}).ToList();
var total = tmp.Sum(x => x.Weight);
var cur = 0d;
foreach (var item in tmp)
{
cur += item.Weight;
dict.TryAdd(item.InstanceId, cur / total);
}
return dict;
}
}
}

View File

@ -1,70 +0,0 @@
namespace Nacos.AspNetCore
{
using Nacos;
using System;
using System.Collections.Generic;
using System.Linq;
public class WeightRoundRobinLBStrategy : ILBStrategy
{
public LBStrategyName Name => LBStrategyName.WeightRoundRobin;
private int _pos;
private static object obj = new object();
public Host GetHost(List<Host> list)
{
var tmp = list.Select(x => new LbKv
{
// aliyun sae, the instanceid returns empty string
// when the instanceid is empty, create a new one, but the group was missed.
InstanceId = string.IsNullOrWhiteSpace(x.InstanceId) ? $"{x.Ip}#{x.Port}#{x.ClusterName}#{x.ServiceName}" : x.InstanceId,
Weight = x.Weight
}).GroupBy(x => x.InstanceId).Select(x => new LbKv
{
InstanceId = x.Key,
Weight = x.Max(y => y.Weight)
}).ToList();
// <instanceid, weight>
var dic = tmp.ToDictionary(k => k.InstanceId, v => (int)v.Weight);
var srcInstanceIdList = dic.Keys.ToList();
var tagInstanceIdList = new List<string>();
foreach (var item in srcInstanceIdList)
{
dic.TryGetValue(item, out var weight);
for (int i = 0; i < weight; i++)
tagInstanceIdList.Add(item);
}
var instanceId = string.Empty;
lock (obj)
{
if (_pos >= tagInstanceIdList.Count)
_pos = 0;
instanceId = tagInstanceIdList[_pos];
_pos++;
}
var instance = list.FirstOrDefault(x => x.InstanceId.Equals(instanceId));
if (instance == null)
{
var arr = instanceId.Split("#");
var ip = arr[0];
int.TryParse(arr[1], out var port);
var cluster = arr[2];
instance = list.First(x => x.Ip.Equals(ip) && x.Port == port && x.ClusterName.Equals(cluster));
}
return instance;
}
}
}

View File

@ -2,8 +2,8 @@
<Import Project="../../build/version.props" />
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
<PackageId>nacos-sdk-csharp-unofficial.AspNetCore</PackageId>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<PackageId>nacos-sdk-csharp.AspNetCore</PackageId>
<VersionPrefix>$(NugetVersion)</VersionPrefix>
<VersionSuffix></VersionSuffix>
<Authors>nacos-sdk-csharp Contributors</Authors>
@ -13,7 +13,8 @@
<RepositoryUrl>https://github.com/nacos-group/nacos-sdk-csharp</RepositoryUrl>
<ProjectUrl>https://github.com/nacos-group/nacos-sdk-csharp</ProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageReleaseNotes>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>
</PackageReleaseNotes>
</PropertyGroup>
@ -28,17 +29,21 @@
<ItemGroup>
<None Include="../../LICENSE" Pack="true" Visible="false" PackagePath="" />
<None Include="README.md" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
<PackageReference Include="EasyCaching.InMemory" Version="0.8.9" />
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.0" />
<PackageReference Include="EasyCaching.InMemory" Version="0.8.9" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>

View File

@ -1,141 +0,0 @@
namespace Nacos.AspNetCore
{
using EasyCaching.Core;
using Microsoft.Extensions.Options;
using Nacos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public class NacosServerManager : INacosServerManager
{
private readonly INacosNamingClient _client;
private readonly IEasyCachingProvider _provider;
private readonly ILBStrategy _strategy;
public NacosServerManager(
INacosNamingClient client,
IEasyCachingProviderFactory factory,
IEnumerable<ILBStrategy> strategies,
IOptions<NacosAspNetCoreOptions> optionsAccs)
{
_client = client;
_provider = factory.GetCachingProvider("nacos.aspnetcore");
_strategy = strategies.FirstOrDefault(x => x.Name.ToString().Equals(optionsAccs.Value.LBStrategy, StringComparison.OrdinalIgnoreCase))
?? new WeightRandomLBStrategy();
}
public async Task<string> GetServerAsync(string serviceName)
{
return await GetUrlAsync(serviceName, null, null, null);
}
public async Task<string> GetServerAsync(string serviceName, string groupName)
{
return await GetUrlAsync(serviceName, groupName, null, null);
}
public async Task<string> GetServerAsync(string serviceName, string groupName, string clusters)
{
return await GetUrlAsync(serviceName, groupName, clusters, null);
}
public async Task<string> GetServerAsync(string serviceName, string groupName, string clusters, string namespaceId)
{
return await GetUrlAsync(serviceName, groupName, clusters, namespaceId);
}
public async Task<List<Host>> GetServerListAsync(string serviceName)
{
return await GetServerListInnerAsync(serviceName, null, null, null);
}
public async Task<List<Host>> GetServerListAsync(string serviceName, string groupName)
{
return await GetServerListInnerAsync(serviceName, groupName, null, null);
}
public async Task<List<Host>> GetServerListAsync(string serviceName, string groupName, string clusters)
{
return await GetServerListInnerAsync(serviceName, groupName, clusters, null);
}
public async Task<List<Host>> GetServerListAsync(string serviceName, string groupName, string clusters, string namespaceId)
{
return await GetServerListInnerAsync(serviceName, groupName, clusters, namespaceId);
}
public async Task<Host> GetServerInfoAsync(string serviceName)
{
return await GetHostAsync(serviceName, null, null, null);
}
public async Task<Host> GetServerInfoAsync(string serviceName, string groupName)
{
return await GetHostAsync(serviceName, groupName, null, null);
}
public async Task<Host> GetServerInfoAsync(string serviceName, string groupName, string clusters)
{
return await GetHostAsync(serviceName, groupName, clusters, null);
}
public async Task<Host> GetServerInfoAsync(string serviceName, string groupName, string clusters, string namespaceId)
{
return await GetHostAsync(serviceName, groupName, clusters, namespaceId);
}
private async Task<List<Host>> GetServerListInnerAsync(string serviceName, string groupName, string clusters, string namespaceId)
{
var cachedKey = $"{serviceName}-{groupName}-{clusters}-{namespaceId}";
var cached = await _provider.GetAsync(cachedKey, async () =>
{
var serviceInstances = await _client.ListInstancesAsync(new ListInstancesRequest
{
ServiceName = serviceName,
GroupName = groupName,
Clusters = clusters,
NamespaceId = namespaceId,
HealthyOnly = true,
});
if (serviceInstances?.Hosts == null || !serviceInstances.Hosts.Any())
return null;
return serviceInstances.Hosts.ToList();
}, TimeSpan.FromSeconds(8));
return cached.HasValue ? cached.Value : null;
}
private async Task<string> GetUrlAsync(string serviceName, string groupName, string clusters, string namespaceId)
{
var list = await GetServerListInnerAsync(serviceName, groupName, clusters, namespaceId);
if (list != null && list.Any())
{
var host = _strategy.GetHost(list);
// it seems that nacos don't return the scheme
// so here use http only.
return $"http://{host.Ip}:{host.Port}";
}
return null;
}
private async Task<Host> GetHostAsync(string serviceName, string groupName, string clusters, string namespaceId)
{
var list = await GetServerListInnerAsync(serviceName, groupName, clusters, namespaceId);
if (list != null && list.Any())
{
var host = _strategy.GetHost(list);
return host;
}
return null;
}
}
}

View File

@ -0,0 +1,31 @@
# nacos-sdk-csharp.AspNetCore
nacos-sdk-csharp.AspNetCore provides service registration and discovery With ASP.NET Core.
```csharp
builder.Services.AddNacosAspNet(x =>
{
x.ServerAddresses = new List<string> { "http://localhost:8848/" };
x.Namespace = "cs";
x.ServiceName = "App2";
x.GroupName = "DEFAULT_GROUP";
x.ClusterName = "DEFAULT";
x.Ip = "";
x.PreferredNetworks = "";
x.Port = 0;
x.Weight = 100;
x.RegisterEnabled = true;
x.InstanceEnabled = true;
x.Ephemeral = true;
x.Secure = false;
});
// or
builder.Services.AddNacosAspNet(builder.Configuration);
```
## Links
* [Documentation](https://nacos-sdk-csharp.readthedocs.io/en/latest/)
* [nacos-sdk-csharp GitHub](https://github.com/nacos-group/nacos-sdk-csharp)

View File

@ -1,88 +0,0 @@
namespace Microsoft.AspNetCore.Builder
{
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Nacos;
using Nacos.AspNetCore;
using System;
public static class ServiceCollectionExtensions
{
/// <summary>
/// Add Nacos AspNetCore.
/// </summary>
/// <param name="services">services.</param>
/// <param name="configuration">configuration</param>
/// <returns>IServiceCollection</returns>
public static IServiceCollection AddNacosAspNetCore(
this IServiceCollection services,
IConfiguration configuration)
{
services.Configure<NacosAspNetCoreOptions>(configuration.GetSection("nacos"));
// services.AddNacos(configuration);
services.AddNacosNaming(configuration);
services.AddEasyCaching(options =>
{
options.UseInMemory(
config =>
{
config.MaxRdSecond = 0;
}, "nacos.aspnetcore");
});
services.TryAddSingleton<INacosServerManager, NacosServerManager>();
// load balance strategies
services.AddSingleton<ILBStrategy, WeightRandomLBStrategy>();
services.AddSingleton<ILBStrategy, WeightRoundRobinLBStrategy>();
// IHostedService, report instance status
services.AddHostedService<StatusReportBgTask>();
return services;
}
/// <summary>
/// Add Nacos AspNetCore.
/// </summary>
/// <param name="services">services.</param>
/// <param name="nacosAspNetCoreOptions">nacosAspNetCoreOptions.</param>
/// <param name="nacosOptions">nacosOptions</param>
/// <returns>IServiceCollection</returns>
public static IServiceCollection AddNacosAspNetCore(
this IServiceCollection services,
Action<NacosAspNetCoreOptions> nacosAspNetCoreOptions,
Action<NacosOptions> nacosOptions)
{
services.Configure(nacosAspNetCoreOptions);
services.AddNacosNaming(nacosOptions);
services.AddEasyCaching(options =>
{
options.UseInMemory(
config =>
{
config.MaxRdSecond = 0;
}, "nacos.aspnetcore");
});
services.TryAddSingleton<INacosServerManager, NacosServerManager>();
// load balance strategies
services.AddSingleton<ILBStrategy, WeightRandomLBStrategy>();
services.AddSingleton<ILBStrategy, WeightRoundRobinLBStrategy>();
services.AddSingleton<ILocalConfigInfoProcessor, MemoryLocalConfigInfoProcessor>();
services.TryAddSingleton<Nacos.Config.Http.IHttpAgent, Nacos.Config.Http.ServerHttpAgent>();
services.AddSingleton<INacosConfigClient, NacosConfigClient>();
// IHostedService, report instance status
services.AddHostedService<StatusReportBgTask>();
return services;
}
}
}

View File

@ -1,167 +0,0 @@
namespace Nacos.AspNetCore
{
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class StatusReportBgTask : IHostedService, IDisposable
{
private readonly ILogger _logger;
private readonly INacosNamingClient _client;
private readonly IFeatureCollection _features;
private NacosAspNetCoreOptions _options;
private Timer _timer;
private bool _reporting;
private IEnumerable<Uri> uris = null;
private List<SendHeartbeatRequest> beatRequests = new List<SendHeartbeatRequest>();
public StatusReportBgTask(
ILoggerFactory loggerFactory,
INacosNamingClient client,
IServer server,
IOptionsMonitor<NacosAspNetCoreOptions> optionsAccs)
{
_logger = loggerFactory.CreateLogger<StatusReportBgTask>();
_client = client;
_options = optionsAccs.CurrentValue;
_features = server.Features;
}
public Task StartAsync(CancellationToken cancellationToken)
{
if (!_options.RegisterEnabled)
{
_logger.LogInformation("setting RegisterEnabled to false, will not register to nacos");
return Task.CompletedTask;
}
uris = UriTool.GetUri(_features, _options);
foreach (var uri in uris)
{
_logger.LogInformation("Report instance ({0}:{1}) status....", uri.Host, uri.Port);
var metadata = new Dictionary<string, string>()
{
{ PreservedMetadataKeys.REGISTER_SOURCE, "ASPNET_CORE" }
};
foreach (var item in _options.Metadata)
{
if (!metadata.ContainsKey(item.Key))
{
metadata.TryAdd(item.Key, item.Value);
}
}
var beatRequest = new SendHeartbeatRequest
{
Ephemeral = true,
ServiceName = _options.ServiceName,
GroupName = _options.GroupName,
BeatInfo = new BeatInfo
{
ip = uri.Host,
port = uri.Port,
serviceName = _options.ServiceName,
scheduled = true,
weight = _options.Weight,
cluster = _options.ClusterName,
metadata = metadata,
},
NameSpaceId = _options.Namespace
};
beatRequests.Add(beatRequest);
}
_timer = new Timer(
async x =>
{
if (_reporting)
{
_logger.LogInformation($"Latest manipulation is still working ...");
return;
}
_reporting = true;
await ReportAsync();
_reporting = false;
}, null, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(10));
return Task.CompletedTask;
}
private async Task ReportAsync()
{
foreach (var beatRequest in beatRequests)
{
bool flag = false;
try
{
// send heart beat will register instance
flag = await _client.SendHeartbeatAsync(beatRequest);
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"{beatRequest.BeatInfo.ip}:{beatRequest.BeatInfo.port} Send heart beat to Nacos error");
}
_logger.LogDebug("host = {0} report at {1}, status = {2}", $"{beatRequest.BeatInfo.ip}:{beatRequest.BeatInfo.port}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), flag);
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (_options.RegisterEnabled)
{
_logger.LogWarning("Unregistering from Nacos, serviceName={0}", _options.ServiceName);
foreach (var uri in uris)
{
var removeRequest = new RemoveInstanceRequest
{
ServiceName = _options.ServiceName,
Ip = uri.Host,
Port = uri.Port,
GroupName = _options.GroupName,
NamespaceId = _options.Namespace,
ClusterName = _options.ClusterName,
Ephemeral = true
};
for (int i = 0; i < 3; i++)
{
try
{
_logger.LogWarning("begin to remove instance, {0}", JsonConvert.SerializeObject(removeRequest));
var flag = await _client.RemoveInstanceAsync(removeRequest);
_logger.LogWarning("remove instance, status = {0}", flag);
break;
}
catch (Exception ex)
{
_logger.LogError(ex, "Unregistering error, count = {0}", i + 1);
}
}
}
_timer?.Change(Timeout.Infinite, 0);
}
}
public void Dispose()
{
_timer?.Dispose();
}
}
}

View File

@ -1,145 +1,174 @@
namespace Nacos.AspNetCore
{
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
internal static class UriTool
{
public static IEnumerable<Uri> GetUri(IFeatureCollection features, NacosAspNetCoreOptions config)
{
var splitChars = new char[] { ',', ';' };
var port = config.Port <= 0 ? 80 : config.Port;
// 1. config
if (!string.IsNullOrWhiteSpace(config.Ip))
{
// it seems that nacos don't return the scheme
// so here use http only.
return new List<Uri> { new Uri($"http://{config.Ip}:{port}") };
}
// 1.1. Ip is null && Port has value
if (string.IsNullOrWhiteSpace(config.Ip) && port != 80)
{
return new List<Uri> { new Uri($"http://{GetCurrentIp(config.PreferredNetworks)}:{port}") };
}
var address = string.Empty;
// 2. IServerAddressesFeature
if (features != null)
{
var addresses = features.Get<IServerAddressesFeature>();
var addressCollection = addresses?.Addresses;
if (addressCollection != null && addressCollection.Any())
{
var uris = new List<Uri>();
foreach (var item in addressCollection)
{
var url = ReplaceAddress(item, config.PreferredNetworks);
uris.Add(new Uri(url));
}
return uris;
}
}
// 3. ASPNETCORE_URLS
address = Environment.GetEnvironmentVariable("ASPNETCORE_URLS");
if (!string.IsNullOrWhiteSpace(address))
{
var url = ReplaceAddress(address, config.PreferredNetworks);
return url.Split(splitChars).Select(x => new Uri(x));
}
// 4. --urls
var cmdArgs = Environment.GetCommandLineArgs();
if (cmdArgs != null && cmdArgs.Any())
{
var cmd = cmdArgs.FirstOrDefault(x => x.StartsWith("--urls", StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(cmd))
{
address = cmd.Split('=')[1];
var url = ReplaceAddress(address, config.PreferredNetworks);
return url.Split(splitChars).Select(x => new Uri(x));
}
}
// 5. current ip address third
address = $"http://{GetCurrentIp(config.PreferredNetworks)}:{port}";
return new List<Uri> { new Uri(address) };
}
private static string ReplaceAddress(string address, string preferredNetworks)
{
var ip = GetCurrentIp(preferredNetworks);
if (address.Contains("*"))
{
address = address.Replace("*", ip);
}
else if (address.Contains("+"))
{
address = address.Replace("+", ip);
}
else if (address.Contains("localhost", StringComparison.OrdinalIgnoreCase))
{
address = address.Replace("localhost", ip, StringComparison.OrdinalIgnoreCase);
}
else if (address.Contains("0.0.0.0", StringComparison.OrdinalIgnoreCase))
{
address = address.Replace("0.0.0.0", ip, StringComparison.OrdinalIgnoreCase);
}
return address;
}
private static string GetCurrentIp(string preferredNetworks)
{
var instanceIp = "127.0.0.1";
try
{
// 获取可用网卡
var nics = NetworkInterface.GetAllNetworkInterfaces()?.Where(network => network.OperationalStatus == OperationalStatus.Up);
// 获取所有可用网卡IP信息
var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses);
foreach (var ipadd in ipCollection)
{
if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork)
{
if (string.IsNullOrEmpty(preferredNetworks))
{
instanceIp = ipadd.Address.ToString();
break;
}
if (!ipadd.Address.ToString().StartsWith(preferredNetworks)) continue;
instanceIp = ipadd.Address.ToString();
break;
}
}
}
catch
{
// ignored
}
return instanceIp;
}
}
}
using System.Text.RegularExpressions;
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Nacos.AspNetCore.Tests")]
namespace Nacos.AspNetCore
{
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
internal static class UriTool
{
public static IEnumerable<Uri> GetUri(IFeatureCollection features, string ip, int port, string preferredNetworks)
{
var splitChars = new char[] { ',', ';' };
var appPort = port <= 0 ? 80 : port;
// 1. config
if (!string.IsNullOrWhiteSpace(ip))
{
// it seems that nacos don't return the scheme
// so here use http only.
return new List<Uri> { new Uri($"http://{ip}:{appPort}") };
}
// 1.1. Ip is null && Port has value
if (string.IsNullOrWhiteSpace(ip) && appPort != 80)
{
return new List<Uri> { new Uri($"http://{GetCurrentIp(preferredNetworks)}:{appPort}") };
}
var address = string.Empty;
// 2. IServerAddressesFeature
if (features != null)
{
var addresses = features.Get<IServerAddressesFeature>();
var addressCollection = addresses?.Addresses;
if (addressCollection != null && addressCollection.Any())
{
var uris = new List<Uri>();
foreach (var item in addressCollection)
{
var url = ReplaceAddress(item, preferredNetworks);
uris.Add(new Uri(url));
}
return uris;
}
}
// 3. ASPNETCORE_URLS
address = Environment.GetEnvironmentVariable("ASPNETCORE_URLS");
if (!string.IsNullOrWhiteSpace(address))
{
var url = ReplaceAddress(address, preferredNetworks);
var uris = url.Split(splitChars).Select(x => new Uri(x));
foreach (var item in uris)
{
if (!IPAddress.TryParse(item.Host, out _))
{
throw new Nacos.V2.Exceptions.NacosException("Invalid ip address from ASPNETCORE_URLS");
}
}
return uris;
}
// 4. --urls
var cmdArgs = Environment.GetCommandLineArgs();
if (cmdArgs != null && cmdArgs.Any())
{
var cmd = cmdArgs.FirstOrDefault(x => x.StartsWith("--urls", StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(cmd))
{
address = cmd.Split('=')[1];
var url = ReplaceAddress(address, preferredNetworks);
var uris = url.Split(splitChars).Select(x => new Uri(x));
foreach (var item in uris)
{
if (!IPAddress.TryParse(item.Host, out _))
{
throw new Nacos.V2.Exceptions.NacosException("Invalid ip address from --urls");
}
}
return uris;
}
}
// 5. current ip address third
address = $"http://{GetCurrentIp(preferredNetworks)}:{appPort}";
return new List<Uri> { new Uri(address) };
}
private static string ReplaceAddress(string address, string preferredNetworks)
{
var ip = GetCurrentIp(preferredNetworks);
if (address.Contains("*"))
{
address = address.Replace("*", ip);
}
else if (address.Contains("+"))
{
address = address.Replace("+", ip);
}
else if (address.Contains("localhost", StringComparison.OrdinalIgnoreCase))
{
address = address.Replace("localhost", ip, StringComparison.OrdinalIgnoreCase);
}
else if (address.Contains("0.0.0.0", StringComparison.OrdinalIgnoreCase))
{
address = address.Replace("0.0.0.0", ip, StringComparison.OrdinalIgnoreCase);
}
return address;
}
private static string GetCurrentIp(string preferredNetworks)
{
var instanceIp = "127.0.0.1";
try
{
// 获取可用网卡
var nics = NetworkInterface.GetAllNetworkInterfaces()?.Where(network => network.OperationalStatus == OperationalStatus.Up);
// 获取所有可用网卡IP信息
var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses);
var preferredNetworksArr = string.IsNullOrEmpty(preferredNetworks)
? new string[0] : preferredNetworks.Split(",");
foreach (var ipadd in ipCollection)
{
if (!IPAddress.IsLoopback(ipadd.Address) &&
ipadd.Address.AddressFamily == AddressFamily.InterNetwork)
{
if (string.IsNullOrEmpty(preferredNetworks))
{
instanceIp = ipadd.Address.ToString();
break;
}
if (!preferredNetworksArr.Any(preferredNetwork =>
ipadd.Address.ToString().StartsWith(preferredNetwork)
|| Regex.IsMatch(ipadd.Address.ToString(), preferredNetwork))) continue;
instanceIp = ipadd.Address.ToString();
break;
}
}
}
catch
{
// ignored
}
return instanceIp;
}
}
}

View File

@ -1,47 +1,25 @@
namespace Nacos.AspNetCore
namespace Nacos.AspNetCore.V2
{
using Nacos.V2;
using System.Collections.Generic;
public class NacosAspNetCoreOptions
public class NacosAspNetOptions : NacosSdkOptions
{
/// <summary>
/// nacos server addresses.
/// </summary>
/// <example>
/// http://10.1.12.123:8848,https://10.1.12.124:8848
/// </example>
public List<string> ServerAddresses { get; set; }
/// <summary>
/// default timeout, unit is Milliseconds.
/// </summary>
public int DefaultTimeOut { get; set; } = 15000;
/// <summary>
/// default namespace
/// </summary>
public string Namespace { get; set; } = "";
/// <summary>
/// the name of the service.
/// </summary>
public string ServiceName { get; set; }
/// <summary>
/// the name of the group.
/// </summary>
public string GroupName { get; set; } = Nacos.V2.Common.Constants.DEFAULT_GROUP;
/// <summary>
/// the name of the cluster.
/// </summary>
/// <value>The name of the cluster.</value>
public string ClusterName { get; set; }
/// <summary>
/// the name of the group.
/// </summary>
public string GroupName { get; set; }
/// <summary>
/// the weight of this instance.
/// </summary>
public double Weight { get; set; } = 100;
public string ClusterName { get; set; } = Nacos.V2.Common.Constants.DEFAULT_CLUSTER_NAME;
/// <summary>
/// the ip of this instance
@ -59,6 +37,11 @@
/// </summary>
public int Port { get; set; }
/// <summary>
/// the weight of this instance.
/// </summary>
public double Weight { get; set; } = 100;
/// <summary>
/// if you just want to subscribe, but don't want to register your service, set it to false.
/// </summary>
@ -70,8 +53,38 @@
public Dictionary<string, string> Metadata { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Load Balance Strategy
/// If instance is enabled to accept request. The default value is true.
/// </summary>
public string LBStrategy { get; set; } = LBStrategyName.WeightRandom.ToString();
public bool InstanceEnabled { get; set; } = true;
/// <summary>
/// If instance is ephemeral.The default value is true.
/// </summary>
public bool Ephemeral { get; set; } = true;
/// <summary>
/// whether your service is a https service.
/// </summary>
public bool Secure { get; set; } = false;
public System.Action<NacosSdkOptions> BuildSdkOptions()
{
return x =>
{
x.AccessKey = this.AccessKey;
x.ConfigUseRpc = this.ConfigUseRpc;
x.ContextPath = this.ContextPath;
x.DefaultTimeOut = this.DefaultTimeOut;
x.EndPoint = this.EndPoint;
x.ListenInterval = this.ListenInterval;
x.Namespace = this.Namespace;
x.NamingLoadCacheAtStart = this.NamingLoadCacheAtStart;
x.NamingUseRpc = this.NamingUseRpc;
x.Password = this.Password;
x.SecretKey = this.SecretKey;
x.ServerAddresses = this.ServerAddresses;
x.UserName = this.UserName;
};
}
}
}

View File

@ -0,0 +1,131 @@
namespace Nacos.AspNetCore.V2
{
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Nacos.V2;
using Nacos.V2.Naming.Core;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class RegSvcBgTask : IHostedService, IDisposable
{
private static readonly string MetadataNetVersion = "DOTNET_VERSION";
private static readonly string MetadataHostOs = "HOST_OS";
private static readonly string MetadataSecure = "secure";
private readonly ILogger _logger;
private readonly INacosNamingService _svc;
private readonly IFeatureCollection _features;
private NacosAspNetOptions _options;
private IEnumerable<Uri> uris = null;
public RegSvcBgTask(
ILoggerFactory loggerFactory,
INacosNamingService svc,
IServer server,
IOptionsMonitor<NacosAspNetOptions> optionsAccs)
{
_logger = loggerFactory.CreateLogger<RegSvcBgTask>();
_svc = svc;
_options = optionsAccs.CurrentValue;
_features = server.Features;
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
public async Task StartAsync(CancellationToken cancellationToken)
{
if (!_options.RegisterEnabled)
{
_logger.LogInformation("setting RegisterEnabled to false, will not register to nacos");
return;
}
uris = UriTool.GetUri(_features, _options.Ip, _options.Port, _options.PreferredNetworks);
var metadata = new Dictionary<string, string>()
{
{ PreservedMetadataKeys.REGISTER_SOURCE, $"ASPNET_CORE" },
{ MetadataNetVersion, Environment.Version.ToString() },
{ MetadataHostOs, Environment.OSVersion.ToString() },
};
if (_options.Secure) metadata[MetadataSecure] = "true";
foreach (var item in _options.Metadata)
{
if (!metadata.ContainsKey(item.Key))
{
metadata.TryAdd(item.Key, item.Value);
}
}
foreach (var uri in uris)
{
for (int i = 0; i < 3; i++)
{
try
{
var instance = new Nacos.V2.Naming.Dtos.Instance
{
Ephemeral = _options.Ephemeral,
ServiceName = _options.ServiceName,
ClusterName = _options.ClusterName,
Enabled = _options.InstanceEnabled,
Healthy = true,
Ip = uri.Host,
Port = uri.Port,
Weight = _options.Weight,
Metadata = metadata,
InstanceId = ""
};
_logger.LogInformation("register instance to nacos server, 【{0}】", instance);
await _svc.RegisterInstance(_options.ServiceName, _options.GroupName, instance).ConfigureAwait(false);
break;
}
catch (Exception ex)
{
_logger.LogError(ex, "register instance error, count = {0}", i + 1);
}
}
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (_options.RegisterEnabled)
{
_logger.LogWarning("deregister instance from nacos server, serviceName={0}", _options.ServiceName);
foreach (var uri in uris)
{
for (int i = 0; i < 3; i++)
{
try
{
_logger.LogWarning("begin to remove instance");
await _svc.DeregisterInstance(_options.ServiceName, _options.GroupName, uri.Host, uri.Port, _options.ClusterName).ConfigureAwait(false);
_logger.LogWarning("removed instance");
break;
}
catch (Exception ex)
{
_logger.LogError(ex, "deregister instance error, count = {0}", i + 1);
}
}
}
}
}
}
}

View File

@ -0,0 +1,50 @@
namespace Nacos.AspNetCore.V2
{
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Nacos.V2.DependencyInjection;
using System;
public static class ServiceCollectionExtensions
{
/// <summary>
/// Add Nacos AspNet. This will register and de-register instance automatically.
/// Mainly for nacos server 2.x
/// </summary>
/// <param name="services">services.</param>
/// <param name="configuration">configuration</param>
/// <param name="section">section, default is nacos</param>
/// <returns>IServiceCollection</returns>
public static IServiceCollection AddNacosAspNet(this IServiceCollection services, IConfiguration configuration, string section = "nacos")
{
services.Configure<NacosAspNetOptions>(configuration.GetSection(section));
services.AddNacosV2Naming(configuration, sectionName: section);
services.AddHostedService<RegSvcBgTask>();
return services;
}
/// <summary>
/// Add Nacos AspNet. This will register and de-register instance automatically.
/// Mainly for nacos server 2.x
/// </summary>
/// <param name="services">services</param>
/// <param name="optionsAccs">optionsAccs</param>
/// <returns>IServiceCollection</returns>
public static IServiceCollection AddNacosAspNet(this IServiceCollection services, Action<NacosAspNetOptions> optionsAccs)
{
services.Configure(optionsAccs);
var options = new NacosAspNetOptions();
optionsAccs.Invoke(options);
services.AddNacosV2Naming(options.BuildSdkOptions());
services.AddHostedService<RegSvcBgTask>();
return services;
}
}
}

View File

@ -1,9 +1,5 @@
namespace Nacos.Microsoft.Extensions.Configuration
{
using global::Microsoft.Extensions.Configuration;
using Nacos.Config;
using System.Collections.Generic;
public class ConfigListener
{
/// <summary>
@ -20,10 +16,5 @@
/// Configuration group
/// </summary>
public string Group { get; set; }
/// <summary>
/// Tenant information. It corresponds to the Namespace field in Nacos.
/// </summary>
public string Tenant { get; set; }
}
}

View File

@ -1,16 +1,14 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Nacos.Microsoft.Extensions.Configuration.Tests")]
namespace Nacos.Microsoft.Extensions.Configuration
namespace Nacos.Microsoft.Extensions.Configuration
{
using global::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;
using Nacos.V2;
internal class DefaultJsonConfigurationStringParser : INacosConfigurationParser
{

View File

@ -1,125 +0,0 @@
namespace Nacos.Microsoft.Extensions.Configuration
{
using Nacos.Config;
using Nacos.Config.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class MsConfigServerHttpAgent : HttpAgent, IDisposable
{
private readonly NacosOptions _options;
private readonly ServerListManager _serverListMgr;
private readonly Nacos.Security.SecurityProxy _securityProxy;
private readonly string _namespaceId;
private readonly Timer _timer;
private long _securityInfoRefreshIntervalMills = 5000;
public MsConfigServerHttpAgent(NacosOptions options)
{
_options = options;
_serverListMgr = new ServerListManager(_options);
_namespaceId = _options.Namespace;
_serverListMgr = new ServerListManager(_options);
_securityProxy = new Security.SecurityProxy(_options);
_securityProxy.LoginAsync(_serverListMgr.GetServerUrls()).ConfigureAwait(false).GetAwaiter().GetResult();
_timer = new Timer(
async x =>
{
await _securityProxy.LoginAsync(_serverListMgr.GetServerUrls());
}, null, 0, _securityInfoRefreshIntervalMills);
}
public override string AbstGetName() => _serverListMgr.GetName();
public override string AbstGetNamespace() => _serverListMgr.GetNamespace();
public override string AbstGetTenant() => _serverListMgr.GetTenant();
public void Dispose()
{
Console.WriteLine("ms config timer dispose");
_timer?.Dispose();
}
public override async Task<HttpResponseMessage> ReqApiAsync(HttpMethod httpMethod, string path, Dictionary<string, string> headers, Dictionary<string, string> paramValues, int timeout)
{
using (HttpClient client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(timeout);
var requestMessage = new HttpRequestMessage
{
Method = httpMethod
};
var currentServerAddr = _serverListMgr.GetCurrentServerAddr();
var requestUrl = GetUrl(currentServerAddr, path);
InjectSecurityInfo(requestMessage, paramValues);
if (paramValues != null && paramValues.Any())
{
if (httpMethod == HttpMethod.Post)
{
requestMessage.RequestUri = new Uri(requestUrl);
requestMessage.Content = new FormUrlEncodedContent(paramValues);
}
else
{
var query = HttpAgentCommon.BuildQueryString(paramValues);
requestMessage.RequestUri = new Uri($"{requestUrl}?{query}");
}
}
HttpAgentCommon.BuildHeader(requestMessage, headers);
HttpAgentCommon.BuildSpasHeaders(requestMessage, paramValues, _options.AccessKey, _options.SecretKey);
var responseMessage = await client.SendAsync(requestMessage);
if (responseMessage.StatusCode == System.Net.HttpStatusCode.InternalServerError
|| responseMessage.StatusCode == System.Net.HttpStatusCode.BadGateway
|| responseMessage.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable)
{
System.Diagnostics.Trace.TraceError("[NACOS ConnectException] currentServerAddr: {0}, httpCode: {1}", _serverListMgr.GetCurrentServerAddr(), responseMessage.StatusCode);
}
else
{
_serverListMgr.UpdateCurrentServerAddr(currentServerAddr);
return responseMessage;
}
throw new System.Net.Http.HttpRequestException($"no available server, currentServerAddr : {currentServerAddr}");
}
}
private void InjectSecurityInfo(HttpRequestMessage requestMessage, Dictionary<string, string> paramValues)
{
if (!string.IsNullOrWhiteSpace(_securityProxy.GetAccessToken()))
{
if (!paramValues.ContainsKey(ConstValue.ACCESS_TOKEN))
{
paramValues.Add(ConstValue.ACCESS_TOKEN, _securityProxy.GetAccessToken());
}
}
if (!string.IsNullOrWhiteSpace(_namespaceId) && paramValues != null && !paramValues.ContainsKey("tenant"))
{
requestMessage.Headers.TryAddWithoutValidation("tenant", _namespaceId);
}
}
private string GetUrl(string serverAddr, string relativePath)
{
return $"{serverAddr}{relativePath}";
}
}
}

View File

@ -1,36 +0,0 @@
namespace Nacos.Microsoft.Extensions.Configuration
{
using global::Microsoft.Extensions.Logging;
using Nacos;
using Nacos.Config.Http;
using System.Collections.Generic;
public class NacosMsConfigClient : AbstNacosConfigClient
{
private readonly Nacos.Config.Http.IHttpAgent _httpAgent;
private readonly ILocalConfigInfoProcessor _processor;
public NacosMsConfigClient(
ILoggerFactory loggerFactory,
NacosOptions options)
{
_logger = loggerFactory.CreateLogger<NacosMsConfigClient>();
_options = options;
_processor = new FileLocalConfigInfoProcessor();
_httpAgent = new MsConfigServerHttpAgent(_options);
listeners = new List<Listener>();
}
public override IHttpAgent GetAgent()
{
return _httpAgent;
}
public override ILocalConfigInfoProcessor GetProcessor()
{
return _processor;
}
}
}

View File

@ -2,8 +2,8 @@
<Import Project="../../build/version.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
<PackageId>nacos-sdk-csharp-unofficial.Extensions.Configuration</PackageId>
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
<PackageId>nacos-sdk-csharp.Extensions.Configuration</PackageId>
<VersionPrefix>$(NugetVersion)</VersionPrefix>
<VersionSuffix></VersionSuffix>
<Authors>nacos-sdk-csharp Contributors</Authors>
@ -13,6 +13,7 @@
<RepositoryUrl>https://github.com/nacos-group/nacos-sdk-csharp</RepositoryUrl>
<ProjectUrl>https://github.com/nacos-group/nacos-sdk-csharp</ProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>
</PackageReleaseNotes>
</PropertyGroup>
@ -24,24 +25,42 @@
<ItemGroup>
<None Include="../../LICENSE" Pack="true" Visible="false" PackagePath="" />
<None Include="README.md" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nacos\Nacos.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Nacos.Microsoft.Extensions.Configuration.Tests" />
</ItemGroup>
</Project>

View File

@ -1,19 +1,32 @@
namespace Microsoft.Extensions.Configuration
{
using Nacos.Config;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Nacos.Microsoft.Extensions.Configuration;
using Nacos.V2;
using Nacos.V2.DependencyInjection;
using System;
public static class NacosConfigurationExtensions
{
/// <summary>
/// Add Nacos Configuration
/// Add Nacos Configuration that integrate with Microsoft.Extensions.Configuration
/// </summary>
/// <param name="builder">IConfigurationBuilder</param>
/// <param name="action">setup NacosConfigurationSource</param>
/// <param name="client">The nacos config client</param>
/// <param name="loggerFactory">The loggerFactory</param>
/// <param name="parser">The parser.</param>
/// <param name="logAction">The logAction.</param>
/// <returns>IConfigurationBuilder</returns>
public static IConfigurationBuilder AddNacosConfiguration(
this IConfigurationBuilder builder, Action<NacosConfigurationSource> action)
public static IConfigurationBuilder AddNacosV2Configuration(
this IConfigurationBuilder builder,
Action<NacosV2ConfigurationSource> action,
INacosConfigService client = null,
ILoggerFactory loggerFactory = null,
INacosConfigurationParser parser = null,
Action<ILoggingBuilder> logAction = null)
{
if (builder == null)
{
@ -25,26 +38,32 @@
throw new ArgumentNullException(nameof(action));
}
var source = new NacosConfigurationSource();
var source = new NacosV2ConfigurationSource(null, null);
action.Invoke(source);
source.NacosConfigurationParser ??= parser ?? DefaultJsonConfigurationStringParser.Instance;
action(source);
source.NacosConfigurationParser ??= DefaultJsonConfigurationStringParser.Instance;
BuildDISource(source, client, loggerFactory, logAction);
return builder.Add(source);
}
/// <summary>
/// Add Nacos Configuration
/// Add Nacos Configuration that integrate with Microsoft.Extensions.Configuration
/// </summary>
/// <param name="builder">IConfigurationBuilder</param>
/// <param name="configuration">Configuration binding nacos configuration source</param>
/// <param name="client">The nacos config client</param>
/// <param name="loggerFactory">The loggerFactory</param>
/// <param name="parser">The parser.</param>
/// <param name="logAction">The logAction.</param>
/// <returns>IConfigurationBuilder</returns>
public static IConfigurationBuilder AddNacosConfiguration(
public static IConfigurationBuilder AddNacosV2Configuration(
this IConfigurationBuilder builder,
IConfiguration configuration,
INacosConfigurationParser parser = null)
INacosConfigService client = null,
ILoggerFactory loggerFactory = null,
INacosConfigurationParser parser = null,
Action<ILoggingBuilder> logAction = null)
{
if (builder == null)
{
@ -56,11 +75,79 @@
throw new ArgumentNullException(nameof(configuration));
}
var source = new NacosConfigurationSource();
var source = new NacosV2ConfigurationSource(null, null);
configuration.Bind(source);
source.NacosConfigurationParser = parser ?? DefaultJsonConfigurationStringParser.Instance;
BuildDISource(source, client, loggerFactory, logAction);
return builder.Add(source);
}
/// <summary>
/// Use nacos config combine IHostBuilder and ConfigureAppConfiguration
/// </summary>
/// <param name="builder">host builder.</param>
/// <param name="section">basic nacos configuration section.</param>
/// <param name="parser">The parser.</param>
/// <param name="logAction">The logAction.</param>
/// <returns>IHostBuilder</returns>
public static IHostBuilder UseNacosConfig(this IHostBuilder builder, string section, INacosConfigurationParser parser = null, Action<ILoggingBuilder> logAction = null)
{
builder.ConfigureAppConfiguration((_, cfb) =>
{
var config = cfb.Build();
cfb.AddNacosV2Configuration(config.GetSection(section), parser: parser, logAction: logAction);
});
return builder;
}
#if NET5_0_OR_GREATER
/// <summary>
/// Use nacos config combine IWebHostBuilder and ConfigureAppConfiguration
/// </summary>
/// <param name="builder">host builder.</param>
/// <param name="section">basic nacos configuration section.</param>
/// <param name="parser">The parser.</param>
/// <param name="logAction">The logAction.</param>
/// <returns>IHostBuilder</returns>
public static AspNetCore.Hosting.IWebHostBuilder UseNacosConfig(this AspNetCore.Hosting.IWebHostBuilder builder, string section, INacosConfigurationParser parser = null, Action<ILoggingBuilder> logAction = null)
{
builder.ConfigureAppConfiguration((_, cfb) =>
{
var config = cfb.Build();
cfb.AddNacosV2Configuration(config.GetSection(section), parser: parser, logAction: logAction);
});
return builder;
}
#endif
private static void BuildDISource(
NacosV2ConfigurationSource source,
INacosConfigService client,
ILoggerFactory logFactory,
Action<ILoggingBuilder> logAction)
{
if (client == null)
{
IServiceCollection serviceCollection = new ServiceCollection();
var sdkAction = source.GetNacosSdkOptions();
serviceCollection.AddNacosV2Config(sdkAction);
serviceCollection.AddLogging(logAction ?? (x => x.AddConsole()));
var serviceProvider = serviceCollection.BuildServiceProvider();
client = serviceProvider.GetService<INacosConfigService>();
logFactory = serviceProvider.GetService<ILoggerFactory>();
}
source.Client = client ?? throw new Nacos.V2.Exceptions.NacosException("Can't get INacosConfigService instance from DI Container");
source.LoggerFactory = logFactory;
}
}
}

Some files were not shown because too many files have changed in this diff Show More