mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-03-03 00:00:58 +08:00
Compare commits
1914 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9550ed57c0 | ||
|
|
19b27d8e9a | ||
|
|
0b30dbb8de | ||
|
|
fadaa0d129 | ||
|
|
6863b773b4 | ||
|
|
82d97ab0b4 | ||
|
|
de94bb260b | ||
|
|
016f930021 | ||
|
|
9b7d98773b | ||
|
|
6988dd224f | ||
|
|
c9b5418a70 | ||
|
|
74d56ced8a | ||
|
|
790fca50f3 | ||
|
|
728b5958f3 | ||
|
|
5a39330fdb | ||
|
|
70c7e0c331 | ||
|
|
67b215ce7a | ||
|
|
d05324cd12 | ||
|
|
33937703c7 | ||
|
|
7f809e0718 | ||
|
|
6d54c650f0 | ||
|
|
11cbb1b612 | ||
|
|
3b6887dc2e | ||
|
|
6af3fb44f4 | ||
|
|
f57b5befd7 | ||
|
|
dbc6b8cf5e | ||
|
|
007a4c223a | ||
|
|
ab2c11e05c | ||
|
|
ec382995b4 | ||
|
|
7a38526ab3 | ||
|
|
4441244575 | ||
|
|
adafb65221 | ||
|
|
74e936c6d3 | ||
|
|
36aa29f9f1 | ||
|
|
d4fcbdc390 | ||
|
|
ca43879cc3 | ||
|
|
9b5826a6b1 | ||
|
|
485f19572b | ||
|
|
2845f03250 | ||
|
|
1ada6360d4 | ||
|
|
21b7ef4d74 | ||
|
|
9a87b41027 | ||
|
|
886cc3155f | ||
|
|
020ad797f2 | ||
|
|
1d5bca773f | ||
|
|
6b86957556 | ||
|
|
caa90cc227 | ||
|
|
87c93534a5 | ||
|
|
b8c79ac61c | ||
|
|
2db8d6e699 | ||
|
|
0983837ff7 | ||
|
|
efa948154f | ||
|
|
e8c1111cbc | ||
|
|
c9c92dcf97 | ||
|
|
f2c2c60127 | ||
|
|
d280cc6d35 | ||
|
|
a1e38234a7 | ||
|
|
ace5a9a1ec | ||
|
|
4ce77ececc | ||
|
|
be9442c113 | ||
|
|
5895f9e794 | ||
|
|
b0d1820919 | ||
|
|
8b183e289c | ||
|
|
09ecddb552 | ||
|
|
127639c20e | ||
|
|
9a0dc6f089 | ||
|
|
0c8f01c00a | ||
|
|
c2f074cb08 | ||
|
|
6b6ddcf550 | ||
|
|
d9f5f1f050 | ||
|
|
7ed7201d10 | ||
|
|
a1ddd1c3e2 | ||
|
|
4800543a77 | ||
|
|
4090046946 | ||
|
|
3a19c75ca1 | ||
|
|
a67af0485e | ||
|
|
5de968f6c7 | ||
|
|
1edb92f6e8 | ||
|
|
2b9bbca400 | ||
|
|
3bd1a977f7 | ||
|
|
d2b5704294 | ||
|
|
611c5ce59a | ||
|
|
fc61b67fc0 | ||
|
|
a2da4c36fe | ||
|
|
5e37859157 | ||
|
|
6f316d3e51 | ||
|
|
53d70ef9d7 | ||
|
|
a9a9e45b7c | ||
|
|
629012d32a | ||
|
|
5f2133eb50 | ||
|
|
ad85890907 | ||
|
|
87518af562 | ||
|
|
62b26bc2a4 | ||
|
|
f237137791 | ||
|
|
0d4d847e08 | ||
|
|
12f1854d31 | ||
|
|
73f5d43ada | ||
|
|
551122de10 | ||
|
|
d092254822 | ||
|
|
1027006e63 | ||
|
|
2544c01e9d | ||
|
|
2f1f25ca37 | ||
|
|
5489f33d54 | ||
|
|
6665d2fb2e | ||
|
|
b5ff6c141c | ||
|
|
f1e8b66689 | ||
|
|
c727aeed99 | ||
|
|
40aa47bb1e | ||
|
|
40234343ff | ||
|
|
00a9bd00e5 | ||
|
|
55c17211d8 | ||
|
|
db7dc0e9a7 | ||
|
|
1727107190 | ||
|
|
e680ac4cac | ||
|
|
6053899516 | ||
|
|
5157eac35c | ||
|
|
537104037b | ||
|
|
29c1768ded | ||
|
|
b4a97e8b09 | ||
|
|
6101ea46d3 | ||
|
|
cad145f067 | ||
|
|
9d8f8b3125 | ||
|
|
4f70356a5c | ||
|
|
69a8b47245 | ||
|
|
88225a97b8 | ||
|
|
c697d12f8b | ||
|
|
7bb8f52813 | ||
|
|
b84f385d2d | ||
|
|
450e023b3b | ||
|
|
9f3b9fc513 | ||
|
|
9721b8bd74 | ||
|
|
bd30a40a6f | ||
|
|
9ec9ace8e2 | ||
|
|
a437d55f9f | ||
|
|
d75a734bc1 | ||
|
|
9c058e9545 | ||
|
|
accbaf3ecb | ||
|
|
f8f2d7568c | ||
|
|
158226601b | ||
|
|
63aa8d9536 | ||
|
|
0147457329 | ||
|
|
1d47b26d0d | ||
|
|
cc1bc6dd82 | ||
|
|
922596c128 | ||
|
|
67cb142c07 | ||
|
|
f164b7dccc | ||
|
|
6cc14c1e32 | ||
|
|
e992cfc928 | ||
|
|
42edd4c230 | ||
|
|
3892ff1937 | ||
|
|
12878ba022 | ||
|
|
a3259ad36f | ||
|
|
5bb7dfb7cd | ||
|
|
3447e2dc5d | ||
|
|
88fae0cdc2 | ||
|
|
f7ebe44fb6 | ||
|
|
5a7f0ab108 | ||
|
|
be5f57f654 | ||
|
|
a6e7a5e906 | ||
|
|
c4ab176089 | ||
|
|
a50f877964 | ||
|
|
28cdc29369 | ||
|
|
e39cbaf5e7 | ||
|
|
9d1dd72584 | ||
|
|
ea403fcae0 | ||
|
|
91533909c2 | ||
|
|
61d5d40dbb | ||
|
|
38dbd0aca7 | ||
|
|
343347ea11 | ||
|
|
a9e11d161c | ||
|
|
d25ca6dc4a | ||
|
|
ba95d1798f | ||
|
|
436b5b910c | ||
|
|
560a76558a | ||
|
|
d7f4e49c2a | ||
|
|
a1be2bebf7 | ||
|
|
3f53eb14ab | ||
|
|
e46044e217 | ||
|
|
80dcd76749 | ||
|
|
9c842ab802 | ||
|
|
b8c0f9a212 | ||
|
|
6cc0059691 | ||
|
|
33d28a8cb0 | ||
|
|
e4621d9049 | ||
|
|
953fbc043b | ||
|
|
c649ad31c2 | ||
|
|
50fc8c5f0a | ||
|
|
64bc65114a | ||
|
|
ae9d778ac7 | ||
|
|
77a9a64a41 | ||
|
|
19ea76bd60 | ||
|
|
0c31b97824 | ||
|
|
70ae2fab44 | ||
|
|
411a9058ca | ||
|
|
4b9f845fae | ||
|
|
bdaa53bac8 | ||
|
|
e5b81c08f3 | ||
|
|
1ffab89e97 | ||
|
|
5440b226c4 | ||
|
|
90c6022839 | ||
|
|
184467e482 | ||
|
|
68045d6458 | ||
|
|
d52f17a17b | ||
|
|
047937af4c | ||
|
|
a9267bfc0e | ||
|
|
1019fd685b | ||
|
|
34246d8a62 | ||
|
|
599b6335d5 | ||
|
|
46bc48d1c1 | ||
|
|
17675e702d | ||
|
|
639c683144 | ||
|
|
96a21210b5 | ||
|
|
7495dc86a0 | ||
|
|
ee4cb20eef | ||
|
|
9ca3cd0b1a | ||
|
|
eb6ec06157 | ||
|
|
62940ae25a | ||
|
|
dfc143379f | ||
|
|
bd3a9a5ce8 | ||
|
|
ec4fdc39fe | ||
|
|
3c3e134d2b | ||
|
|
81089cc058 | ||
|
|
681194a517 | ||
|
|
8f515f76c0 | ||
|
|
fcb74eb28c | ||
|
|
44afdaef8e | ||
|
|
41c55d088d | ||
|
|
3b71fe3135 | ||
|
|
4326c41258 | ||
|
|
7f0d57b311 | ||
|
|
75c208dafc | ||
|
|
8021ca9eff | ||
|
|
2cf06a5677 | ||
|
|
2fa42cd8a3 | ||
|
|
a600eb9e7e | ||
|
|
fcf0fd7f70 | ||
|
|
4e421c160c | ||
|
|
340e2016d6 | ||
|
|
5dfaead60e | ||
|
|
c8acb12e4a | ||
|
|
5fbcb8cbd9 | ||
|
|
fd8d4399d3 | ||
|
|
6f1efafd86 | ||
|
|
2714a507d9 | ||
|
|
9a9230786b | ||
|
|
4a8b58a65c | ||
|
|
7d81f88658 | ||
|
|
0ce3c0bbdd | ||
|
|
981235e6e9 | ||
|
|
d0ecb232a1 | ||
|
|
c7a52604e7 | ||
|
|
da81b2d8a3 | ||
|
|
7b14fdd8de | ||
|
|
1fc2734eb7 | ||
|
|
f3bef72ebb | ||
|
|
7e6d2e829b | ||
|
|
944626960b | ||
|
|
c073868989 | ||
|
|
d2981100fa | ||
|
|
ce4f7e5711 | ||
|
|
cc812ba2cb | ||
|
|
8a6e5abf48 | ||
|
|
8b191330b8 | ||
|
|
5ed79c6dd0 | ||
|
|
6e2ca8f1c3 | ||
|
|
a46a552097 | ||
|
|
53e56134d4 | ||
|
|
0d2f2cb826 | ||
|
|
f90105ebb4 | ||
|
|
67ed1ac1e3 | ||
|
|
69b84f6613 | ||
|
|
433d616b9b | ||
|
|
53aa575ad4 | ||
|
|
571df74c43 | ||
|
|
b7847c7e7d | ||
|
|
94eb41996e | ||
|
|
cefde6848d | ||
|
|
381b712b25 | ||
|
|
c319b0b4e4 | ||
|
|
1a32fa9e20 | ||
|
|
909406238c | ||
|
|
54a1d2a66f | ||
|
|
8dcbfcad33 | ||
|
|
f64fd43951 | ||
|
|
551597765c | ||
|
|
bfda33280a | ||
|
|
8d0411f1f4 | ||
|
|
3995d4acab | ||
|
|
6ff5727156 | ||
|
|
f654386dfe | ||
|
|
c03ef82643 | ||
|
|
525545329b | ||
|
|
755cb6f509 | ||
|
|
55469708f0 | ||
|
|
94c52c62fe | ||
|
|
37b4709d76 | ||
|
|
86555af6ce | ||
|
|
ddb00879f4 | ||
|
|
2d0ca08314 | ||
|
|
b78ecf27d5 | ||
|
|
02a5f69958 | ||
|
|
cf5bf746ef | ||
|
|
0a5e40ee25 | ||
|
|
51a266ef58 | ||
|
|
1f0901c90c | ||
|
|
a725c06396 | ||
|
|
54547f0d7c | ||
|
|
afe9c8bcae | ||
|
|
688d93e5c1 | ||
|
|
4c65b2398d | ||
|
|
41435f1aa3 | ||
|
|
20206bbc44 | ||
|
|
f2dc0d1825 | ||
|
|
51b4d1b072 | ||
|
|
9180799e4e | ||
|
|
9788b9182b | ||
|
|
260b9a4795 | ||
|
|
9380e3daa8 | ||
|
|
bb894e14a4 | ||
|
|
b492d82442 | ||
|
|
5eaffe2ec2 | ||
|
|
d7bcad9da7 | ||
|
|
04e11d15e2 | ||
|
|
97e3dc5eed | ||
|
|
695bd56a27 | ||
|
|
7919383be3 | ||
|
|
d6cc3c5d96 | ||
|
|
19f0d05a69 | ||
|
|
3c5e575e9b | ||
|
|
f875617de1 | ||
|
|
9976e8a6e2 | ||
|
|
38e8cbc5ca | ||
|
|
d95c14c903 | ||
|
|
ffb2f2fb4c | ||
|
|
4bd2fc357d | ||
|
|
da23d17af8 | ||
|
|
c1a6046107 | ||
|
|
2ec7b5f4fd | ||
|
|
d21f61646a | ||
|
|
eecdf442fb | ||
|
|
8e8338743d | ||
|
|
1b4c3cbb8d | ||
|
|
b7756e2112 | ||
|
|
cb49059e84 | ||
|
|
690cabfd96 | ||
|
|
4521212a90 | ||
|
|
771ecd9d81 | ||
|
|
94834f45c3 | ||
|
|
a9b2979a21 | ||
|
|
22ac150acd | ||
|
|
17337b8d78 | ||
|
|
09fb43ee14 | ||
|
|
477c0e3f2c | ||
|
|
2e4f520dac | ||
|
|
067b25b9af | ||
|
|
36370c215d | ||
|
|
e24731acfe | ||
|
|
927e9df7de | ||
|
|
114b41144e | ||
|
|
5019a36138 | ||
|
|
e15eb6149b | ||
|
|
9d401a9c93 | ||
|
|
eacf86e118 | ||
|
|
c4b631c815 | ||
|
|
fb25e75a3a | ||
|
|
e9099bbe04 | ||
|
|
f02fb91175 | ||
|
|
5beef22269 | ||
|
|
933cbb91d8 | ||
|
|
efd917d184 | ||
|
|
e906208f4a | ||
|
|
cf137f6307 | ||
|
|
e6b991fe86 | ||
|
|
3e75792e43 | ||
|
|
dd3f6325bb | ||
|
|
108ba348f6 | ||
|
|
bcdcec40e0 | ||
|
|
2ce8baea42 | ||
|
|
c6425ca206 | ||
|
|
acb359ec33 | ||
|
|
a1395d9a33 | ||
|
|
609de29e71 | ||
|
|
2efed4f4a5 | ||
|
|
aec90ec9d6 | ||
|
|
1aaff2942d | ||
|
|
cdbfc5383d | ||
|
|
f302555e0c | ||
|
|
86c5890476 | ||
|
|
a13ee395c7 | ||
|
|
9abcd72aca | ||
|
|
4ddea6d468 | ||
|
|
867a2dc861 | ||
|
|
4a72e3fa0d | ||
|
|
8b4371aabb | ||
|
|
799dd08ec0 | ||
|
|
c5c22224cf | ||
|
|
2dae47e85c | ||
|
|
375dd4f797 | ||
|
|
acb2db8397 | ||
|
|
b7a3e76d0b | ||
|
|
48150b712a | ||
|
|
6db9dfc308 | ||
|
|
2d6c1f3c46 | ||
|
|
161e10d2d1 | ||
|
|
a9a2a91183 | ||
|
|
1c9a6f108e | ||
|
|
d6adf9b736 | ||
|
|
959eb3f782 | ||
|
|
7a53e0c90c | ||
|
|
533b87fc5b | ||
|
|
15713cf7fe | ||
|
|
31dc756868 | ||
|
|
52f6b6130f | ||
|
|
16945b3d5b | ||
|
|
bdc664fc44 | ||
|
|
9555ef10e0 | ||
|
|
49e6cb26fc | ||
|
|
3ace29e692 | ||
|
|
aa9dd0129b | ||
|
|
1464271fbd | ||
|
|
754f145559 | ||
|
|
6afd0cb955 | ||
|
|
d32906702a | ||
|
|
9bcdaf6bd8 | ||
|
|
db82a8cf08 | ||
|
|
a9e8b2b01f | ||
|
|
85bd1ce8d6 | ||
|
|
4d09243efd | ||
|
|
5934056fe6 | ||
|
|
2a81062fa3 | ||
|
|
fdc868323f | ||
|
|
593b3a4cdd | ||
|
|
2b12e18e6c | ||
|
|
345ed80ec8 | ||
|
|
29dc1ae250 | ||
|
|
9fdd41b134 | ||
|
|
31ee5e8ffb | ||
|
|
d7922bb71d | ||
|
|
1cc5f2a14f | ||
|
|
d9997eeb28 | ||
|
|
06e77aa8fd | ||
|
|
e9e2228f6e | ||
|
|
d516a381d0 | ||
|
|
4e792ba976 | ||
|
|
fa3ac91ba4 | ||
|
|
f90d3871fa | ||
|
|
e7c152e955 | ||
|
|
0223b5c104 | ||
|
|
9e41a7c446 | ||
|
|
2ba0ffc1b7 | ||
|
|
7d038e1266 | ||
|
|
b98285f314 | ||
|
|
73438da666 | ||
|
|
85f2e1b579 | ||
|
|
ece89ebad0 | ||
|
|
6e2dd39246 | ||
|
|
a61286e534 | ||
|
|
4f944a5466 | ||
|
|
d29aac088a | ||
|
|
8abd122773 | ||
|
|
08084aa0bc | ||
|
|
e69cd5a73c | ||
|
|
76aa3bdc64 | ||
|
|
93251104af | ||
|
|
3cae477f3e | ||
|
|
25c736dc0a | ||
|
|
96a09d8980 | ||
|
|
72387235a0 | ||
|
|
1b00e505b7 | ||
|
|
1c54e47b9e | ||
|
|
ba07e2c905 | ||
|
|
bde4611a50 | ||
|
|
e7326fea7b | ||
|
|
d13b23ad2e | ||
|
|
8b1830a711 | ||
|
|
b70c530754 | ||
|
|
d90e24f9ed | ||
|
|
1fbd521d1a | ||
|
|
2ae6183e7f | ||
|
|
7905911624 | ||
|
|
c5b6b33d8e | ||
|
|
5d29fd6d3b | ||
|
|
ad8f48f36b | ||
|
|
f9843c13d4 | ||
|
|
6bd561b094 | ||
|
|
d2c6238df1 | ||
|
|
1d108983e8 | ||
|
|
b768bca638 | ||
|
|
28fcd6c9ce | ||
|
|
6005b9329d | ||
|
|
10559a925c | ||
|
|
942e218a9e | ||
|
|
f6af9edc38 | ||
|
|
e0f6331ec3 | ||
|
|
06f0c6caa7 | ||
|
|
56ec260e3a | ||
|
|
176cf84369 | ||
|
|
6de3b722ed | ||
|
|
2cf6326764 | ||
|
|
ec27ee58b4 | ||
|
|
4e42e2202e | ||
|
|
e60d8eceb7 | ||
|
|
08fb939b38 | ||
|
|
482dd73afd | ||
|
|
f09a9fee75 | ||
|
|
9a31d14b41 | ||
|
|
2fd7f88f04 | ||
|
|
9d4cc802e9 | ||
|
|
ee6b4827fa | ||
|
|
48d8c528f6 | ||
|
|
40c0a5ac64 | ||
|
|
3a60bcc174 | ||
|
|
2b3fad16fd | ||
|
|
f0cf6bf5c8 | ||
|
|
0ba4e3240b | ||
|
|
9332b17fc1 | ||
|
|
4ec4023f40 | ||
|
|
d9971541f2 | ||
|
|
7b0e4fcc73 | ||
|
|
cfde73d13a | ||
|
|
c17c9000a8 | ||
|
|
42d537a68b | ||
|
|
25eebec8f7 | ||
|
|
bbe5b01872 | ||
|
|
6b31536de5 | ||
|
|
2e5db5500f | ||
|
|
7038d31c53 | ||
|
|
3eb27c3d35 | ||
|
|
a9c3a1bcec | ||
|
|
384926e73a | ||
|
|
4335c12659 | ||
|
|
e6e4829164 | ||
|
|
f3c67cf598 | ||
|
|
4681d468ce | ||
|
|
63e7d3d5f5 | ||
|
|
f47d8c8ce3 | ||
|
|
6f69f45ddc | ||
|
|
e73678c788 | ||
|
|
09a2f91cbf | ||
|
|
29da7499a4 | ||
|
|
5b024e9443 | ||
|
|
225932eff1 | ||
|
|
65d5f5ae86 | ||
|
|
3e647ef14d | ||
|
|
7cb3aea2e6 | ||
|
|
7f4b8f1c8a | ||
|
|
0a2710b865 | ||
|
|
2a301c4983 | ||
|
|
faa8131a1b | ||
|
|
71bd885bd0 | ||
|
|
691a1e50f0 | ||
|
|
ef6e9fd16d | ||
|
|
17f9ac6d54 | ||
|
|
3f8e6e48c0 | ||
|
|
bda4fdf69d | ||
|
|
5c85ed13fd | ||
|
|
1986901031 | ||
|
|
e1d3ec21e5 | ||
|
|
f45283dade | ||
|
|
31c44d8df7 | ||
|
|
bf443963c8 | ||
|
|
a0eb234539 | ||
|
|
b6d670c240 | ||
|
|
b5fb2c42c6 | ||
|
|
d72cc529ba | ||
|
|
660bd00cae | ||
|
|
b5489711ec | ||
|
|
76717c4f8a | ||
|
|
3d53d0bcd6 | ||
|
|
c7c9428b68 | ||
|
|
991a970d6a | ||
|
|
cbe93b9f7e | ||
|
|
5d7217b775 | ||
|
|
d6836b8bcf | ||
|
|
c367651c78 | ||
|
|
77123fd971 | ||
|
|
9d73a6837b | ||
|
|
651f0157dc | ||
|
|
90e8dbe449 | ||
|
|
ccba2667bc | ||
|
|
3ce9fc9790 | ||
|
|
2f24dd77bf | ||
|
|
2bc07cb3df | ||
|
|
30678dbbb4 | ||
|
|
c5b0f69b51 | ||
|
|
e593f2cba4 | ||
|
|
10f7499066 | ||
|
|
36b7e495f7 | ||
|
|
94b96e3c19 | ||
|
|
0d1ee18da0 | ||
|
|
cab0b61ee0 | ||
|
|
8e6611d76d | ||
|
|
1ef82e5f93 | ||
|
|
43dc962606 | ||
|
|
020d674ca2 | ||
|
|
bb0e1081cc | ||
|
|
5162f9ce3b | ||
|
|
57fae7fe4b | ||
|
|
17412d7de7 | ||
|
|
d59f40dfba | ||
|
|
5953be63cb | ||
|
|
58a4311947 | ||
|
|
c5a9b9a15f | ||
|
|
716c344780 | ||
|
|
9af8c4897b | ||
|
|
ca72024a68 | ||
|
|
0d2bc585a9 | ||
|
|
4e3edefb35 | ||
|
|
9408242726 | ||
|
|
4710208e81 | ||
|
|
4fc6a1e818 | ||
|
|
c9b79a074b | ||
|
|
2e79eb346f | ||
|
|
3f88bd4158 | ||
|
|
f58e079741 | ||
|
|
6f1eb1f4b9 | ||
|
|
826d529997 | ||
|
|
43e60eab4a | ||
|
|
6c33024790 | ||
|
|
d27e625fde | ||
|
|
9d4b3e7d0c | ||
|
|
23cecb9360 | ||
|
|
7e4c835ced | ||
|
|
aff460f555 | ||
|
|
52961b459e | ||
|
|
0af2f867fc | ||
|
|
85e291e0b8 | ||
|
|
6d8a859b20 | ||
|
|
a70dfb0769 | ||
|
|
c637d412e6 | ||
|
|
e996bc2d7f | ||
|
|
15be047371 | ||
|
|
0a0e0bca10 | ||
|
|
9a8f3bd161 | ||
|
|
7e2c035692 | ||
|
|
72795382a1 | ||
|
|
35cdff2afa | ||
|
|
dcf547f513 | ||
|
|
8660d45f36 | ||
|
|
63dd55e7a4 | ||
|
|
40cd89f90c | ||
|
|
44b2ade9bc | ||
|
|
1200d02fbf | ||
|
|
b020f48325 | ||
|
|
917857f1ff | ||
|
|
69d8ff1034 | ||
|
|
9a334101ca | ||
|
|
ee53b3d9c4 | ||
|
|
01a5ad5302 | ||
|
|
f12f0e1f84 | ||
|
|
6aefcdbed8 | ||
|
|
3d22a2ef65 | ||
|
|
a33c6dbf1a | ||
|
|
2b7c779e14 | ||
|
|
0e36f7c0b3 | ||
|
|
228a309545 | ||
|
|
b15ad8eb5e | ||
|
|
a525735b0b | ||
|
|
6a58af8dfb | ||
|
|
0089e63832 | ||
|
|
d4f00eb89f | ||
|
|
d15e6e395b | ||
|
|
39eb4bef07 | ||
|
|
03de576d8c | ||
|
|
216b57a4c7 | ||
|
|
5383d2d40e | ||
|
|
1d7a2013e3 | ||
|
|
24d2908cca | ||
|
|
330845a387 | ||
|
|
bbedd01a72 | ||
|
|
2b07061c18 | ||
|
|
01a3c81359 | ||
|
|
96e275efa6 | ||
|
|
12eb6c73c3 | ||
|
|
4166eddd28 | ||
|
|
6ea1592c19 | ||
|
|
f8799a073c | ||
|
|
0eb83fc930 | ||
|
|
a5dd3946f8 | ||
|
|
2732df24af | ||
|
|
f0ae27a50b | ||
|
|
c5037ea397 | ||
|
|
695aaedfba | ||
|
|
4f71d874bd | ||
|
|
c69729fadd | ||
|
|
64d04996af | ||
|
|
8eea510583 | ||
|
|
04c2b246f6 | ||
|
|
a46eb176d7 | ||
|
|
2bea88f1a3 | ||
|
|
06617de984 | ||
|
|
6459d7c024 | ||
|
|
bd4af8039f | ||
|
|
8aaa22cea3 | ||
|
|
7d902682f8 | ||
|
|
a81be99100 | ||
|
|
b6dfe93d2c | ||
|
|
35aa022984 | ||
|
|
dfe2d4cc37 | ||
|
|
1d16502d32 | ||
|
|
25c88187a3 | ||
|
|
ac04e846fa | ||
|
|
29985e2118 | ||
|
|
3b74dfd49a | ||
|
|
6abcc49ed4 | ||
|
|
f16e1cd7a6 | ||
|
|
4341b8a24b | ||
|
|
a89e11d132 | ||
|
|
bc91a8cff2 | ||
|
|
8040010b98 | ||
|
|
b39f15c798 | ||
|
|
c3cf49c63e | ||
|
|
899bd7e316 | ||
|
|
890727d495 | ||
|
|
8a8e69596a | ||
|
|
58fcc92e4d | ||
|
|
0cd795f57a | ||
|
|
4830be6388 | ||
|
|
901ccc7314 | ||
|
|
629add1e8a | ||
|
|
8b92cd6bed | ||
|
|
e63fb71ef6 | ||
|
|
aa122d2d82 | ||
|
|
5d6bfe36d0 | ||
|
|
26dadd7dae | ||
|
|
520dca6953 | ||
|
|
699f7febe4 | ||
|
|
87a14ebac1 | ||
|
|
29573342b5 | ||
|
|
91b216c06e | ||
|
|
83a6ec1b98 | ||
|
|
c5d636d697 | ||
|
|
3d704220f3 | ||
|
|
b830317608 | ||
|
|
21ff599a4e | ||
|
|
224c2b96e4 | ||
|
|
cbb3510d94 | ||
|
|
0b111852ec | ||
|
|
ff8038a616 | ||
|
|
710ad95eda | ||
|
|
f7d9effa07 | ||
|
|
cec28faaf7 | ||
|
|
bcdcca82eb | ||
|
|
4e0cc9a24a | ||
|
|
53a402a656 | ||
|
|
85ed4df1e4 | ||
|
|
8ef91ebd03 | ||
|
|
ccaebb8ec2 | ||
|
|
4afc1cc492 | ||
|
|
ddba0f9aa1 | ||
|
|
c782246a1d | ||
|
|
afa5fad8c6 | ||
|
|
d605809932 | ||
|
|
30250db0fb | ||
|
|
b48f584db8 | ||
|
|
56d850d74b | ||
|
|
3ef1323f05 | ||
|
|
d9ed547a20 | ||
|
|
82865631fc | ||
|
|
337088c908 | ||
|
|
c092ee46e9 | ||
|
|
287634cf99 | ||
|
|
c1535fd116 | ||
|
|
d7d4fd8a48 | ||
|
|
1552b00516 | ||
|
|
a40d9b79b4 | ||
|
|
0bc5b1a940 | ||
|
|
4dce50438c | ||
|
|
de7f9264fd | ||
|
|
f00a90f1ef | ||
|
|
2c578cc9e4 | ||
|
|
a04974d905 | ||
|
|
23cedbec83 | ||
|
|
3e07ca822a | ||
|
|
f9341fd2ac | ||
|
|
f6b19ec2a5 | ||
|
|
f8a4c737ee | ||
|
|
c395900861 | ||
|
|
b2ad667894 | ||
|
|
45736dfce9 | ||
|
|
753b5b0a26 | ||
|
|
3aaed801f6 | ||
|
|
1fd4f2754a | ||
|
|
bedee3391e | ||
|
|
176a672e86 | ||
|
|
9da6bcde41 | ||
|
|
3f8daa1d17 | ||
|
|
ed873da3b6 | ||
|
|
c0dfa83828 | ||
|
|
db08688968 | ||
|
|
400a146a48 | ||
|
|
a645264da7 | ||
|
|
09d19d876f | ||
|
|
373877cfcf | ||
|
|
9e143c0a75 | ||
|
|
37b16e8395 | ||
|
|
9c94953e0e | ||
|
|
2c48b8f881 | ||
|
|
4c4b78dda7 | ||
|
|
4ba9a7917f | ||
|
|
5d286ebc9e | ||
|
|
e69bbb46b3 | ||
|
|
f203c53e19 | ||
|
|
8a9a0c8396 | ||
|
|
813b08bf1c | ||
|
|
bce9b58265 | ||
|
|
85223629c1 | ||
|
|
9a73789788 | ||
|
|
25929483c3 | ||
|
|
0e90c54dbb | ||
|
|
5dea4ab18c | ||
|
|
7187397687 | ||
|
|
bf8454a963 | ||
|
|
2b2ac9b924 | ||
|
|
78b874936c | ||
|
|
b9866af6cd | ||
|
|
350e4a5753 | ||
|
|
2544d03434 | ||
|
|
d1c1eed52e | ||
|
|
2329cfd1da | ||
|
|
9960c63f59 | ||
|
|
680f9ae246 | ||
|
|
7994e66283 | ||
|
|
2c9d344b76 | ||
|
|
6a9e28700b | ||
|
|
811e5c1a8c | ||
|
|
545cef34a9 | ||
|
|
950c89a8bc | ||
|
|
7b5bc0fe3e | ||
|
|
e05514bc41 | ||
|
|
438abf6cea | ||
|
|
5d5ebb559b | ||
|
|
3be5675828 | ||
|
|
6482218a68 | ||
|
|
8d6824b03d | ||
|
|
69ab65dbc6 | ||
|
|
4b0b0e4451 | ||
|
|
5d21fd0f7c | ||
|
|
0184015ba8 | ||
|
|
ffb329a0d9 | ||
|
|
03a712fcfe | ||
|
|
652c2b6fd0 | ||
|
|
f0093499d1 | ||
|
|
c00ada5aee | ||
|
|
6c409bfa00 | ||
|
|
1c7637d28b | ||
|
|
48dc89c43d | ||
|
|
b60cc50508 | ||
|
|
4e66762036 | ||
|
|
ff4e1dd182 | ||
|
|
36442072ba | ||
|
|
ea134f52be | ||
|
|
fe97ba1c19 | ||
|
|
2cd8b73aa3 | ||
|
|
07a5b69511 | ||
|
|
da0e207b44 | ||
|
|
fb0edc0ee0 | ||
|
|
8a26a4aeec | ||
|
|
723ce1bd5d | ||
|
|
8408b39fbb | ||
|
|
5dfaf75440 | ||
|
|
bb3b3702e1 | ||
|
|
81138fcaef | ||
|
|
6be5398114 | ||
|
|
365ae8ef0a | ||
|
|
3932b24fda | ||
|
|
f44737216f | ||
|
|
e4180a0c1a | ||
|
|
356938d6d3 | ||
|
|
1090907178 | ||
|
|
da2f7073f9 | ||
|
|
57fe0e702c | ||
|
|
90d4a98e1e | ||
|
|
d047f8aa32 | ||
|
|
f656ec32c1 | ||
|
|
3415543175 | ||
|
|
4191bc86ef | ||
|
|
1cc0ef916f | ||
|
|
fdbee4562a | ||
|
|
5d793344cd | ||
|
|
559a45c917 | ||
|
|
cadbc09846 | ||
|
|
bcaca0b782 | ||
|
|
5cee7319c6 | ||
|
|
e960db0d3e | ||
|
|
eb2c05e9df | ||
|
|
353a6b9d0c | ||
|
|
5d2d269f11 | ||
|
|
9acb157fae | ||
|
|
4198b53996 | ||
|
|
d8286fb005 | ||
|
|
a7bf5e8873 | ||
|
|
fdec9ed6b8 | ||
|
|
a2e2072634 | ||
|
|
84cd83894b | ||
|
|
32e4145927 | ||
|
|
18dd177961 | ||
|
|
e94c65d24a | ||
|
|
e72c0d4480 | ||
|
|
1a7f1c3d15 | ||
|
|
ace5374813 | ||
|
|
41f91ea12d | ||
|
|
91bf5f93cd | ||
|
|
9445fa8005 | ||
|
|
6b491d1246 | ||
|
|
644045b307 | ||
|
|
0bf53a1c0d | ||
|
|
6b47ae232d | ||
|
|
536c3cc56b | ||
|
|
b75a8cb60d | ||
|
|
05ca1aa224 | ||
|
|
02d45bb6a7 | ||
|
|
8e805a4cf8 | ||
|
|
43c4c03832 | ||
|
|
bf2bcd1395 | ||
|
|
f9217dc066 | ||
|
|
dad4ca4ab4 | ||
|
|
b282ee8273 | ||
|
|
3dcb7d0a39 | ||
|
|
6703897fb1 | ||
|
|
eef2ed0d64 | ||
|
|
17bc4ade84 | ||
|
|
aea0896356 | ||
|
|
7c13ed6497 | ||
|
|
93dea4fa46 | ||
|
|
83fb93da11 | ||
|
|
3fbaffe9a2 | ||
|
|
3b93e8b8ec | ||
|
|
24cf087320 | ||
|
|
ae82a2d1cf | ||
|
|
2412bc1da4 | ||
|
|
42b00515eb | ||
|
|
f3c5d0862b | ||
|
|
e832921edf | ||
|
|
0c0ead26c0 | ||
|
|
f9a018638b | ||
|
|
d5ca8ddf1e | ||
|
|
650c29e75a | ||
|
|
ed5c20c612 | ||
|
|
49f1d1a8fa | ||
|
|
a87d6345c2 | ||
|
|
d83db53acb | ||
|
|
c944bd3b0e | ||
|
|
751cc3cadb | ||
|
|
80fe1116a8 | ||
|
|
81f9fd7473 | ||
|
|
9aaa88ef51 | ||
|
|
e2091eb986 | ||
|
|
22a8703978 | ||
|
|
1468a7b878 | ||
|
|
fe7211860f | ||
|
|
fddf80e74a | ||
|
|
5054391f6b | ||
|
|
5e096a277c | ||
|
|
ef2d00a254 | ||
|
|
d38159f68b | ||
|
|
dd29c9a2fa | ||
|
|
ca1b8a728d | ||
|
|
6b647cf4ea | ||
|
|
a21f2342d8 | ||
|
|
0e6f79c28e | ||
|
|
ab6563899c | ||
|
|
894d4eb051 | ||
|
|
f82122edf0 | ||
|
|
8d9c5bb762 | ||
|
|
76d94c0bc9 | ||
|
|
7a916fc78e | ||
|
|
73db2a202a | ||
|
|
31dceec787 | ||
|
|
a2106bba3e | ||
|
|
f9890bdc7f | ||
|
|
b321283f99 | ||
|
|
505e4b6586 | ||
|
|
b2efd065be | ||
|
|
050af30acb | ||
|
|
8a0c0de8a1 | ||
|
|
677dca2231 | ||
|
|
47ca08e432 | ||
|
|
8c940126b5 | ||
|
|
1cb396aa14 | ||
|
|
a47d271a33 | ||
|
|
363be13d12 | ||
|
|
3bc044e148 | ||
|
|
b8e6dfcd99 | ||
|
|
4b320c2af2 | ||
|
|
dc28d701ba | ||
|
|
71b7b7cc79 | ||
|
|
77c423f421 | ||
|
|
f6be4ad7ac | ||
|
|
8a157ba472 | ||
|
|
f6cbe899c6 | ||
|
|
7598c8319f | ||
|
|
a798f36529 | ||
|
|
779e84213e | ||
|
|
254975fcd3 | ||
|
|
e5773df1ab | ||
|
|
c2290f95cf | ||
|
|
6eb72c0303 | ||
|
|
59d9674aeb | ||
|
|
c4e79e46cf | ||
|
|
36ed5400be | ||
|
|
6378c69764 | ||
|
|
b44db20938 | ||
|
|
61cd7b42d4 | ||
|
|
77d64796e0 | ||
|
|
a4001c21b1 | ||
|
|
4fadba27dc | ||
|
|
9e1d01774f | ||
|
|
7eab4dd5b1 | ||
|
|
be4f0a2a90 | ||
|
|
0e6d380b7e | ||
|
|
1a73f7bef3 | ||
|
|
c45c17748e | ||
|
|
a518e7b210 | ||
|
|
57ad7ae1a3 | ||
|
|
e2dae1c4ab | ||
|
|
998d97b669 | ||
|
|
453d95a460 | ||
|
|
0d00f91b31 | ||
|
|
d3b87e8984 | ||
|
|
fcaad5c6cc | ||
|
|
8ca741792a | ||
|
|
0f687a7e34 | ||
|
|
736995c35b | ||
|
|
4ae548cc5b | ||
|
|
d55545849a | ||
|
|
942868f17f | ||
|
|
8a57bf52f9 | ||
|
|
260d87c97e | ||
|
|
cb1bac25a3 | ||
|
|
ef20ef7014 | ||
|
|
b88cad7b80 | ||
|
|
22ba44c271 | ||
|
|
ae2cc7ad9b | ||
|
|
3383e86064 | ||
|
|
a0ef3af155 | ||
|
|
c880f32d33 | ||
|
|
e8fcab4c6b | ||
|
|
7b20b68b6a | ||
|
|
974f264272 | ||
|
|
bcbb2b5139 | ||
|
|
1c6a795061 | ||
|
|
36246c2945 | ||
|
|
7af54f600f | ||
|
|
e09aaa2dc7 | ||
|
|
e3178d7579 | ||
|
|
b59dfbc3fd | ||
|
|
0f21688b3c | ||
|
|
801e30c1dc | ||
|
|
7049175827 | ||
|
|
f27a5a135b | ||
|
|
82ad9e249a | ||
|
|
fcff711a04 | ||
|
|
0c78b8d868 | ||
|
|
b6b54164a8 | ||
|
|
983daddebc | ||
|
|
605db9340c | ||
|
|
36ea04bd70 | ||
|
|
6f691e45d8 | ||
|
|
2c6558874d | ||
|
|
d60b432f0c | ||
|
|
adb9849650 | ||
|
|
48abbbf83e | ||
|
|
9e5361338c | ||
|
|
c5ecd71c6e | ||
|
|
b09bbba21b | ||
|
|
2db543573c | ||
|
|
cadd4df5d0 | ||
|
|
427de4b42f | ||
|
|
79cb82ea24 | ||
|
|
1b472c4ad7 | ||
|
|
21ab4950c8 | ||
|
|
1b2977d591 | ||
|
|
c54cf0bca2 | ||
|
|
935c990fe4 | ||
|
|
44f94f8398 | ||
|
|
8380cb1084 | ||
|
|
83fc4f46b2 | ||
|
|
9a97134a37 | ||
|
|
912010ed70 | ||
|
|
09b0bd8b09 | ||
|
|
c0dece8936 | ||
|
|
571b610417 | ||
|
|
658339047c | ||
|
|
13120712b1 | ||
|
|
10e1fad7f3 | ||
|
|
d7629763ef | ||
|
|
94ee0fb058 | ||
|
|
d4e8ce9c89 | ||
|
|
707e241f25 | ||
|
|
58fa94e8b8 | ||
|
|
72d307503e | ||
|
|
d9fd9163e4 | ||
|
|
21807c3a66 | ||
|
|
f499d2d8a9 | ||
|
|
0f9958bb26 | ||
|
|
8e66a9880c | ||
|
|
38e112fb06 | ||
|
|
bb0e48cd41 | ||
|
|
fd0edd93ea | ||
|
|
6359696bde | ||
|
|
1fee392989 | ||
|
|
dfdced9644 | ||
|
|
e50c1c374a | ||
|
|
dbcd051aae | ||
|
|
96571bb999 | ||
|
|
0620f6b6e3 | ||
|
|
ae163167b6 | ||
|
|
ba0bb32b5f | ||
|
|
b15e789b0b | ||
|
|
8c7afa2e7a | ||
|
|
87e30b9edf | ||
|
|
887ebe6f2f | ||
|
|
099581dddc | ||
|
|
3e84890765 | ||
|
|
d2fb0791d9 | ||
|
|
a2f22007cf | ||
|
|
d4dd531ac4 | ||
|
|
8374c81860 | ||
|
|
579f60e789 | ||
|
|
40b5f33c4e | ||
|
|
978a7fab4c | ||
|
|
f7790c46d2 | ||
|
|
9fc5b521e5 | ||
|
|
775e31c5e9 | ||
|
|
3339e30014 | ||
|
|
4ed44a2a8f | ||
|
|
6134e76030 | ||
|
|
e1ea210fe9 | ||
|
|
d9022a0383 | ||
|
|
0b0c1405ea | ||
|
|
e393e1f525 | ||
|
|
ad78cb1bcd | ||
|
|
e886614641 | ||
|
|
bc83362b35 | ||
|
|
b648f09f16 | ||
|
|
eb8d1626ea | ||
|
|
db94cd32d5 | ||
|
|
71fd5a13fc | ||
|
|
67c7ef37e6 | ||
|
|
2e22f4ea67 | ||
|
|
8be36f088b | ||
|
|
b985c2c784 | ||
|
|
e39d381f08 | ||
|
|
7694c7f97b | ||
|
|
eadb5eb216 | ||
|
|
cf5c46b2ce | ||
|
|
6e9dd669ba | ||
|
|
60ef93b510 | ||
|
|
e3aada0fff | ||
|
|
bbe1a44788 | ||
|
|
bfe0f346c8 | ||
|
|
8f10146d39 | ||
|
|
5f402488d4 | ||
|
|
07c48479af | ||
|
|
4bc2cebd60 | ||
|
|
dc242420f8 | ||
|
|
0656e3f536 | ||
|
|
cfffcda068 | ||
|
|
187885fdb9 | ||
|
|
f67b60dd82 | ||
|
|
92a2421a9b | ||
|
|
556d32729a | ||
|
|
4a3bd18bac | ||
|
|
de8f23bf2f | ||
|
|
3691a74d7e | ||
|
|
2aba4eccee | ||
|
|
3e6d02eccc | ||
|
|
add3437bcf | ||
|
|
2cf244058b | ||
|
|
971f137a21 | ||
|
|
b1a245c2a2 | ||
|
|
e8f957f344 | ||
|
|
74d43ca974 | ||
|
|
9af98089f2 | ||
|
|
b619204c5e | ||
|
|
27051aa01d | ||
|
|
23ffd23694 | ||
|
|
96b9cad2f8 | ||
|
|
35ebce6a85 | ||
|
|
9530350d06 | ||
|
|
c122863e45 | ||
|
|
b4de38fbb9 | ||
|
|
0c1ad1f4e5 | ||
|
|
e2a675054c | ||
|
|
6095f2174f | ||
|
|
0ad49e9b9d | ||
|
|
b4751ea87a | ||
|
|
d46d6a58ab | ||
|
|
dee6ea1663 | ||
|
|
74988a80bf | ||
|
|
24b011ef93 | ||
|
|
1c7486a7bc | ||
|
|
b30e2f0cc0 | ||
|
|
07d82e508e | ||
|
|
29f9cb6b4a | ||
|
|
b4e29d4776 | ||
|
|
a4aff25008 | ||
|
|
940dbca248 | ||
|
|
4097244d5b | ||
|
|
bb6e9b9e3f | ||
|
|
1d1f43afe3 | ||
|
|
5a4d00a788 | ||
|
|
578d410b77 | ||
|
|
84b11ae6a8 | ||
|
|
923972c543 | ||
|
|
62708830b1 | ||
|
|
a55b633d84 | ||
|
|
634c88e337 | ||
|
|
afa27a3f53 | ||
|
|
277126e9df | ||
|
|
c72fb7c05e | ||
|
|
396d4b456b | ||
|
|
594708c18f | ||
|
|
8159f90cc8 | ||
|
|
2eaa5f5bb6 | ||
|
|
8b890a9271 | ||
|
|
df1a4d7149 | ||
|
|
12c181a5aa | ||
|
|
480606eaf5 | ||
|
|
54f125a2f5 | ||
|
|
e04edf4a4e | ||
|
|
0a54ba9cae | ||
|
|
a074cdefa5 | ||
|
|
0382d4f114 | ||
|
|
60ab339d79 | ||
|
|
26a52ee451 | ||
|
|
79bd539a02 | ||
|
|
047000fb1d | ||
|
|
616e06d262 | ||
|
|
d9e91bcbf5 | ||
|
|
a0478279df | ||
|
|
58d1b62250 | ||
|
|
27c76a62f1 | ||
|
|
7f7640d326 | ||
|
|
d0412af18f | ||
|
|
1e577527b3 | ||
|
|
38bfc87fc1 | ||
|
|
1c09722d4f | ||
|
|
38e936fa35 | ||
|
|
d034063bab | ||
|
|
ebbe4465b3 | ||
|
|
38c39d4cb9 | ||
|
|
8bf01451a8 | ||
|
|
1b180ed60c | ||
|
|
0aa532ffa4 | ||
|
|
e5d6d319fd | ||
|
|
b49ae9c034 | ||
|
|
996401eb62 | ||
|
|
426c67631a | ||
|
|
7fa4a5f363 | ||
|
|
1843b9c44f | ||
|
|
fcea4c63a7 | ||
|
|
d5eead48cf | ||
|
|
389ce08dad | ||
|
|
7946894d33 | ||
|
|
7955a9747b | ||
|
|
ca200c81b3 | ||
|
|
b30662d2b4 | ||
|
|
1c84757d1d | ||
|
|
5db4fea3b5 | ||
|
|
3bcc8d3eba | ||
|
|
cc9a015111 | ||
|
|
08de00f640 | ||
|
|
1c5be59105 | ||
|
|
5b109e91d1 | ||
|
|
14db420cbe | ||
|
|
db08e993df | ||
|
|
26dbc8d00d | ||
|
|
a903b5e36c | ||
|
|
0789ebf9a9 | ||
|
|
198ce36fea | ||
|
|
40a89c9374 | ||
|
|
f267d820bf | ||
|
|
f44a099469 | ||
|
|
419b25f38d | ||
|
|
c23ff654ed | ||
|
|
b69267d94f | ||
|
|
1ddcde1684 | ||
|
|
33abda8fb3 | ||
|
|
39a9416427 | ||
|
|
9cc5d76888 | ||
|
|
19983283f2 | ||
|
|
75ac150908 | ||
|
|
66a7cba068 | ||
|
|
d71cea6fea | ||
|
|
27dbdad9b2 | ||
|
|
863507ade1 | ||
|
|
4660ae212c | ||
|
|
44114c0d19 | ||
|
|
565cd3da5c | ||
|
|
c55711c1eb | ||
|
|
5df066999b | ||
|
|
d9c9db332c | ||
|
|
bca3ce1e5f | ||
|
|
6121e62cc9 | ||
|
|
cbc34ade78 | ||
|
|
daaa3513ae | ||
|
|
0d6b62c8e7 | ||
|
|
a2d9326826 | ||
|
|
c847af3df1 | ||
|
|
ef220a5b36 | ||
|
|
695989969d | ||
|
|
3429de9eb6 | ||
|
|
f2e3c76539 | ||
|
|
1ca1c280f6 | ||
|
|
d73fdaf7ad | ||
|
|
071c541a4b | ||
|
|
0b8467c0b0 | ||
|
|
41e202fe7b | ||
|
|
269d0c00c5 | ||
|
|
146a7093f7 | ||
|
|
c9127c6d30 | ||
|
|
339c333679 | ||
|
|
a70ea536d4 | ||
|
|
1a62c0154d | ||
|
|
29ee0b5945 | ||
|
|
68e627bb04 | ||
|
|
32aca8c6a8 | ||
|
|
ef22651860 | ||
|
|
547c7d1b6d | ||
|
|
cabdd55cf5 | ||
|
|
d7a4c4f82d | ||
|
|
df5224cf12 | ||
|
|
a6625de5d5 | ||
|
|
515919b048 | ||
|
|
c21d1dd155 | ||
|
|
643b284e27 | ||
|
|
368b4fcfd4 | ||
|
|
1f4f98b513 | ||
|
|
8c343fb01f | ||
|
|
777aa64153 | ||
|
|
ae30d4b2cb | ||
|
|
4c12626b44 | ||
|
|
d389dcbedf | ||
|
|
58ff8f45cf | ||
|
|
826271c84d | ||
|
|
3a158c8249 | ||
|
|
6b14f6fbea | ||
|
|
e92dd48bbf | ||
|
|
250937a099 | ||
|
|
53b594a36a | ||
|
|
ea86ab667f | ||
|
|
8fc686bddf | ||
|
|
f60298a941 | ||
|
|
cb2674ebb6 | ||
|
|
3f92a0ccb4 | ||
|
|
cb7f4db207 | ||
|
|
6bfcccfbb6 | ||
|
|
9ef959ee46 | ||
|
|
c24ef3f6b5 | ||
|
|
86ea2ce863 | ||
|
|
646531393f | ||
|
|
29d4bebdca | ||
|
|
ac69cbc0b4 | ||
|
|
4e83663f90 | ||
|
|
0faa1aecad | ||
|
|
8546c59f52 | ||
|
|
944bd8c956 | ||
|
|
641217085f | ||
|
|
586775c8ff | ||
|
|
3f2f89768b | ||
|
|
1087b0965d | ||
|
|
6aedff75f1 | ||
|
|
43b4032bbb | ||
|
|
b57d56f317 | ||
|
|
6404f1b786 | ||
|
|
47f77a4dee | ||
|
|
4febaa68eb | ||
|
|
f5c83cb770 | ||
|
|
3fc0b1020c | ||
|
|
887ea275f6 | ||
|
|
4d10caecb9 | ||
|
|
3bfe4b6980 | ||
|
|
33bf294f71 | ||
|
|
11443beb22 | ||
|
|
c2c92ab196 | ||
|
|
d752c97aff | ||
|
|
f53a6cf05b | ||
|
|
b6ec8cf6f0 | ||
|
|
38ad893a5c | ||
|
|
dd2475e829 | ||
|
|
f9a3514c1d | ||
|
|
534b03ef5c | ||
|
|
822febba2e | ||
|
|
e989313b0d | ||
|
|
b713793063 | ||
|
|
0327f040e9 | ||
|
|
e4f89e5a05 | ||
|
|
069e411dc4 | ||
|
|
9dc72ef3ee | ||
|
|
61d774817f | ||
|
|
af98ef56a1 | ||
|
|
4bb93a947e | ||
|
|
8857fb24f0 | ||
|
|
21fdb41b09 | ||
|
|
3b3c778a0f | ||
|
|
a63c986c02 | ||
|
|
2279fb3788 | ||
|
|
f0ae259040 | ||
|
|
65f0445001 | ||
|
|
a7a794c709 | ||
|
|
4ce9ee520a | ||
|
|
70a65766c1 | ||
|
|
1ab0263347 | ||
|
|
c0f721d737 | ||
|
|
257197e1f1 | ||
|
|
3f80307154 | ||
|
|
14781da78e | ||
|
|
d4e4a4a8b7 | ||
|
|
aa5d3b9d90 | ||
|
|
48003554b4 | ||
|
|
bcb9f094c9 | ||
|
|
bbcfadbba4 | ||
|
|
0e7c6d6d1c | ||
|
|
eaed0cac8a | ||
|
|
d23492b9a8 | ||
|
|
6697649b97 | ||
|
|
5a2d9125d4 | ||
|
|
0b97823f92 | ||
|
|
f39514a623 | ||
|
|
0a247a9229 | ||
|
|
2fb831075e | ||
|
|
e0f8ac1eea | ||
|
|
8ff472042c | ||
|
|
5f4ee6cc68 | ||
|
|
de48c64bc9 | ||
|
|
01aa699462 | ||
|
|
801b280717 | ||
|
|
96b4bb0ce6 | ||
|
|
11b94f965c | ||
|
|
3532bf54e7 | ||
|
|
a35ab95809 | ||
|
|
36207ee29a | ||
|
|
d7d6986927 | ||
|
|
db81a5358f | ||
|
|
9f4c87c555 | ||
|
|
f77887e6a3 | ||
|
|
1907acd35d | ||
|
|
f7f8bad301 | ||
|
|
d2ae803ecc | ||
|
|
5416ba1048 | ||
|
|
071ca9462a | ||
|
|
02fc86af4f | ||
|
|
2dbfdc67c5 | ||
|
|
609c7c821f | ||
|
|
b239a4ff56 | ||
|
|
7fb5cb72f5 | ||
|
|
798cb92f50 | ||
|
|
9477ca0373 | ||
|
|
efa87e0e1a | ||
|
|
26dd107f48 | ||
|
|
4673398976 | ||
|
|
c72a990162 | ||
|
|
3f1f76b2e8 | ||
|
|
6675376241 | ||
|
|
12ec7a0392 | ||
|
|
1d9b0f771f | ||
|
|
f7ef896f48 | ||
|
|
da1d24bb5c | ||
|
|
e30586d314 | ||
|
|
58fceea247 | ||
|
|
36f72c857d | ||
|
|
39d472bdc8 | ||
|
|
64adfcceab | ||
|
|
419cadfe1d | ||
|
|
44b13acc61 | ||
|
|
13ae0e33c1 | ||
|
|
ff19cb68b9 | ||
|
|
c50f1ffcb4 | ||
|
|
e17ba2889a | ||
|
|
fdb4e46019 | ||
|
|
0be8a69eca | ||
|
|
69a4de8e0e | ||
|
|
fd78b2e3c3 | ||
|
|
6bc9f1c7fd | ||
|
|
861379b678 | ||
|
|
7969a75a19 | ||
|
|
b6d35a88db | ||
|
|
1087b5aebe | ||
|
|
4a626503f7 | ||
|
|
add74b0ad0 | ||
|
|
10823b3c98 | ||
|
|
8e85a233a9 | ||
|
|
19d8912680 | ||
|
|
b5d8d43e72 | ||
|
|
98896f838b | ||
|
|
3fa884f326 | ||
|
|
633f8d66f2 | ||
|
|
6b96231087 | ||
|
|
e614935693 | ||
|
|
6b15aa9c8e | ||
|
|
c9e01e0782 | ||
|
|
c18334002c | ||
|
|
e0fa97f7a2 | ||
|
|
e9b5147743 | ||
|
|
96ae77e5ab | ||
|
|
ba9ac0fa5d | ||
|
|
f43f1e7be1 | ||
|
|
88eba44f68 | ||
|
|
fac6f04943 | ||
|
|
56785f96a9 | ||
|
|
2013aa5db8 | ||
|
|
68c1d59638 | ||
|
|
3412ce64cb | ||
|
|
1c32534ba1 | ||
|
|
e509adfdab | ||
|
|
c42f3c329e | ||
|
|
32ab379003 | ||
|
|
1d777f8704 | ||
|
|
226b4ce722 | ||
|
|
edcf7f52af | ||
|
|
7e895403a9 | ||
|
|
d604e9c3f3 | ||
|
|
6debf25162 | ||
|
|
a81873c148 | ||
|
|
7475a683cc | ||
|
|
666f5a10d3 | ||
|
|
70a7840365 | ||
|
|
98a4a2158a | ||
|
|
0d5c196f39 | ||
|
|
3d5aff3e29 | ||
|
|
d324ddff3f | ||
|
|
72b0135410 | ||
|
|
820400d77f | ||
|
|
ba2fa497b1 | ||
|
|
6bec254d49 | ||
|
|
71aabe9fe4 | ||
|
|
f461a1978e | ||
|
|
bbc5287551 | ||
|
|
71108b6ba8 | ||
|
|
56760a0aac | ||
|
|
a06c8c00b3 | ||
|
|
40195ea993 | ||
|
|
e64b12097a | ||
|
|
cf793c198f | ||
|
|
f1a87ef529 | ||
|
|
4e5f51a4c8 | ||
|
|
36e9938011 | ||
|
|
cf4e5aae47 | ||
|
|
e71936063d | ||
|
|
ae5f63b1ed | ||
|
|
4a0a0e0bb6 | ||
|
|
c80ecf958c | ||
|
|
5a65a2e49f | ||
|
|
3ee8419802 | ||
|
|
90a5a14d30 | ||
|
|
6ae73e6c2b | ||
|
|
e394726eef | ||
|
|
c3f74b8dc2 | ||
|
|
00f4d3eaf3 | ||
|
|
ad55441bf6 | ||
|
|
0287e0481c | ||
|
|
93e4ab88fb | ||
|
|
1267cf9845 | ||
|
|
c588936c7e | ||
|
|
1ca8c80af1 | ||
|
|
08b696fd9b | ||
|
|
ef53885bd2 | ||
|
|
d27dd0e318 | ||
|
|
ada31888f4 | ||
|
|
41455cd47f | ||
|
|
b7903910de | ||
|
|
36af5f06b5 | ||
|
|
6bec250f6c | ||
|
|
ce667a9f9e | ||
|
|
2c8d579668 | ||
|
|
a3f7c1e867 | ||
|
|
3f2b0319fa | ||
|
|
4394039f29 | ||
|
|
2b870358e9 | ||
|
|
fab126ddfd | ||
|
|
ad7c851fdc | ||
|
|
bf8ce2e845 | ||
|
|
d81f09bf28 | ||
|
|
50d381cab9 | ||
|
|
ec38f939d5 | ||
|
|
a66f010af9 | ||
|
|
2325c83455 | ||
|
|
9d826c7063 | ||
|
|
bf6155b1bd | ||
|
|
8c122b7e09 | ||
|
|
5357c813e4 | ||
|
|
84503d9a81 | ||
|
|
6642f97231 | ||
|
|
b5c3f930f5 | ||
|
|
ba8412faa7 | ||
|
|
30c09eec47 | ||
|
|
6b32608fa8 | ||
|
|
888c29373b | ||
|
|
785b685e8d | ||
|
|
10a2593979 | ||
|
|
a0fd35bf5e | ||
|
|
1466c4e6cd | ||
|
|
944acd90a6 | ||
|
|
7101238eae | ||
|
|
8d0deaebba | ||
|
|
ecb4240d8d | ||
|
|
1898068f6b | ||
|
|
d0b64b6521 | ||
|
|
684a83b7c2 | ||
|
|
2eb45768c6 | ||
|
|
5bf95f8e75 | ||
|
|
766a1a6c00 | ||
|
|
e32ae8027d | ||
|
|
7b6a6e6e73 | ||
|
|
4ba41c8ae7 | ||
|
|
6c92e29b3b | ||
|
|
299b358c8f | ||
|
|
fcf481d7f3 | ||
|
|
add374f0a7 | ||
|
|
dba380ff24 | ||
|
|
5ea1bd4896 | ||
|
|
e553192e59 | ||
|
|
d506754e63 | ||
|
|
deec60d1a9 | ||
|
|
6214e10f01 | ||
|
|
ebad623032 | ||
|
|
0bcc604757 | ||
|
|
cc51a4870c | ||
|
|
b52e432ab7 | ||
|
|
371f5d9d98 | ||
|
|
093b5a7a7b | ||
|
|
a1199a52af | ||
|
|
073a2d5487 | ||
|
|
3313689799 | ||
|
|
5bc2abb0df | ||
|
|
0bc5d865b0 | ||
|
|
8fa19b3190 | ||
|
|
72d1dcd75c | ||
|
|
d3c989036a | ||
|
|
6253fed3bb | ||
|
|
cb07b04664 | ||
|
|
1126419e2e | ||
|
|
52db51ce10 | ||
|
|
791ec9132a | ||
|
|
e6ba4f63f7 | ||
|
|
310e6749b8 | ||
|
|
2218d261d2 | ||
|
|
c186d564cc | ||
|
|
cd995c74bd | ||
|
|
da49ac3b4a | ||
|
|
7115f95e45 | ||
|
|
425218908e | ||
|
|
e666aff9eb | ||
|
|
cdb6df4a8f | ||
|
|
7ca101e5dd | ||
|
|
60a36ee5f0 | ||
|
|
aa8eb5d389 | ||
|
|
599d33b822 | ||
|
|
b82dc187c1 | ||
|
|
5f861aa389 | ||
|
|
b691ce19f7 | ||
|
|
961e3445ce | ||
|
|
6e72b8d76e | ||
|
|
216c5317e1 | ||
|
|
ad3174b207 | ||
|
|
b2949bae6c | ||
|
|
461ea6c54d | ||
|
|
0446431f2f | ||
|
|
7928424931 | ||
|
|
8cb2b4a496 | ||
|
|
84e4deecd6 | ||
|
|
0b8c296ef5 | ||
|
|
cba119e116 | ||
|
|
b199b24b23 | ||
|
|
9070585701 | ||
|
|
9254b11f8d | ||
|
|
b96fe12aeb | ||
|
|
a78c2d805d | ||
|
|
ffaa3153b3 | ||
|
|
937f9e1711 | ||
|
|
e3108f7382 | ||
|
|
abd7074e1d | ||
|
|
31d0f867cb | ||
|
|
eb19fb783f | ||
|
|
c376f7e97c | ||
|
|
153a0b9354 | ||
|
|
b6e8239e25 | ||
|
|
ddc3579409 | ||
|
|
0aac42e19b | ||
|
|
f66f250936 | ||
|
|
faa2a97b5e | ||
|
|
4acd6a3c06 | ||
|
|
726a87b644 | ||
|
|
54716e9144 | ||
|
|
d51e682110 | ||
|
|
a4570b7b2f | ||
|
|
faf28d40c6 | ||
|
|
225fec8ebf | ||
|
|
8f6d84f3ad | ||
|
|
6270e4b101 | ||
|
|
5489442ebd | ||
|
|
469ec71074 | ||
|
|
470c908453 | ||
|
|
a18e71dc9b | ||
|
|
fc9590cb7a | ||
|
|
803b49083e | ||
|
|
4867a0df2b | ||
|
|
f539ab39e7 | ||
|
|
8ef2ff43b0 | ||
|
|
21bce5ec23 | ||
|
|
d86ee7a028 | ||
|
|
8ca8f291a1 | ||
|
|
47929c9d37 | ||
|
|
29fa839b24 | ||
|
|
15d31dbcbf | ||
|
|
124f1151db | ||
|
|
360054dda6 | ||
|
|
fb5bcac2d7 | ||
|
|
c9c97e8a4e | ||
|
|
e12ff6508c | ||
|
|
1fc6a7a1c6 | ||
|
|
f4eb31570e | ||
|
|
a3809b3fc7 | ||
|
|
5c6bbd2793 | ||
|
|
b3dae901a0 | ||
|
|
34903cf870 | ||
|
|
57d4189f02 | ||
|
|
0aee86a885 | ||
|
|
09b3e6ee74 | ||
|
|
547b8b0f91 | ||
|
|
006679ce5d | ||
|
|
b0b0b0d8d1 | ||
|
|
6934fe03ce | ||
|
|
4d15d81c7e | ||
|
|
15d9c272e0 | ||
|
|
149ebc0cf3 | ||
|
|
5d40397fa3 | ||
|
|
038e0bea86 | ||
|
|
3b73121c29 | ||
|
|
eb74bebf9c | ||
|
|
47b5bf3dc9 | ||
|
|
bf5848b5f5 | ||
|
|
69cfb63d03 | ||
|
|
f391afaef8 | ||
|
|
4e7465c08f | ||
|
|
491891a001 | ||
|
|
9f19c608e7 | ||
|
|
64efe9def2 | ||
|
|
3272117564 | ||
|
|
706df9ab78 | ||
|
|
a89281f98b | ||
|
|
74cebb37a8 | ||
|
|
04fb38757c | ||
|
|
58d90cc699 | ||
|
|
2ba9272043 | ||
|
|
e98f24279a | ||
|
|
004cf1d5c0 | ||
|
|
935f5aa529 | ||
|
|
35e8ed0944 | ||
|
|
3dc6bfe6ee | ||
|
|
556e9f52c8 | ||
|
|
4e2292f48f | ||
|
|
61beac9ef2 | ||
|
|
8139a9585d | ||
|
|
906409921f | ||
|
|
f6fcf7b1b2 | ||
|
|
8501af7d16 | ||
|
|
0a2c42c27f | ||
|
|
4ace93bff3 | ||
|
|
c5cfa2f143 | ||
|
|
06fecf813a | ||
|
|
2a172b0c0b | ||
|
|
1f74334c92 | ||
|
|
522b18ff7d | ||
|
|
732cd3798b | ||
|
|
024ced4b3e | ||
|
|
65c6e90f68 | ||
|
|
5a3afb9951 | ||
|
|
89ef5f3df4 | ||
|
|
d5b470ec24 | ||
|
|
af67149851 | ||
|
|
0cb6a505d1 | ||
|
|
7173d854d8 | ||
|
|
defc67c51d | ||
|
|
0391ed0fa3 | ||
|
|
6540da0112 | ||
|
|
9fcfbb6688 | ||
|
|
44b3a4e4f7 | ||
|
|
65d1042643 | ||
|
|
528f83ac87 | ||
|
|
7f399d6854 | ||
|
|
2df46b0bf5 | ||
|
|
e9af19e3dc | ||
|
|
64cdcea6b9 | ||
|
|
ca60d4eb86 | ||
|
|
edcba7a35a | ||
|
|
8f81888784 | ||
|
|
06ced2d544 | ||
|
|
22d25fd67e | ||
|
|
7163184423 | ||
|
|
0ab4d76d0f | ||
|
|
55e30df5ec | ||
|
|
01a49a8b65 | ||
|
|
6f65ad5255 | ||
|
|
7766a7b239 | ||
|
|
4e8c2cd1b8 | ||
|
|
9f6f7b8977 | ||
|
|
0a1095bfc6 | ||
|
|
3a8b205e8c | ||
|
|
d6f4dd0418 | ||
|
|
205f2e3526 | ||
|
|
af60e61cc7 | ||
|
|
e84a9ae114 | ||
|
|
c49e89605c | ||
|
|
141dc6d80f | ||
|
|
eed9534309 | ||
|
|
72307cd89f | ||
|
|
0d5e993042 | ||
|
|
6fd7baa10f | ||
|
|
d146652ab4 | ||
|
|
afc1d55b52 | ||
|
|
b7f977c09c | ||
|
|
7141918e27 | ||
|
|
a77deecb2e | ||
|
|
f32b539e45 | ||
|
|
3422dff72c | ||
|
|
6fc7028507 | ||
|
|
6f72141616 | ||
|
|
96639524e5 | ||
|
|
aa519f764f | ||
|
|
6188786d12 | ||
|
|
2a6c754123 | ||
|
|
a5c980626b | ||
|
|
a304515f90 | ||
|
|
9ee905c033 | ||
|
|
3527c45556 | ||
|
|
0c45311bf3 | ||
|
|
ced7f26809 | ||
|
|
e14c973a74 | ||
|
|
a3703d9025 | ||
|
|
4c0375ac2c | ||
|
|
1604a5a666 | ||
|
|
ac9c87a70f | ||
|
|
156ce300f6 | ||
|
|
01051ad675 | ||
|
|
329760e39d | ||
|
|
26bdcad0b3 | ||
|
|
e563a79278 | ||
|
|
7b70371ffa | ||
|
|
15dc3f469f | ||
|
|
49c5a7289c | ||
|
|
3d451824f3 | ||
|
|
8ba41e9e19 | ||
|
|
3a2d8846bc | ||
|
|
a03a7162dd | ||
|
|
5a546cbbd0 | ||
|
|
dc09ac078a | ||
|
|
743d169a75 | ||
|
|
d210760e08 | ||
|
|
ebc58ccd00 | ||
|
|
65d66876a8 | ||
|
|
e96e99fe0c | ||
|
|
2cca25450e | ||
|
|
3d4368544f | ||
|
|
849b8d0322 | ||
|
|
f7b597ab6b | ||
|
|
964523c84c | ||
|
|
ba97bd3eb5 | ||
|
|
7d9e6f3a23 | ||
|
|
212606f638 | ||
|
|
8ad5f28e99 | ||
|
|
f8ee7bc015 | ||
|
|
36785f46f2 | ||
|
|
088a76b3cc | ||
|
|
38b854ed90 | ||
|
|
db11e1731b | ||
|
|
a84ff4a0f8 | ||
|
|
3cf0fabe15 | ||
|
|
ff405f0aef | ||
|
|
1a3282eb8a | ||
|
|
3f40358e2d | ||
|
|
2ca35a2924 | ||
|
|
5490893756 | ||
|
|
4b9bbd37e3 | ||
|
|
120ff6c5a1 | ||
|
|
e9aa584c27 | ||
|
|
e1211521ff | ||
|
|
13d49bc9fb | ||
|
|
cebd5b6c71 | ||
|
|
ca9add7d93 | ||
|
|
6cc079aac7 | ||
|
|
d8d1b10de7 | ||
|
|
d4c3756f75 | ||
|
|
99b1deea3c | ||
|
|
c6f734277f | ||
|
|
65a0f1df9b | ||
|
|
18ea3f5c58 | ||
|
|
a110a69d7f | ||
|
|
c61f187e1a | ||
|
|
2e65ffd332 | ||
|
|
7697acc8aa | ||
|
|
31338846e3 | ||
|
|
db669c8ad4 | ||
|
|
6d5b3b0b17 | ||
|
|
0bea3caae7 | ||
|
|
f0c8b477eb | ||
|
|
58f6e94f90 | ||
|
|
5efe05af24 | ||
|
|
6773279d3e | ||
|
|
3461ae1fdf | ||
|
|
45b86761f6 | ||
|
|
ac7a1acee3 | ||
|
|
41ec4907da | ||
|
|
cccdec584e | ||
|
|
472da835bd | ||
|
|
30de46b840 | ||
|
|
8921b319c8 | ||
|
|
aa49398c29 | ||
|
|
27a2849619 | ||
|
|
9d583e2e5c | ||
|
|
01825ad87f | ||
|
|
769a6a9c63 |
139
.gitignore
vendored
139
.gitignore
vendored
@@ -1,14 +1,7 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
|
||||||
dist/
|
|
||||||
|
|
||||||
appsettings.Production.json
|
|
||||||
appsettings.Development.json
|
|
||||||
wwwroot
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
@@ -24,21 +17,16 @@ wwwroot
|
|||||||
[Rr]eleases/
|
[Rr]eleases/
|
||||||
x64/
|
x64/
|
||||||
x86/
|
x86/
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
bld/
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
[Ll]og/
|
[L]og/
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
# Visual Studio 2015 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
#wwwroot/
|
#wwwroot/
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
# MSTest test Results
|
||||||
[Tt]est[Rr]esult*/
|
[Tt]est[Rr]esult*/
|
||||||
[Bb]uild[Ll]og.*
|
[Bb]uild[Ll]og.*
|
||||||
@@ -52,28 +40,18 @@ TestResult.xml
|
|||||||
[Rr]eleasePS/
|
[Rr]eleasePS/
|
||||||
dlldata.c
|
dlldata.c
|
||||||
|
|
||||||
# Benchmark Results
|
# DNX
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
|
||||||
project.lock.json
|
project.lock.json
|
||||||
project.fragment.lock.json
|
|
||||||
artifacts/
|
artifacts/
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
|
||||||
*_i.c
|
*_i.c
|
||||||
*_p.c
|
*_p.c
|
||||||
*_h.h
|
*_i.h
|
||||||
*.ilk
|
*.ilk
|
||||||
*.meta
|
*.meta
|
||||||
*.obj
|
*.obj
|
||||||
*.iobj
|
|
||||||
*.pch
|
*.pch
|
||||||
*.pdb
|
*.pdb
|
||||||
*.ipdb
|
|
||||||
*.pgc
|
*.pgc
|
||||||
*.pgd
|
*.pgd
|
||||||
*.rsp
|
*.rsp
|
||||||
@@ -83,7 +61,6 @@ StyleCopReport.xml
|
|||||||
*.tlh
|
*.tlh
|
||||||
*.tmp
|
*.tmp
|
||||||
*.tmp_proj
|
*.tmp_proj
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
*.log
|
||||||
*.vspscc
|
*.vspscc
|
||||||
*.vssscc
|
*.vssscc
|
||||||
@@ -112,9 +89,6 @@ ipch/
|
|||||||
*.vspx
|
*.vspx
|
||||||
*.sap
|
*.sap
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
# TFS 2012 Local Workspace
|
||||||
$tf/
|
$tf/
|
||||||
|
|
||||||
@@ -135,14 +109,6 @@ _TeamCity*
|
|||||||
# DotCover is a Code Coverage Tool
|
# DotCover is a Code Coverage Tool
|
||||||
*.dotCover
|
*.dotCover
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
# NCrunch
|
||||||
_NCrunch_*
|
_NCrunch_*
|
||||||
.*crunch*.local.xml
|
.*crunch*.local.xml
|
||||||
@@ -174,7 +140,7 @@ publish/
|
|||||||
# Publish Web Output
|
# Publish Web Output
|
||||||
*.[Pp]ublish.xml
|
*.[Pp]ublish.xml
|
||||||
*.azurePubxml
|
*.azurePubxml
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
*.pubxml
|
*.pubxml
|
||||||
*.publishproj
|
*.publishproj
|
||||||
@@ -187,12 +153,12 @@ PublishScripts/
|
|||||||
# NuGet Packages
|
# NuGet Packages
|
||||||
*.nupkg
|
*.nupkg
|
||||||
# The packages folder can be ignored because of Package Restore
|
# The packages folder can be ignored because of Package Restore
|
||||||
**/[Pp]ackages/*
|
**/packages/*
|
||||||
# except build/, which is used as an MSBuild target.
|
# except build/, which is used as an MSBuild target.
|
||||||
!**/[Pp]ackages/build/
|
!**/packages/build/
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
#!**/[Pp]ackages/repositories.config
|
#!**/packages/repositories.config
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
# NuGet v3's project.json files produces more ignoreable files
|
||||||
*.nuget.props
|
*.nuget.props
|
||||||
*.nuget.targets
|
*.nuget.targets
|
||||||
|
|
||||||
@@ -209,13 +175,12 @@ AppPackages/
|
|||||||
BundleArtifacts/
|
BundleArtifacts/
|
||||||
Package.StoreAssociation.xml
|
Package.StoreAssociation.xml
|
||||||
_pkginfo.txt
|
_pkginfo.txt
|
||||||
*.appx
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
# Visual Studio cache files
|
||||||
# files ending in .cache can be ignored
|
# files ending in .cache can be ignored
|
||||||
*.[Cc]ache
|
*.[Cc]ache
|
||||||
# but keep track of directories ending in .cache
|
# but keep track of directories ending in .cache
|
||||||
!?*.[Cc]ache/
|
!*.[Cc]ache/
|
||||||
|
|
||||||
# Others
|
# Others
|
||||||
ClientBin/
|
ClientBin/
|
||||||
@@ -223,15 +188,11 @@ ClientBin/
|
|||||||
*~
|
*~
|
||||||
*.dbmdl
|
*.dbmdl
|
||||||
*.dbproj.schemaview
|
*.dbproj.schemaview
|
||||||
*.jfm
|
|
||||||
*.pfx
|
*.pfx
|
||||||
*.publishsettings
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
orleans.codegen.cs
|
orleans.codegen.cs
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
#bower_components/
|
#bower_components/
|
||||||
@@ -246,20 +207,15 @@ _UpgradeReport_Files/
|
|||||||
Backup*/
|
Backup*/
|
||||||
UpgradeLog*.XML
|
UpgradeLog*.XML
|
||||||
UpgradeLog*.htm
|
UpgradeLog*.htm
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
# SQL Server files
|
||||||
*.mdf
|
*.mdf
|
||||||
*.ldf
|
*.ldf
|
||||||
*.ndf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
# Business Intelligence projects
|
||||||
*.rdl.data
|
*.rdl.data
|
||||||
*.bim.layout
|
*.bim.layout
|
||||||
*.bim_*.settings
|
*.bim_*.settings
|
||||||
*.rptproj.rsuser
|
|
||||||
*- Backup*.rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
# Microsoft Fakes
|
||||||
FakesAssemblies/
|
FakesAssemblies/
|
||||||
@@ -269,7 +225,6 @@ FakesAssemblies/
|
|||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
# Node.js Tools for Visual Studio
|
||||||
.ntvs_analysis.dat
|
.ntvs_analysis.dat
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
# Visual Studio 6 build log
|
||||||
*.plg
|
*.plg
|
||||||
@@ -277,9 +232,6 @@ node_modules/
|
|||||||
# Visual Studio 6 workspace options file
|
# Visual Studio 6 workspace options file
|
||||||
*.opt
|
*.opt
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
# Visual Studio LightSwitch build output
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
@@ -299,48 +251,33 @@ paket-files/
|
|||||||
.idea/
|
.idea/
|
||||||
*.sln.iml
|
*.sln.iml
|
||||||
|
|
||||||
# CodeRush personal settings
|
# BookStore
|
||||||
.cr/personal
|
src/Acme.BookStore.Web/Logs/*
|
||||||
|
src/Acme.BookStore.Web.Host/Logs/*
|
||||||
|
src/Acme.BookStore.AuthServer/Logs/*
|
||||||
|
src/Acme.BookStore.HttpApi.Host/Logs/*
|
||||||
|
src/Acme.BookStore.HttpApi.HostWithIds/Logs/*
|
||||||
|
src/Acme.BookStore.DbMigrator/Logs/*
|
||||||
|
src/Acme.BookStore.Blazor.Server/Logs/*
|
||||||
|
src/Acme.BookStore.Blazor.Server.Tiered/Logs/*
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
# Use abp install-libs to restore.
|
||||||
__pycache__/
|
**/wwwroot/libs/*
|
||||||
*.pyc
|
public
|
||||||
|
dist
|
||||||
|
dist - 副本
|
||||||
|
.vscode
|
||||||
|
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Development.json
|
||||||
|
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Production.json
|
||||||
|
/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Development.json
|
||||||
|
/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Production.json
|
||||||
|
/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.Development.json
|
||||||
|
database_backup
|
||||||
|
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Staging.json
|
||||||
|
/Yi.Abp.Net8/src/Yi.Abp.Web/logs/
|
||||||
|
/Yi.Abp.Net8/src/Yi.Abp.Web/yi-abp-dev.db
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
package-lock.json
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
.claude
|
||||||
*.tss
|
components.d.ts
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
appsettings.Development.json
|
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2022 jacktang
|
Copyright (c) 2023 橙子
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
37
README-Docker.md
Normal file
37
README-Docker.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# 🍉Docker 构建说明
|
||||||
|
|
||||||
|
## 🍊后端
|
||||||
|
执行目录:Yi\Yi.Abp.Net8
|
||||||
|
|
||||||
|
#### 🍊启动
|
||||||
|
D:/code/csharp/source/Yi/Yi.Bbs.Vue3/yi-bbs.conf 为我的配置文件,内部带了默认的配置文件,根据自己配置进行更改
|
||||||
|
|
||||||
|
//不带配置文件
|
||||||
|
docker run -d --name yi.admin -p 19001:19001 jiftcc/yi.admin:1.0.0
|
||||||
|
|
||||||
|
//带配置文件
|
||||||
|
docker run -d --name yi.admin -p 19001:19001 -v D:/code/csharp/source/Yi/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json:/app/appsettings.json jiftcc/yi.admin:1.0.0
|
||||||
|
|
||||||
|
|
||||||
|
#### 🍊完整代码编译
|
||||||
|
docker build -t jiftcc/yi.admin:1.0.0 -f Dockerfile .
|
||||||
|
|
||||||
|
#### 🍊快速产物编译
|
||||||
|
docker build -t jiftcc/yi.admin:1.0.0 -f DockerfileFast .
|
||||||
|
|
||||||
|
****
|
||||||
|
|
||||||
|
## 🍇前端
|
||||||
|
执行目录:Yi\Yi.Bbs.Vue3
|
||||||
|
|
||||||
|
#### 🍇启动
|
||||||
|
D:/code/csharp/source/Yi/Yi.Bbs.Vue3/yi-bbs.conf 为我的conf配置目录,默认反向代理到ccnetcore.com,根据自己后端地址进行修改配置
|
||||||
|
|
||||||
|
docker run -d --name yi.bbs -p 18001:18001 -v D:/code/csharp/source/Yi/Yi.Bbs.Vue3/yi-bbs.conf:/etc/nginx/conf.d/yi-bbs.conf jiftcc/yi.bbs:1.0.0
|
||||||
|
|
||||||
|
#### 🍇完整代码编译
|
||||||
|
docker build -t jiftcc/yi.bbs:1.0.0 -f Dockerfile .
|
||||||
|
|
||||||
|
#### 🍇快速产物编译
|
||||||
|
docker build -t jiftcc/yi.bbs:1.0.0 -f DockerfileFast .
|
||||||
|
|
||||||
225
README-en.md
Normal file
225
README-en.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
<h1 align="center"><img align="left" height="150px" src="https://ccnetcore.com/prod-api/wwwroot/logo.png"> Yi-Framework</h1>
|
||||||
|
<h4 align="center">A .NET 8 Web open-source Asp.NetCore framework focused on user experience.</h4>
|
||||||
|
<h5 align="center">Supports Native/Abp.vNext/Furion/Ruoyi/Pure</h5>
|
||||||
|
<h2 align="center">A comprehensive solution that ultimately becomes a wheel</h2>
|
||||||
|
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
|
||||||
|
English | [简体中文](README.md)
|
||||||
|
****
|
||||||
|
## 🍍 Introduction:
|
||||||
|
YiFramework is a DDD (Domain-Driven Design) backend open-source framework based on .Net8, Abp.vNext, and SqlSugar.
|
||||||
|
|
||||||
|
Who says ABP is complex? Who says DDD is difficult?`Breaking conventions, simplifying complexity.`,Newcomer-friendly and one of the best approaches for project extensions.
|
||||||
|
|
||||||
|
Modular design allows for the independent inclusion or exclusion of components based on business needs. It is an all-encompassing framework where you may gain unique insights.
|
||||||
|
|
||||||
|
A Comprehensive Solution, Ultimately Just Another Wheel.
|
||||||
|
|
||||||
|
(Frequent updates, feel free to watch for continuous updates.)
|
||||||
|
|
||||||
|
— This is not just a program; it is also a work of art, focused on artistic development!
|
||||||
|
|
||||||
|
> Core Features: Simple and easy to use, the framework is not referenced in a packaged form, but is provided directly with the project alongside the source code. It offers maximum freedom and complies with the MIT license, allowing for unrestricted modifications (please indicate the source).
|
||||||
|
|
||||||
|
**Branch Directory:**
|
||||||
|
|
||||||
|
- Branch **Abp**: Based on the Abp.vNext branch, DDD (Domain-Driven Design) simplifies the essence of development, providing support for multiple frontends from one backend.
|
||||||
|
|
||||||
|
- Yi.Abp.Net8:Backend
|
||||||
|
- Yi.Bbs.Vue3:Bbs Community - Frontend
|
||||||
|
- Yi.Doc.Md: Open Source Documentation Tutorial
|
||||||
|
- Yi.Pure.Vue3:Pure TS Backend Frontend
|
||||||
|
- Yi.RuoYi.Vue3:RuoYi JS Backend Frontend
|
||||||
|
|
||||||
|
****
|
||||||
|
## 🍉 docker
|
||||||
|
|
||||||
|
Full content:README-Docker.md
|
||||||
|
|
||||||
|
backend:`docker run -d --name yi.admin -p 19001:19001 jiftcc/yi.admin:last`
|
||||||
|
|
||||||
|
bbs frontend:`docker run -d --name yi.bbs -p 18001:18001 -v /home/Yi/Yi.Bbs.Vue3/yi-bbs.conf:/etc/nginx/conf.d/yi-bbs.conf jiftcc/yi.bbs:last`
|
||||||
|
|
||||||
|
> In addition, we provide Docker build operation, and we hope that you can build your own image through this method
|
||||||
|
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
## 🍊 Official website and demo link:
|
||||||
|
|
||||||
|
Let's get straight to the point and provide the link.
|
||||||
|
|
||||||
|
YiCommunity official website URL.(Bbs):[ccnetcore.com](https://ccnetcore.com) (Now live, welcome to join!)
|
||||||
|
|
||||||
|
Rbac:https://ccnetcore.com:1000 (userName cc\password 123456)
|
||||||
|
|
||||||
|
Pure:https://ccnetcore.com:1001 (userNamecc\password 123456)
|
||||||
|
|
||||||
|
## 🍏 Support:
|
||||||
|
|
||||||
|
- [x] Fully supports monolithic application architecture
|
||||||
|
- [x] Fully supports distributed application architecture
|
||||||
|
- [x] Fully supports microservices architecture
|
||||||
|
|
||||||
|
****
|
||||||
|
## 🍇 Explosive Detail Yi Framework Tutorial Navigation:
|
||||||
|
|
||||||
|
1. [Framework Quick Start Guide](https://ccnetcore.com/article/aaa00329-7f35-d3fe-d258-3a0f8380b742)(Completed)
|
||||||
|
2. [Framework Functionality Module Tutorials](https://ccnetcore.com/article/8c464ab3-8ba5-2761-a4b0-3a0f83a9f312)(Completed)
|
||||||
|
3. [Practical Development Exercises](https://ccnetcore.com/article/e89c9593-f337-ada7-d108-3a0f83ae48e6)(Completed)
|
||||||
|
4. [Chengzi Ops CI/CD Tutorial](https://ccnetcore.com/article/6b80ed42-50cd-db15-c073-3a0fa8f7fd77)(Completed)
|
||||||
|
5. [Version Update Log](https://ccnetcore.com/article/e9e69a38-ce1e-06f5-7944-3a0fdc942ef3)(Completed)
|
||||||
|
|
||||||
|
****
|
||||||
|
## 🍓 Its philosophy:
|
||||||
|
Who says ABP is complicated? Who says DDD is difficult? Break the norm, simplify complexity, and serve as one of the best ways for newcomers and project second development.
|
||||||
|
|
||||||
|
> For every hundred people, there are a hundred different interpretations of DDD. The YiFramework may not strict adherence to DDD principles, but it is built on the shoulders of giants, distilled from numerous projects to craft a best practice.
|
||||||
|
|
||||||
|
Effortlessly achieve rapid development; typically, simplicity and elegance are hard to reconcile. The YiFramework does not solely pursue extreme decoupling but considers user experience and ease of use.
|
||||||
|
|
||||||
|
A user-oriented rapid development backend framework.
|
||||||
|
|
||||||
|
> Once you truly get hands-on, you'll understand this: extreme simplicity is also a form of elegance.
|
||||||
|
****
|
||||||
|
|
||||||
|
## 🍍 Features
|
||||||
|
- A user-oriented backend framework that is easy to use, suitable for small, medium, and enterprise-level projects.
|
||||||
|
- The project comes with the source code directly embedded, without packaging, making it ideal for secondary development and modification.
|
||||||
|
- Includes a large number of reusable modules for common scenarios.
|
||||||
|
- Elegantly supports distributed and microservices architectures.
|
||||||
|
- And more…
|
||||||
|
|
||||||
|
## 🥭 Core Technologies
|
||||||
|
#### Backend
|
||||||
|
C# Asp.NetCore 8.0
|
||||||
|
- [x] Dynamic API: Abp.vNext
|
||||||
|
- [x] Authentication and Authorization: Jwt
|
||||||
|
- [x] Logging: Serilog
|
||||||
|
- [x] Modularization: Abp.vNext
|
||||||
|
- [x] Dependency Injection: Autofac
|
||||||
|
- [x] Object Mapping: Mapster
|
||||||
|
- [x] ORM: SqlsugarCore
|
||||||
|
- [x] Multi-tenancy: Abp.vNext
|
||||||
|
- [x] Background Tasks: Quartz.Net
|
||||||
|
- [x] Local Caching: Abp.vNext
|
||||||
|
- [x] Distributed Caching: Abp.vNext
|
||||||
|
- [x] Event Bus: Abp.vNext
|
||||||
|
|
||||||
|
#### Frontend
|
||||||
|
js Vue3
|
||||||
|
- [x] Asynchronous Requests: axios
|
||||||
|
- [x] Charts: echarts
|
||||||
|
- [x] UI: element-plus
|
||||||
|
- [x] State Management: pinia
|
||||||
|
- [x] Routing: vue-router
|
||||||
|
- [x] Bundling: vite
|
||||||
|
|
||||||
|
#### DevOps
|
||||||
|
- [x] Deployment: nginx
|
||||||
|
- [x] CICD: gitlab+Jenkins
|
||||||
|
- [x] Docker: harbor
|
||||||
|
|
||||||
|
#### 🍉 Demo:
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/101.png"/></td>
|
||||||
|
<td><img src="readme/102.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/103.png"/></td>
|
||||||
|
<td><img src="readme/104.png"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/201.png"/></td>
|
||||||
|
<td><img src="readme/202.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/203.png"/></td>
|
||||||
|
<td><img src="readme/204.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/205.png"/></td>
|
||||||
|
<td><img src="readme/206.png"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/1.png"/></td>
|
||||||
|
<td><img src="readme/2.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/3.png"/></td>
|
||||||
|
<td><img src="readme/4.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/3.png"/></td>
|
||||||
|
<td><img src="readme/4.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/5.png"/></td>
|
||||||
|
<td><img src="readme/6.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/7.png"/></td>
|
||||||
|
<td><img src="readme/8.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/9.png"/></td>
|
||||||
|
<td><img src="readme/10.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/11.png"/></td>
|
||||||
|
<td><img src="readme/12.png"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## 🌶 Thank you:
|
||||||
|
|
||||||
|
[橙子]https://ccnetcore.com
|
||||||
|
|
||||||
|
[XWen]https://gitee.com/on-wensil
|
||||||
|
|
||||||
|
[朝夕教育]https://www.zhaoxiedu.net
|
||||||
|
|
||||||
|
[Sqlsugar老杰哥]https://www.donet5.com/Home/Doc
|
||||||
|
|
||||||
|
[车神]微信公众号搜索Dotnet技术进阶
|
||||||
|
|
||||||
|
[RuYiAdmin如意老兄]https://gitee.com/pang-mingjun/RuYiAdmin
|
||||||
|
|
||||||
|
[ZrAdminNetCore字母老哥]https://gitee.com/izory/ZrAdminNetCore
|
||||||
|
|
||||||
|
[Admin.NET]https://gitee.com/zuohuaijun/Admin.NET
|
||||||
|
|
||||||
|
[Furion百小僧]https://furion.baiqian.ltd/
|
||||||
|
|
||||||
|
****
|
||||||
|
## 🌽 Contact Us:
|
||||||
|
|
||||||
|
Author's QQ:`454313500`
|
||||||
|
|
||||||
|
QQ group chat:官方一群(Full)、官方二群(Full)、官方三群:`786308927`(Full)、官方四群:`498310311`(Full)、官方五群:`981136525`(New)
|
||||||
|
|
||||||
|
WeChat Group Chat:官方微信一群(Full)、官方微信二群
|
||||||
|
|
||||||
|
WeChat Community: Add the author's WeChat chengzilaoge520 (橙子老哥520),Note: Join the group.
|
||||||
|
|
||||||
|
Contact the author, everyone here is a consultant.
|
||||||
|
|
||||||
|
Official website message area:[ccnetcore.com](https://ccnetcore.com)
|
||||||
|
|
||||||
|
****
|
||||||
|
## 🍄 FQA:
|
||||||
|
|
||||||
|
Visit the official website to view the message board.
|
||||||
|
|
||||||
|
[the message board](https://ccnetcore.com/discuss/1641030787056930818)
|
||||||
324
README.md
324
README.md
@@ -1,184 +1,147 @@
|
|||||||
<h1 align="center"><img align="left" height="150px" src="https://user-images.githubusercontent.com/68722157/138828506-f58b7c57-5e10-4178-8f7d-5d5e12050113.png"> Yi框架</h1>
|
<h1 align="center"><img align="left" height="150px" src="https://ccnetcore.com/prod-api/wwwroot/logo.png"> Yi框架</h1>
|
||||||
<h4 align="center">一套以用户体验出发的.Net6 Web开源框架</h4>
|
<h4 align="center">一套以用户体验出发的.Net8 Web开源框架</h4>
|
||||||
<h5 align="center">支持原生版本、Furion版本、Abp版本,前端后台接入Ruoyi Vue3.0</h5>
|
<h5 align="center">支持Abp.vNext 版本原生版本、Furion版本,前端接入Ruoyi/Pure Vue</h5>
|
||||||
<h2 align="center">集大成者,终究轮子</h2>
|
<h2 align="center">集大成者,终究轮子</h2>
|
||||||
|
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
|
||||||
|
本项目 CDN 加速及安全防护由 Tencent EdgeOne 赞助
|
||||||
|
|
||||||
|
[亚洲最佳CDN、边缘和安全解决方案 - Tencent EdgeOne](https://edgeone.ai/zh?from=github)
|
||||||
|
|
||||||
|
<img src="readme/edgeone.png"/>
|
||||||
|
|
||||||
[English](README-en.md) | 简体中文
|
[English](README-en.md) | 简体中文
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
****
|
****
|
||||||
### 简介:
|
## 🍍 简介:
|
||||||
|
YiFramework是一个基于.Net8+Abp.vNext+SqlSugar的DDD领域驱动设计后端开源框架
|
||||||
|
|
||||||
|
谁说Abp复杂?谁说DDD难?`打破常规,化繁为简`,新人入门,项目二开,最佳方式之一
|
||||||
|
|
||||||
**中文:意框架**(和他的名字一样“简易”,同时接入Java的Ruoyi Vue3.0前端)
|
**中文:意框架**(和他的名字一样“简易”,同时接入Java的Ruoyi Vue3.0前端)
|
||||||
|
|
||||||
模块分化较多,可根据业务自行引用或抛弃,集大成者,大而全乎,也许你能从中学习到一些独特见解
|
模块化,可根据业务自行引用或抛弃,集大成者,大而全乎,也许你能从中学习到一些独特见解
|
||||||
|
|
||||||
**英文:YiFramework**
|
**英文:YiFramework**
|
||||||
|
|
||||||
Yi框架-一套与SqlSugar一样爽的.Net6开源框架。
|
Yi框架-一套与SqlSugar一样爽的.Net8开源框架。
|
||||||
与Sqlsugar理念一致,以用户体验出发。
|
与Sqlsugar理念一致,以用户体验出发。
|
||||||
适合.Net6学习、Sqlsugar学习 、项目二次开发。
|
全生态拥抱AI,接入AI,100%代码经过AI洗礼
|
||||||
集大成者,终究轮子
|
集大成者,终究轮子
|
||||||
|
|
||||||
Yi框架最新版本标签:`v3.0.0`,具体版本可以查看标签迭代
|
(更新频繁,可watching持续关注。)
|
||||||
|
|
||||||
(项目与Sqlsugar同步更新,但这作者老杰哥代码天天爆肝到凌晨两点,我们也尽量会跟上他的脚步。更新频繁,所以可watching持续关注。)
|
|
||||||
|
|
||||||
————这不仅仅是一个程序,更是一个艺术品,面向艺术的开发!
|
————这不仅仅是一个程序,更是一个艺术品,面向艺术的开发!
|
||||||
|
|
||||||
> 核心特点:简单好用,框架不以打包形式引用,而是直接以项目附带源码给出,自由度拉满,遵循Mit协议,允许随意修改(请注明来源即可)
|
> 核心特点:简单好用,框架不以打包形式引用,而是直接以项目附带源码给出,自由度拉满,遵循Mit协议,允许随意修改(请注明来源即可)
|
||||||
|
|
||||||
**分支:**
|
**分支目录:**
|
||||||
|
|
||||||
(本项目由EFCore版本历经4年不断迭代至Sqlsugar版本,现EFcore版本已弃用,目前sqlsugar已带业务功能)
|
- 分支**Abp**: 基于Abp.vNext分支,DDD领域驱动设计,回归开发本质,极度简单,一个后台支持以下多个前端
|
||||||
|
|
||||||
- (推荐) **Furion**: 基于Furion分支,回归开发本质,极度简单,用起来贼爽
|
- Yi.Abp.Net8:后端
|
||||||
|
- Yi.Bbs.Vue3:Bbs社区 前端
|
||||||
|
- Yi.Doc.Md: 开源文档教程
|
||||||
|
- Yi.Pure.Vue3:Pure ts后台前端
|
||||||
|
- Yi.RuoYi.Vue3:RuoYi js后台前端
|
||||||
|
|
||||||
- ~~**Framework**~~: 框架分支,所有东西都在这里
|
****
|
||||||
|
## 🍉 docker 一键启动
|
||||||
|
|
||||||
- ~~**SqlSugar**:.Net6 DDD领域驱动设计 简单分层微服务架构~~
|
完整内容在:README-Docker.md
|
||||||
|
|
||||||
- ~~**SqlSugar-Dev**:为sqlsugar分支的实时开发版本~~
|
后端:`docker run -d --name yi.admin -p 19001:19001 jiftcc/yi.admin:last`
|
||||||
|
|
||||||
- ~~**abp**:基于abp.vnext项目~~
|
bbs前端:`docker run -d --name yi.bbs -p 18001:18001 -v /home/Yi/Yi.Bbs.Vue3/yi-bbs.conf:/etc/nginx/conf.d/yi-bbs.conf jiftcc/yi.bbs:last`
|
||||||
|
|
||||||
|
> 另外我们提供docker的build操作,我们更希望你能通过此种方式二开构建属于自己的镜像
|
||||||
|
|
||||||
****
|
****
|
||||||
|
|
||||||
**目录:**
|
## 🍊 官网及演示地址:
|
||||||
|
|
||||||
Yi后端框架分为3个部分:
|
废话少说直接上地址
|
||||||
|
|
||||||
- Infrastructure(基础设施,框架底层+sqlsugar+furion)
|
Yi社区官网网址(Bbs社区正式):[ccnetcore.com](https://ccnetcore.com) (已上线,欢迎加入)
|
||||||
- Module(应用模块,可选项,例如缓存模块、微信模块、文件模块、日志模块等)
|
|
||||||
- Application(业务模块,用于开发)
|
|
||||||
|
|
||||||
另外,光说不练假把式,我们不仅仅提供一个空白的框架,还同时提供3个基于yi框架的业务模块,没有听错,目前为1个后端,支持3个前端。各个模块关系解耦,可单独使用其中的任意业务模块
|
Rbac后台演示地址:https://data.ccnetcore.com:1000 (用户cc、密码123456)
|
||||||
|
|
||||||
- Yi.RuoYi.Vue3:Ruoyi后台管理系统Rbac Vue3前端(推荐)
|
Pure后台演示地址:https://data.ccnetcore.com:1001 (用户cc、密码123456)
|
||||||
|
|
||||||
- Yi.Furion.Net6:.NET6后端(推荐)
|
## 🍏 支持:
|
||||||
|
|
||||||
- Yi.App.Vue3:移动端App Vue3前端
|
|
||||||
|
|
||||||
- Yi.BBS.Vue3:Web网页端BBS论坛 Vue3+Ts前端
|
|
||||||
|
|
||||||
后续我们持续更新各大应用模块及业务模块:shop商场、erp进销存、mes工厂系统等
|
|
||||||
|
|
||||||
业务支持并扩展至各个领域,用于具体项目的二次开发极大复用后端代码及前端代码,以通用的部分+不通的部分快速二开
|
|
||||||
|
|
||||||
|
|
||||||
### 演示地址:
|
|
||||||
|
|
||||||
废话少说直接上地址,**请不要**更改里面的数据
|
|
||||||
|
|
||||||
官网网址:[ccnetcore.com](https://ccnetcore.com) (已上线,欢迎加入)
|
|
||||||
|
|
||||||
Bbs社区系统:[ccnetcore.com](https://ccnetcore.com) (已上线,欢迎加入)
|
|
||||||
|
|
||||||
Rbac后台管理系统:[yi.ccnetcore.com](http://yi.ccnetcore.com) (已上线)~~管理员账号:cc 、 123456~~
|
|
||||||
|
|
||||||
App移动端系统:[xxx](xxx)正在部署
|
|
||||||
|
|
||||||
网关地址:~~[gate.ccnetcore.com/swagger](http://gate.ccnetcore.com/swagger)~~(目前使用单体架构部署,无需网关)
|
|
||||||
|
|
||||||
### 支持:
|
|
||||||
|
|
||||||
- [x] 完全支持单体应用架构
|
- [x] 完全支持单体应用架构
|
||||||
- [x] 完全支持分布式应用架构
|
- [x] 完全支持分布式应用架构
|
||||||
- [x] 完全支持微服务架构
|
- [x] 完全支持微服务架构
|
||||||
|
|
||||||
****
|
****
|
||||||
### 详细到爆炸的Yi框架教程导航:
|
|
||||||
|
|
||||||
1. [框架快速开始](https://ccnetcore.com/article/1641733850189139969)(已完成)
|
## 🍇 详细到爆炸的Yi框架教程导航:
|
||||||
2. [框架模块教程](https://ccnetcore.com/article/1641733991574933505)(已完成)
|
|
||||||
3. [应用模块教程](https://ccnetcore.com/article/1641734073091231745)
|
0. [社区导航大全](https://ccnetcore.com/article/aaa00329-7f35-d3fe-d258-3a0f8380b742/fb8c871b-41fc-21bc-474f-3a154498f42b)
|
||||||
4. [Yi.RBAC后台系统](https://ccnetcore.com/article/1641734171128893441)
|
|
||||||
5. [Yi.BBS社区系统](https://ccnetcore.com/article/1641734308475572225)
|
1. [框架快速开始教程](https://ccnetcore.com/article/aaa00329-7f35-d3fe-d258-3a0f8380b742)(已完成)
|
||||||
|
2. [框架功能模块教程](https://ccnetcore.com/article/8c464ab3-8ba5-2761-a4b0-3a0f83a9f312)(已完成)
|
||||||
|
3. [实战演练开发教程](https://ccnetcore.com/article/e89c9593-f337-ada7-d108-3a0f83ae48e6)(已完成)
|
||||||
|
4. [橙子运维CICD教程](https://ccnetcore.com/article/6b80ed42-50cd-db15-c073-3a0fa8f7fd77)(已完成)
|
||||||
|
5. [版本更新日志](https://ccnetcore.com/article/e9e69a38-ce1e-06f5-7944-3a0fdc942ef3)(已完成)
|
||||||
|
|
||||||
****
|
****
|
||||||
### 它的理念:
|
## 🍓 它的理念:
|
||||||
优雅的进行快速开发,通常,简单程度与优雅程度不可兼得,Yi框架并不一昧的追求极致的解耦,会站在用户使用角度上,在使用难易度进行考虑衡量
|
谁说Abp复杂?谁说DDD难?打破常规,化繁为简,新人入门,项目二开,最佳方式之一
|
||||||
|
|
||||||
例如:我们大部分功能紧密贴合Sqlsugar,虽然缺少其他orm的替换性,但在使用程度上降低的使用难度
|
> 一百个人,就有一百种DDD,Yi框架不一定是极度严格的DDD,而是站在巨人的肩膀上,经过极多项目的提炼,摸索出一种最佳实践
|
||||||
|
|
||||||
|
|
||||||
|
优雅的进行快速开发,通常,简单程度与优雅程度不可兼得,Yi框架并不一昧的追求极致的解耦,会站在用户使用角度上,在使用难易度进行考虑衡量
|
||||||
|
|
||||||
> 一个面向用户的快速开发后端框架
|
> 一个面向用户的快速开发后端框架
|
||||||
|
|
||||||
在真正的使用这,你会明白这一点,极致的简单,也是优雅的一种体现。
|
在真正的使用过,你会明白这一点,极致的简单,也是优雅的一种体现。
|
||||||
****
|
****
|
||||||
|
|
||||||
### 特点:
|
## 🍍 特点
|
||||||
- 面向用户的后端框架,使用简单,适合小型、企业级项目
|
- 面向用户的后端框架,使用简单,适合小型、中型、企业级项目
|
||||||
- 项目内置源码,不打包
|
- 项目直接内置源码,不打包,非常适合进行二开改造
|
||||||
- 开箱即用
|
|
||||||
- 支持模块化
|
|
||||||
- 支持动态Api
|
|
||||||
- 支持属性注入
|
|
||||||
- 内置包含大量通用场景模块
|
- 内置包含大量通用场景模块
|
||||||
|
- 优雅支持分布式及微服务架构
|
||||||
- 等等
|
- 等等
|
||||||
|
|
||||||
### 基础设施简介
|
## 🍍 基础设施简介
|
||||||
- Jwt鉴权
|
|
||||||
- 接口级别授权
|
|
||||||
- 对象映射
|
|
||||||
- O/RM
|
|
||||||
- 数据过滤
|
|
||||||
- 多租户
|
|
||||||
- 逻辑删除
|
|
||||||
- 审计日志
|
|
||||||
- 种子数据
|
|
||||||
- 工作单元
|
|
||||||
- 模块化
|
|
||||||
- 动态Api
|
|
||||||
- 属性注入
|
|
||||||
- 自动依赖注入
|
|
||||||
- 当前用户
|
|
||||||
- 仓储
|
|
||||||
- Crud
|
|
||||||
|
|
||||||
|
以下全部功能可直接使用:
|
||||||
|
|
||||||
### 内置模块简介
|
- [Abp.vNext官网](https://docs.abp.io/zh-Hans/abp/latest/)
|
||||||
- 后台任务
|
|
||||||
- 本地缓存
|
|
||||||
- 分布式缓存
|
|
||||||
- 事件总线
|
|
||||||
- 字典管理
|
|
||||||
- 文件管理
|
|
||||||
- 图片操作
|
|
||||||
- Excel操作
|
|
||||||
- 操作日志管理
|
|
||||||
- Sms短信
|
|
||||||
- 微信支付
|
|
||||||
- WebFirst代码生成
|
|
||||||
|
|
||||||
### 业务项目
|
- [SqlSugar官网](https://www.donet5.com/home/doc)
|
||||||
- RABC后台管理系统
|
|
||||||
- BBS社区系统
|
## 🍅 内置模块简介
|
||||||
- APP移动端系统
|
- Rbac权限管理系统(已上线)(支持pure、ruoyi前端)
|
||||||
|
- Bbs论坛社区系统(已上线)
|
||||||
|
|
||||||
> 重复的东西,无需再写一遍,这也是优雅的体现之一
|
> 重复的东西,无需再写一遍,这也是优雅的体现之一
|
||||||
|
|
||||||
****
|
****
|
||||||
### 核心技术
|
## 🥭 核心技术
|
||||||
#### 后端
|
#### 后端
|
||||||
C# Asp.NetCore 6.0
|
C# Asp.NetCore 8.0
|
||||||
- [x] 动态Api:Cike.AutoApi
|
- [x] 动态Api:Abp.vNext
|
||||||
- [x] 鉴权授权:Jwt
|
- [x] 鉴权授权:Jwt
|
||||||
- [x] 日志:Nlog
|
- [x] 日志:Serilog
|
||||||
- [x] 模块化:StartupModules
|
- [x] 模块化:Abp.vNext
|
||||||
- [x] 依赖注入:Autofac
|
- [x] 依赖注入:Autofac
|
||||||
- [x] 对象映射:Mapster
|
- [x] 对象映射:Mapster
|
||||||
- [x] ORM:SqlsugarCore
|
- [x] ORM: SqlsugarCore
|
||||||
- [x] 多租户:Abp
|
- [x] 多租户:Abp.vNext
|
||||||
- [x] 后台任务:Quartz.Net
|
- [x] 后台任务:Quartz.Net
|
||||||
- [x] 本地缓存:MemortCache
|
- [x] 本地缓存:Abp.vNext
|
||||||
- [x] 分布式缓存:CSRedisCore
|
- [x] 分布式缓存:Abp.vNext
|
||||||
- [x] 事件总线:Cike.EventBus
|
- [x] 事件总线:Abp.vNext
|
||||||
- [x] 图像操作:SixLabors.ImageSharp
|
|
||||||
- [x] Excle操作:ExcelToObject.Npoi
|
|
||||||
|
|
||||||
#### 前端
|
#### 前端
|
||||||
js Vue3.2
|
js Vue3
|
||||||
- [x] 异步请求:axios
|
- [x] 异步请求:axios
|
||||||
- [x] 图表:echarts
|
- [x] 图表:echarts
|
||||||
- [x] ui:element-plus
|
- [x] ui:element-plus
|
||||||
@@ -191,10 +154,11 @@ js Vue3.2
|
|||||||
- [x] CICD:gitlab+Jenkins
|
- [x] CICD:gitlab+Jenkins
|
||||||
- [x] Docker:harbor
|
- [x] Docker:harbor
|
||||||
|
|
||||||
****
|
|
||||||
### 业务支持模块:
|
|
||||||
|
|
||||||
RABC权限管理系统(正在更新)
|
****
|
||||||
|
## 🍌 业务支持模块:
|
||||||
|
|
||||||
|
#### 🍒 RABC权限管理系统(持续更新)
|
||||||
(采用ruoyi前端)
|
(采用ruoyi前端)
|
||||||
- 用户管理
|
- 用户管理
|
||||||
- 角色管理
|
- 角色管理
|
||||||
@@ -209,80 +173,112 @@ RABC权限管理系统(正在更新)
|
|||||||
- 定时任务
|
- 定时任务
|
||||||
- 缓存列表
|
- 缓存列表
|
||||||
- 服务监控
|
- 服务监控
|
||||||
- WebFirst代码生成工具
|
|
||||||
|
|
||||||
**演示截图:**
|
#### 🍐 BBS社区论坛系统(持续更新)
|
||||||

|
(采用vue3前端)
|
||||||

|
- 文章功能
|
||||||

|
- 板块功能
|
||||||

|
- 主题功能
|
||||||

|
- 个人中心
|
||||||

|
- 授权中心
|
||||||

|
- 权限管理
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
BBS论坛系统(持续迭代)
|
#### 🍉 演示截图:
|
||||||
- 文章管理
|
<table>
|
||||||
- 评论管理
|
<tr>
|
||||||
- 主题管理
|
<td><img src="readme/101.png"/></td>
|
||||||
- 板块管理
|
<td><img src="readme/102.png"/></td>
|
||||||
- 点赞管理
|
</tr>
|
||||||
- 等等
|
<tr>
|
||||||
|
<td><img src="readme/103.png"/></td>
|
||||||
|
<td><img src="readme/104.png"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
APP移动端系统(持续迭代)
|
<table>
|
||||||
- 动态查询
|
<tr>
|
||||||
- 我的资料
|
<td><img src="readme/201.png"/></td>
|
||||||
|
<td><img src="readme/202.png"/></td>
|
||||||
ERP进销存系统(持续迭代)
|
</tr>
|
||||||
- 供货商管理
|
<tr>
|
||||||
- 等等
|
<td><img src="readme/203.png"/></td>
|
||||||
|
<td><img src="readme/204.png"/></td>
|
||||||
SHOP电商系统(持续迭代)
|
</tr>
|
||||||
- SPU管理
|
<tr>
|
||||||
- SKU管理
|
<td><img src="readme/205.png"/></td>
|
||||||
- 商品规格
|
<td><img src="readme/206.png"/></td>
|
||||||
- 商品分类
|
</tr>
|
||||||
- 等等
|
</table>
|
||||||
|
|
||||||
|
|
||||||
****
|
<table>
|
||||||
### 感谢:
|
<tr>
|
||||||
|
<td><img src="readme/1.png"/></td>
|
||||||
|
<td><img src="readme/2.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/3.png"/></td>
|
||||||
|
<td><img src="readme/4.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/3.png"/></td>
|
||||||
|
<td><img src="readme/4.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/5.png"/></td>
|
||||||
|
<td><img src="readme/6.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/7.png"/></td>
|
||||||
|
<td><img src="readme/8.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/9.png"/></td>
|
||||||
|
<td><img src="readme/10.png"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><img src="readme/11.png"/></td>
|
||||||
|
<td><img src="readme/12.png"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
**大力支持**: Eleven神、Sqlsugar上海杰哥、Gerry、哲学的老张
|
## 🌶 感谢:
|
||||||
|
|
||||||
[橙子]https://ccnetcore.com
|
[橙子]https://ccnetcore.com
|
||||||
|
|
||||||
[lzw]https://github.com/yeslode
|
[XWen]https://gitee.com/on-wensil
|
||||||
|
|
||||||
[朝夕教育]https://www.zhaoxiedu.net
|
[朝夕教育]https://www.zhaoxiedu.net
|
||||||
|
|
||||||
[Sqlsugar老杰哥]https://www.donet5.com/Home/Doc
|
[Sqlsugar老杰哥]https://www.donet5.com/Home/Doc
|
||||||
|
|
||||||
|
[车神]微信公众号搜索Dotnet技术进阶
|
||||||
|
|
||||||
[RuYiAdmin如意老兄]https://gitee.com/pang-mingjun/RuYiAdmin
|
[RuYiAdmin如意老兄]https://gitee.com/pang-mingjun/RuYiAdmin
|
||||||
|
|
||||||
[ZrAdminNetCore字母老哥]https://gitee.com/izory/ZrAdminNetCore
|
[ZrAdminNetCore字母老哥]https://gitee.com/izory/ZrAdminNetCore
|
||||||
|
|
||||||
[Admin.NET周哥]https://gitee.com/zuohuaijun/Admin.NET
|
[Admin.NET]https://gitee.com/zuohuaijun/Admin.NET
|
||||||
|
|
||||||
[Furion百小僧]https://furion.baiqian.ltd/
|
[Furion百小僧]https://furion.baiqian.ltd/
|
||||||
|
|
||||||
****
|
****
|
||||||
### 联系我们:
|
## 🌽 联系我们:
|
||||||
|
|
||||||
作者QQ:`454313500`,2029年之前作者24小时在线,时刻保持活跃更新。
|
作者QQ:`454313500`,2029年之前作者24小时在线,时刻保持活跃更新。
|
||||||
|
|
||||||
QQ交流群:官方一群(已满)、官方二群(已满)、官方三群:`786308927`(基本已满)、官方四群:`498310311`(新群)
|
QQ交流群:官方一群(已满)、官方二群(已满)、官方三群:`786308927`(已满)、官方四群:`498310311`(已满)、官方五群:`981136525`
|
||||||
|
|
||||||
|
微信交流群:官方微信一群(已满)、官方微信二群(已满)、官方微信三群
|
||||||
|
|
||||||
|
微信交流群:加作者微信 chengzilaoge520 (橙子老哥520),备注拉群
|
||||||
|
|
||||||
联系作者,这里人人都是顾问
|
联系作者,这里人人都是顾问
|
||||||
|
|
||||||
官方网址留言区:[ccnetcore.com](https://ccnetcore.com)
|
官方网址留言区:[ccnetcore.com](https://ccnetcore.com)
|
||||||
|
|
||||||
****
|
****
|
||||||
### FQA:
|
## 🍄 FQA:
|
||||||
|
|
||||||
前往官网查看留言区
|
前往官网查看留言区
|
||||||
|
|
||||||
|
|||||||
11
Yi.Abp.Net8/.claude/settings.local.json
Normal file
11
Yi.Abp.Net8/.claude/settings.local.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(dotnet build \"E:\\code\\github\\Yi\\Yi.Abp.Net8\\module\\ai-hub\\Yi.Framework.AiHub.Application\\Yi.Framework.AiHub.Application.csproj\" --no-restore)",
|
||||||
|
"Read(//e/code/github/Yi/Yi.Ai.Vue3/**)",
|
||||||
|
"Bash(dotnet build:*)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Yi.Abp.Net8/.dockerignore
Normal file
33
Yi.Abp.Net8/.dockerignore
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
!**/.gitignore
|
||||||
|
!.git/HEAD
|
||||||
|
!.git/config
|
||||||
|
!.git/packed-refs
|
||||||
|
!.git/refs/heads/**
|
||||||
|
appsettings.Development.json
|
||||||
|
appsettings.Production.json
|
||||||
|
appsettings.Staging.json
|
||||||
129
Yi.Abp.Net8/CLAUDE.md
Normal file
129
Yi.Abp.Net8/CLAUDE.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Yi.Abp.Net8 is a modular, multi-tenant SaaS platform built on ABP Framework 8.3.4 with .NET 8.0. It uses **SqlSugar** (not EF Core) as the ORM and follows Domain-Driven Design (DDD) principles. The platform includes AI/ML features (chat, models, agents, token tracking), RBAC, forum, messaging, and digital collectibles modules.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Solution Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
Yi.Abp.Net8/
|
||||||
|
├── src/ # Main application host
|
||||||
|
│ └── Yi.Abp.Web/ # ASP.NET Core 8.0 Web Host (port 19001)
|
||||||
|
├── framework/ # Framework layer (shared infrastructure)
|
||||||
|
│ ├── Yi.Framework.Core # Core utilities, JSON handling
|
||||||
|
│ ├── Yi.Framework.SqlSugarCore # SqlSugar ORM abstraction (v5.1.4.197-preview22)
|
||||||
|
│ ├── Yi.Framework.SqlSugarCore.Abstractions # Repository interfaces
|
||||||
|
│ ├── Yi.Framework.AspNetCore # ASP.NET Core extensions
|
||||||
|
│ ├── Yi.Framework.AspNetCore.Authentication.OAuth # QQ, Gitee OAuth
|
||||||
|
│ ├── Yi.Framework.Ddd.Application # DDD application base classes
|
||||||
|
│ ├── Yi.Framework.BackgroundWorkers.Hangfire # Job scheduling
|
||||||
|
│ ├── Yi.Framework.Caching.FreeRedis # Redis caching
|
||||||
|
│ └── Yi.Framework.SemanticKernel # AI/ML integration
|
||||||
|
├── module/ # Business modules (each follows 5-layer DDD pattern)
|
||||||
|
│ ├── ai-hub/ # AI services (chat, models, sessions, agents)
|
||||||
|
│ ├── rbac/ # Role-Based Access Control (core auth/authz)
|
||||||
|
│ ├── bbs/ # Forum/community
|
||||||
|
│ ├── chat-hub/ # Real-time messaging
|
||||||
|
│ ├── audit-logging/ # Audit trail tracking
|
||||||
|
│ ├── code-gen/ # Code generation
|
||||||
|
│ ├── tenant-management/ # Multi-tenancy support
|
||||||
|
│ ├── digital-collectibles/ # NFT/digital assets
|
||||||
|
│ └── ai-stock/ # AI-powered stock analysis
|
||||||
|
├── test/ # Unit tests (xUnit + NSubstitute + Shouldly)
|
||||||
|
├── client/ # HTTP API clients
|
||||||
|
└── tool/ # Development utilities
|
||||||
|
```
|
||||||
|
|
||||||
|
### Module Structure (DDD Layers)
|
||||||
|
|
||||||
|
Each module follows this pattern:
|
||||||
|
|
||||||
|
```
|
||||||
|
module/[feature]/
|
||||||
|
├── [Feature].Domain.Shared/ # Constants, enums, shared DTOs
|
||||||
|
├── [Feature].Domain/ # Entities, aggregates, domain services
|
||||||
|
├── [Feature].Application.Contracts/ # Service interfaces, DTOs
|
||||||
|
├── [Feature].Application/ # Application services (implementations)
|
||||||
|
└── [Feature].SqlSugarCore/ # Repository implementations, DbContext
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dependency Flow:** Application → Domain + Application.Contracts → Domain.Shared → Framework
|
||||||
|
|
||||||
|
### Module Registration
|
||||||
|
|
||||||
|
All modules are registered in `src/Yi.Abp.Web/YiAbpWebModule.cs`. When adding a new module:
|
||||||
|
|
||||||
|
1. Add `DependsOn` attribute in `YiAbpWebModule`
|
||||||
|
2. Add conventional controller in `PreConfigureServices`:
|
||||||
|
```csharp
|
||||||
|
options.ConventionalControllers.Create(typeof(YiFramework[Feature]ApplicationModule).Assembly,
|
||||||
|
option => option.RemoteServiceName = "[service-name]");
|
||||||
|
```
|
||||||
|
|
||||||
|
### API Routing
|
||||||
|
|
||||||
|
All API routes use the unified prefix: `/api/app/{service-name}/{controller}/{action}`
|
||||||
|
|
||||||
|
Registered service names:
|
||||||
|
- `default` - Main application services
|
||||||
|
- `rbac` - Authentication, authorization, user/role management
|
||||||
|
- `ai-hub` - AI chat, models, sessions, agents
|
||||||
|
- `bbs` - Forum posts and comments
|
||||||
|
- `chat-hub` - Real-time messaging
|
||||||
|
- `tenant-management` - Multi-tenant configuration
|
||||||
|
- `code-gen` - Code generation utilities
|
||||||
|
- `digital-collectibles` - NFT/digital assets
|
||||||
|
- `ai-stock` - Stock analysis
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
**ORM:** SqlSugar (NOT Entity Framework Core)
|
||||||
|
|
||||||
|
**Configuration** (`appsettings.json`):
|
||||||
|
```json
|
||||||
|
"DbConnOptions": {
|
||||||
|
"Url": "DataSource=yi-abp-dev.db",
|
||||||
|
"DbType": "Sqlite", // Sqlite, Mysql, Sqlserver, Oracle, PostgreSQL
|
||||||
|
"EnabledCodeFirst": true, // Auto-create tables
|
||||||
|
"EnabledDbSeed": true, // Auto-seed data
|
||||||
|
"EnabledSaasMultiTenancy": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multi-tenancy:** Tenant isolation via `HeaderTenantResolveContributor` (NOT cookie-based). Tenant is resolved from `__tenant` header.
|
||||||
|
|
||||||
|
## Key Technologies
|
||||||
|
|
||||||
|
| Component | Technology |
|
||||||
|
|-----------|-----------|
|
||||||
|
| Framework | ABP 8.3.4 |
|
||||||
|
| .NET Version | .NET 8.0 |
|
||||||
|
| ORM | SqlSugar 5.1.4.197-preview22 |
|
||||||
|
| Authentication | JWT Bearer + Refresh Tokens |
|
||||||
|
| OAuth | QQ, Gitee |
|
||||||
|
| Caching | FreeRedis (optional) |
|
||||||
|
| Background Jobs | Hangfire (in-memory or Redis) |
|
||||||
|
| Logging | Serilog (daily rolling files) |
|
||||||
|
| Testing | xUnit + NSubstitute + Shouldly |
|
||||||
|
| Container | Autofac |
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- **JSON Serialization:** Uses Microsoft's `System.Text.Json`, NOT Newtonsoft.Json. Date format handled via `DatetimeJsonConverter`.
|
||||||
|
- **Multi-tenancy:** Tenant resolved from `__tenant` header, NOT cookies.
|
||||||
|
- **Rate Limiting:** Disabled in development, enabled in production (1000 req/60s sliding window).
|
||||||
|
- **Swagger:** Available at `/swagger` in development.
|
||||||
|
- **Hangfire Dashboard:** Available at `/hangfire` (requires JWT authorization).
|
||||||
|
- **Background Workers:** Disabled in development (`AbpBackgroundWorkerOptions.IsEnabled = false`).
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
1. **Branch:** Main branch is `abp`, current development branch is `ai-hub`.
|
||||||
|
2. **Commit Convention:** Chinese descriptive messages with prefixes (`feat:`, `fix:`, `style:`).
|
||||||
|
3. **Testing:** Run `dotnet test` before committing.
|
||||||
|
4. **Building:** Use `dotnet build --no-restore` for faster builds after initial restore.
|
||||||
22
Yi.Abp.Net8/Dockerfile
Normal file
22
Yi.Abp.Net8/Dockerfile
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||||
|
USER root
|
||||||
|
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||||
|
RUN echo "Asia/Shanghai" > /etc/timezone
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 19001
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
WORKDIR /main
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/main/src/Yi.Abp.Web"
|
||||||
|
RUN dotnet restore "Yi.Abp.Web.csproj"
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
WORKDIR "/main/src/Yi.Abp.Web"
|
||||||
|
RUN dotnet publish "Yi.Abp.Web.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "Yi.Abp.Web.dll"]
|
||||||
11
Yi.Abp.Net8/DockerfileFast
Normal file
11
Yi.Abp.Net8/DockerfileFast
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||||
|
USER root
|
||||||
|
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||||
|
RUN echo "Asia/Shanghai" > /etc/timezone
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 19001
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ["./publish","."]
|
||||||
|
ENTRYPOINT ["dotnet", "Yi.Abp.Web.dll"]
|
||||||
596
Yi.Abp.Net8/Yi.Abp.sln
Normal file
596
Yi.Abp.Net8/Yi.Abp.sln
Normal file
@@ -0,0 +1,596 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.7.34202.233
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Web", "src\Yi.Abp.Web\Yi.Abp.Web.csproj", "{15913E44-DA92-44B9-9AC5-E9457EA34BF5}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SqlSugarCore", "framework\Yi.Framework.SqlSugarCore\Yi.Framework.SqlSugarCore.csproj", "{DC431ECC-C75D-4B01-8B79-4861948179BB}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B782C78B-6C17-49E6-A237-3383BA720766}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0D10EEF2-FBAE-4C72-B816-A52823FC299B}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "framework", "framework", "{77B949E9-530E-45A5-9657-20F7D5C6875C}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "module", "module", "{2317227D-7796-4E7B-BEDB-7CD1CAE7B853}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.SqlSugarCore", "src\Yi.Abp.SqlSugarCore\Yi.Abp.SqlSugarCore.csproj", "{9A7BBA40-28D6-4900-9E1D-D627A516EE72}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Application", "src\Yi.Abp.Application\Yi.Abp.Application.csproj", "{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Application.Contracts", "src\Yi.Abp.Application.Contracts\Yi.Abp.Application.Contracts.csproj", "{51EEBF59-3D37-4681-981D-56F8D8F8968D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Domain", "src\Yi.Abp.Domain\Yi.Abp.Domain.csproj", "{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Domain.Shared", "src\Yi.Abp.Domain.Shared\Yi.Abp.Domain.Shared.csproj", "{F4D5A496-BFBE-470B-A05B-CB5823B47E72}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6A5375C6-1D55-4E93-9B19-736F1C68CBC3}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
common.props = common.props
|
||||||
|
end.sh = end.sh
|
||||||
|
logo.png = logo.png
|
||||||
|
start.sh = start.sh
|
||||||
|
tool.bat = tool.bat
|
||||||
|
usings.props = usings.props
|
||||||
|
version.props = version.props
|
||||||
|
publish.bat = publish.bat
|
||||||
|
publish_Demo.bat = publish_Demo.bat
|
||||||
|
Dockerfile = Dockerfile
|
||||||
|
DockerfileFast = DockerfileFast
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SqlSugarCore.Abstractions", "framework\Yi.Framework.SqlSugarCore.Abstractions\Yi.Framework.SqlSugarCore.Abstractions.csproj", "{FD6D6860-3753-4747-8A26-977E4A3001F9}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core", "framework\Yi.Framework.Core\Yi.Framework.Core.csproj", "{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Mapster", "framework\Yi.Framework.Mapster\Yi.Framework.Mapster.csproj", "{1995A019-C8AE-467E-B427-ED57D6CBF44F}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore", "framework\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj", "{F5011C0D-209B-4A98-BBE3-68157503EEF8}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Ddd.Application.Contracts", "framework\Yi.Framework.Ddd.Application.Contracts\Yi.Framework.Ddd.Application.Contracts.csproj", "{0A8296A3-C11F-4F13-8E49-6BC8188D4804}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Ddd.Application", "framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj", "{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rbac", "rbac", "{9CC7A457-1236-40BA-B47B-E7B710A3F061}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Application.Contracts", "module\rbac\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj", "{1C360956-8CD8-407E-B87F-D0BD57068EB9}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Application", "module\rbac\Yi.Framework.Rbac.Application\Yi.Framework.Rbac.Application.csproj", "{4F02B08D-5FE2-460D-BCA5-DA565151AE30}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Domain", "module\rbac\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj", "{C04D3F71-1557-46D0-B810-97B1FBB6AB73}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Domain.Shared", "module\rbac\Yi.Framework.Rbac.Domain.Shared\Yi.Framework.Rbac.Domain.Shared.csproj", "{A2BB899D-4F9A-4184-81BD-94B938E2AB03}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.SqlSugarCore", "module\rbac\Yi.Framework.Rbac.SqlSugarCore\Yi.Framework.Rbac.SqlSugarCore.csproj", "{4503A2F9-139D-4CBC-AF11-689C34F0D77B}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bbs", "bbs", "{E902A945-4F41-4E96-A0DA-9F66CDA22261}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.Domain.Shared", "module\bbs\Yi.Framework.Bbs.Domain.Shared\Yi.Framework.Bbs.Domain.Shared.csproj", "{EB9349E2-256D-41EB-A345-21635A1361B3}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.Domain", "module\bbs\Yi.Framework.Bbs.Domain\Yi.Framework.Bbs.Domain.csproj", "{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.Application.Contracts", "module\bbs\Yi.Framework.Bbs.Application.Contracts\Yi.Framework.Bbs.Application.Contracts.csproj", "{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.Application", "module\bbs\Yi.Framework.Bbs.Application\Yi.Framework.Bbs.Application.csproj", "{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.SqlSugarCore", "module\bbs\Yi.Framework.Bbs.SqlSugarCore\Yi.Framework.Bbs.SqlSugarCore.csproj", "{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "audit-logging", "audit-logging", "{73CCF2C4-B9FD-44AB-8D4B-0A421805B094}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AuditLogging.SqlSugarCore", "module\audit-logging\Yi.Framework.AuditLogging.SqlSugarCore\Yi.Framework.AuditLogging.SqlSugarCore.csproj", "{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore.Authentication.OAuth", "framework\Yi.Framework.AspNetCore.Authentication.OAuth\Yi.Framework.AspNetCore.Authentication.OAuth.csproj", "{791AC2FA-50D3-4408-8D68-31DA72F608BE}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Test", "test\Yi.Abp.Test\Yi.Abp.Test.csproj", "{68627BC2-F049-4C69-AD17-81DF9478E8CE}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant-management", "{499A8C71-7892-42D0-A77E-48756E1EFF16}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.SqlSugarCore", "module\tenant-management\Yi.Framework.TenantManagement.SqlSugarCore\Yi.Framework.TenantManagement.SqlSugarCore.csproj", "{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.Domain", "module\tenant-management\Yi.Framework.TenantManagement.Domain\Yi.Framework.TenantManagement.Domain.csproj", "{54D8E2BC-591C-4344-A58E-874D49C00B41}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AuditLogging.Domain", "module\audit-logging\Yi.Framework.AuditLogging.Domain\Yi.Framework.AuditLogging.Domain.csproj", "{EFD13211-17B5-400A-B99A-9F6F4E520C1E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AuditLogging.Domain.Shared", "module\audit-logging\Yi.Framework.AuditLogging.Domain.Shared\Yi.Framework.AuditLogging.Domain.Shared.csproj", "{9C8C3C53-3DCE-4516-867E-228858E61B26}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.Application", "module\tenant-management\Yi.Framework.TenantManagement.Application\Yi.Framework.TenantManagement.Application.csproj", "{17816837-E53B-486B-B796-53C601FE6CD9}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.Application.Contracts", "module\tenant-management\Yi.Framework.TenantManagement.Application.Contracts\Yi.Framework.TenantManagement.Application.Contracts.csproj", "{FA735055-CBDD-4EFD-B84B-85810DA1425E}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code-gen", "code-gen", "{4FFE7212-21F2-476D-B628-3C65E6C5075E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application", "module\code-gen\Yi.Framework.CodeGen.Application\Yi.Framework.CodeGen.Application.csproj", "{97EC40D7-DBFA-467A-98CB-221AF27B14F2}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application.Contracts", "module\code-gen\Yi.Framework.CodeGen.Application.Contracts\Yi.Framework.CodeGen.Application.Contracts.csproj", "{882BC563-2F75-4B95-AC96-F4BF23F5E69D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain", "module\code-gen\Yi.Framework.CodeGen.Domain\Yi.Framework.CodeGen.Domain.csproj", "{85CB8517-2B80-42D8-B954-081079AC9BA0}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain.Shared", "module\code-gen\Yi.Framework.CodeGen.Domain.Shared\Yi.Framework.CodeGen.Domain.Shared.csproj", "{EEFF0F05-2709-4151-A8CE-667935CEAE0B}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching.FreeRedis", "framework\Yi.Framework.Caching.FreeRedis\Yi.Framework.Caching.FreeRedis.csproj", "{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.SqlSugarCore", "module\code-gen\Yi.Framework.CodeGen.SqlSugarCore\Yi.Framework.CodeGen.SqlSugarCore.csproj", "{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client", "client", "{8B27846A-043D-4F2F-8140-5CEC9D1863B5}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.HttpApi.Client", "client\Yi.Abp.HttpApi.Client\Yi.Abp.HttpApi.Client.csproj", "{6B554DCC-3A81-4624-9141-4E39365ADA35}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Client.Console", "client\Yi.Abp.Client.Console\Yi.Abp.Client.Console.csproj", "{2D23B44A-DFA3-4C36-8516-4F5AE442403C}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Client.WebApi", "client\Yi.Abp.Client.WebApi\Yi.Abp.Client.WebApi.csproj", "{00E49781-C6A0-491C-86A1-46F685C90915}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "setting-management", "setting-management", "{8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SettingManagement.Domain", "module\setting-management\Yi.Framework.SettingManagement.Domain\Yi.Framework.SettingManagement.Domain.csproj", "{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SettingManagement.SqlSugarCore", "module\setting-management\Yi.Framework.SettingManagement.SqlSugarCore\Yi.Framework.SettingManagement.SqlSugarCore.csproj", "{495C4643-39D4-46E7-BDC8-237589627BE4}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "chat-hub", "chat-hub", "{D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.Application.Contracts", "module\chat-hub\Yi.Framework.ChatHub.Application.Contracts\Yi.Framework.ChatHub.Application.Contracts.csproj", "{65D4D033-5504-44B9-B152-0172ACD64CE6}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.Domain.Shared", "module\chat-hub\Yi.Framework.ChatHub.Domain.Shared\Yi.Framework.ChatHub.Domain.Shared.csproj", "{DEEC0B15-190C-4464-B469-C45C6563C592}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.SqlSugarCore", "module\chat-hub\Yi.Framework.ChatHub.SqlSugarCore\Yi.Framework.ChatHub.SqlSugarCore.csproj", "{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.Domain", "module\chat-hub\Yi.Framework.ChatHub.Domain\Yi.Framework.ChatHub.Domain.csproj", "{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.Application", "module\chat-hub\Yi.Framework.ChatHub.Application\Yi.Framework.ChatHub.Application.csproj", "{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Test", "test\Yi.Framework.Rbac.Test\Yi.Framework.Rbac.Test.csproj", "{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tool", "tool", "{084CBEEC-5D37-4716-B9C7-D80D6960DFF4}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool", "tool\Yi.Abp.Tool\Yi.Abp.Tool.csproj", "{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Web", "tool\Yi.Abp.Tool.Web\Yi.Abp.Tool.Web.csproj", "{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Application", "tool\Yi.Abp.Tool.Application\Yi.Abp.Tool.Application.csproj", "{776590BA-B900-4C8B-986A-5B721FA4B306}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Application.Contracts", "tool\Yi.Abp.Tool.Application.Contracts\Yi.Abp.Tool.Application.Contracts.csproj", "{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Domain", "tool\Yi.Abp.Tool.Domain\Yi.Abp.Tool.Domain.csproj", "{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Domain.Shared", "tool\Yi.Abp.Tool.Domain.Shared\Yi.Abp.Tool.Domain.Shared.csproj", "{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.HttpApi.Client", "tool\Yi.Abp.Tool.HttpApi.Client\Yi.Abp.Tool.HttpApi.Client.csproj", "{C8F97775-D903-4365-A4FF-3DA97E318CD2}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.SettingManagement.Application", "module\setting-management\Yi.Framework.SettingManagement.Application\Yi.Framework.SettingManagement.Application.csproj", "{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "digital-collectibles", "digital-collectibles", "{B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.Application", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.Application\Yi.Framework.DigitalCollectibles.Application.csproj", "{236B88D4-F018-4A5F-A506-7458F2308C70}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.Application.Contracts", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.Application.Contracts\Yi.Framework.DigitalCollectibles.Application.Contracts.csproj", "{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.Domain", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.Domain\Yi.Framework.DigitalCollectibles.Domain.csproj", "{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.Domain.Shared", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.Domain.Shared\Yi.Framework.DigitalCollectibles.Domain.Shared.csproj", "{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.SqlSugarCore", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.SqlSugarCore\Yi.Framework.DigitalCollectibles.SqlSugarCore.csproj", "{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.WeChat.MiniProgram", "framework\Yi.Framework.WeChat.MiniProgram\Yi.Framework.WeChat.MiniProgram.csproj", "{81CEA2ED-917B-41D8-BE0D-39A785B050C0}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.BackgroundWorkers.Hangfire", "framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj", "{862CA181-BEE6-4870-82D2-B662E527ED8C}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ai-stock", "ai-stock", "{DB46873F-981A-43D8-91B0-D464CCB65943}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Stock.Application", "module\ai-stock\Yi.Framework.Stock.Application\Yi.Framework.Stock.Application.csproj", "{B79CE23C-10F8-48A5-A039-5940A188CF5A}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Stock.Application.Contracts", "module\ai-stock\Yi.Framework.Stock.Application.Contracts\Yi.Framework.Stock.Application.Contracts.csproj", "{846B781A-B77E-4F86-A31F-0B5B57AB0775}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Stock.Domain", "module\ai-stock\Yi.Framework.Stock.Domain\Yi.Framework.Stock.Domain.csproj", "{162821E4-8FE0-4A68-B3C0-49BD6596446F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Stock.Domain.Shared", "module\ai-stock\Yi.Framework.Stock.Domain.Shared\Yi.Framework.Stock.Domain.Shared.csproj", "{10273544-715D-4BB3-893C-6F010D947BDD}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Stock.SqlSugarCore", "module\ai-stock\Yi.Framework.Stock.SqlSugarCore\Yi.Framework.Stock.SqlSugarCore.csproj", "{5F49318F-E6C7-4194-BAE0-83D4FB8D1983}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ai-hub", "ai-hub", "{7AD5DBAE-44F9-474B-8F7B-837EDE908934}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.AiHub.Application", "module\ai-hub\Yi.Framework.AiHub.Application\Yi.Framework.AiHub.Application.csproj", "{1AD10DD2-535E-4EAB-A8A4-EC3FCA206895}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.AiHub.Application.Contracts", "module\ai-hub\Yi.Framework.AiHub.Application.Contracts\Yi.Framework.AiHub.Application.Contracts.csproj", "{123D1C81-D667-4060-8E85-FFE7FB4584AD}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.AiHub.Domain", "module\ai-hub\Yi.Framework.AiHub.Domain\Yi.Framework.AiHub.Domain.csproj", "{8EB4C8BB-6B21-4811-9FAB-B98FA5CA754D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.AiHub.Domain.Shared", "module\ai-hub\Yi.Framework.AiHub.Domain.Shared\Yi.Framework.AiHub.Domain.Shared.csproj", "{5FC6CA90-D5B4-433E-9B2C-94330FFB4C48}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.AiHub.SqlSugarCore", "module\ai-hub\Yi.Framework.AiHub.SqlSugarCore\Yi.Framework.AiHub.SqlSugarCore.csproj", "{8698C812-4DDC-4E80-BCD6-24C5D56AEDB1}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EB9349E2-256D-41EB-A345-21635A1361B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EB9349E2-256D-41EB-A345-21635A1361B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EB9349E2-256D-41EB-A345-21635A1361B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EB9349E2-256D-41EB-A345-21635A1361B3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{17816837-E53B-486B-B796-53C601FE6CD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{17816837-E53B-486B-B796-53C601FE6CD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{17816837-E53B-486B-B796-53C601FE6CD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{17816837-E53B-486B-B796-53C601FE6CD9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{97EC40D7-DBFA-467A-98CB-221AF27B14F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{97EC40D7-DBFA-467A-98CB-221AF27B14F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{97EC40D7-DBFA-467A-98CB-221AF27B14F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{97EC40D7-DBFA-467A-98CB-221AF27B14F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{882BC563-2F75-4B95-AC96-F4BF23F5E69D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{882BC563-2F75-4B95-AC96-F4BF23F5E69D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{882BC563-2F75-4B95-AC96-F4BF23F5E69D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{882BC563-2F75-4B95-AC96-F4BF23F5E69D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{85CB8517-2B80-42D8-B954-081079AC9BA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{85CB8517-2B80-42D8-B954-081079AC9BA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{85CB8517-2B80-42D8-B954-081079AC9BA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{85CB8517-2B80-42D8-B954-081079AC9BA0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{00E49781-C6A0-491C-86A1-46F685C90915}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{00E49781-C6A0-491C-86A1-46F685C90915}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{00E49781-C6A0-491C-86A1-46F685C90915}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{00E49781-C6A0-491C-86A1-46F685C90915}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{495C4643-39D4-46E7-BDC8-237589627BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{495C4643-39D4-46E7-BDC8-237589627BE4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{65D4D033-5504-44B9-B152-0172ACD64CE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{65D4D033-5504-44B9-B152-0172ACD64CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{65D4D033-5504-44B9-B152-0172ACD64CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{65D4D033-5504-44B9-B152-0172ACD64CE6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DEEC0B15-190C-4464-B469-C45C6563C592}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DEEC0B15-190C-4464-B469-C45C6563C592}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DEEC0B15-190C-4464-B469-C45C6563C592}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DEEC0B15-190C-4464-B469-C45C6563C592}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{776590BA-B900-4C8B-986A-5B721FA4B306}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{776590BA-B900-4C8B-986A-5B721FA4B306}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{776590BA-B900-4C8B-986A-5B721FA4B306}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{776590BA-B900-4C8B-986A-5B721FA4B306}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C8F97775-D903-4365-A4FF-3DA97E318CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C8F97775-D903-4365-A4FF-3DA97E318CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C8F97775-D903-4365-A4FF-3DA97E318CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C8F97775-D903-4365-A4FF-3DA97E318CD2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{236B88D4-F018-4A5F-A506-7458F2308C70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{236B88D4-F018-4A5F-A506-7458F2308C70}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{236B88D4-F018-4A5F-A506-7458F2308C70}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{236B88D4-F018-4A5F-A506-7458F2308C70}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B79CE23C-10F8-48A5-A039-5940A188CF5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B79CE23C-10F8-48A5-A039-5940A188CF5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B79CE23C-10F8-48A5-A039-5940A188CF5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B79CE23C-10F8-48A5-A039-5940A188CF5A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{846B781A-B77E-4F86-A31F-0B5B57AB0775}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{846B781A-B77E-4F86-A31F-0B5B57AB0775}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{846B781A-B77E-4F86-A31F-0B5B57AB0775}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{846B781A-B77E-4F86-A31F-0B5B57AB0775}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{162821E4-8FE0-4A68-B3C0-49BD6596446F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{162821E4-8FE0-4A68-B3C0-49BD6596446F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{162821E4-8FE0-4A68-B3C0-49BD6596446F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{162821E4-8FE0-4A68-B3C0-49BD6596446F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{10273544-715D-4BB3-893C-6F010D947BDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{10273544-715D-4BB3-893C-6F010D947BDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{10273544-715D-4BB3-893C-6F010D947BDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{10273544-715D-4BB3-893C-6F010D947BDD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5F49318F-E6C7-4194-BAE0-83D4FB8D1983}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5F49318F-E6C7-4194-BAE0-83D4FB8D1983}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5F49318F-E6C7-4194-BAE0-83D4FB8D1983}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5F49318F-E6C7-4194-BAE0-83D4FB8D1983}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1AD10DD2-535E-4EAB-A8A4-EC3FCA206895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1AD10DD2-535E-4EAB-A8A4-EC3FCA206895}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1AD10DD2-535E-4EAB-A8A4-EC3FCA206895}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1AD10DD2-535E-4EAB-A8A4-EC3FCA206895}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{123D1C81-D667-4060-8E85-FFE7FB4584AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{123D1C81-D667-4060-8E85-FFE7FB4584AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{123D1C81-D667-4060-8E85-FFE7FB4584AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{123D1C81-D667-4060-8E85-FFE7FB4584AD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{8EB4C8BB-6B21-4811-9FAB-B98FA5CA754D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8EB4C8BB-6B21-4811-9FAB-B98FA5CA754D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8EB4C8BB-6B21-4811-9FAB-B98FA5CA754D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8EB4C8BB-6B21-4811-9FAB-B98FA5CA754D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5FC6CA90-D5B4-433E-9B2C-94330FFB4C48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5FC6CA90-D5B4-433E-9B2C-94330FFB4C48}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5FC6CA90-D5B4-433E-9B2C-94330FFB4C48}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5FC6CA90-D5B4-433E-9B2C-94330FFB4C48}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{8698C812-4DDC-4E80-BCD6-24C5D56AEDB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8698C812-4DDC-4E80-BCD6-24C5D56AEDB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8698C812-4DDC-4E80-BCD6-24C5D56AEDB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8698C812-4DDC-4E80-BCD6-24C5D56AEDB1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{15913E44-DA92-44B9-9AC5-E9457EA34BF5} = {B782C78B-6C17-49E6-A237-3383BA720766}
|
||||||
|
{DC431ECC-C75D-4B01-8B79-4861948179BB} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{9A7BBA40-28D6-4900-9E1D-D627A516EE72} = {B782C78B-6C17-49E6-A237-3383BA720766}
|
||||||
|
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD} = {B782C78B-6C17-49E6-A237-3383BA720766}
|
||||||
|
{51EEBF59-3D37-4681-981D-56F8D8F8968D} = {B782C78B-6C17-49E6-A237-3383BA720766}
|
||||||
|
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD} = {B782C78B-6C17-49E6-A237-3383BA720766}
|
||||||
|
{F4D5A496-BFBE-470B-A05B-CB5823B47E72} = {B782C78B-6C17-49E6-A237-3383BA720766}
|
||||||
|
{FD6D6860-3753-4747-8A26-977E4A3001F9} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{1995A019-C8AE-467E-B427-ED57D6CBF44F} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{F5011C0D-209B-4A98-BBE3-68157503EEF8} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{0A8296A3-C11F-4F13-8E49-6BC8188D4804} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{9CC7A457-1236-40BA-B47B-E7B710A3F061} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{1C360956-8CD8-407E-B87F-D0BD57068EB9} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
|
||||||
|
{4F02B08D-5FE2-460D-BCA5-DA565151AE30} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
|
||||||
|
{C04D3F71-1557-46D0-B810-97B1FBB6AB73} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
|
||||||
|
{A2BB899D-4F9A-4184-81BD-94B938E2AB03} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
|
||||||
|
{4503A2F9-139D-4CBC-AF11-689C34F0D77B} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
|
||||||
|
{E902A945-4F41-4E96-A0DA-9F66CDA22261} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{EB9349E2-256D-41EB-A345-21635A1361B3} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
|
||||||
|
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
|
||||||
|
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
|
||||||
|
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
|
||||||
|
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
|
||||||
|
{73CCF2C4-B9FD-44AB-8D4B-0A421805B094} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094}
|
||||||
|
{791AC2FA-50D3-4408-8D68-31DA72F608BE} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{68627BC2-F049-4C69-AD17-81DF9478E8CE} = {0D10EEF2-FBAE-4C72-B816-A52823FC299B}
|
||||||
|
{499A8C71-7892-42D0-A77E-48756E1EFF16} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
|
||||||
|
{54D8E2BC-591C-4344-A58E-874D49C00B41} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
|
||||||
|
{EFD13211-17B5-400A-B99A-9F6F4E520C1E} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094}
|
||||||
|
{9C8C3C53-3DCE-4516-867E-228858E61B26} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094}
|
||||||
|
{17816837-E53B-486B-B796-53C601FE6CD9} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
|
||||||
|
{FA735055-CBDD-4EFD-B84B-85810DA1425E} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
|
||||||
|
{4FFE7212-21F2-476D-B628-3C65E6C5075E} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{97EC40D7-DBFA-467A-98CB-221AF27B14F2} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||||
|
{882BC563-2F75-4B95-AC96-F4BF23F5E69D} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||||
|
{85CB8517-2B80-42D8-B954-081079AC9BA0} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||||
|
{EEFF0F05-2709-4151-A8CE-667935CEAE0B} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||||
|
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
|
||||||
|
{6B554DCC-3A81-4624-9141-4E39365ADA35} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5}
|
||||||
|
{2D23B44A-DFA3-4C36-8516-4F5AE442403C} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5}
|
||||||
|
{00E49781-C6A0-491C-86A1-46F685C90915} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5}
|
||||||
|
{8C68059E-F3B1-4D28-A1C9-A5830F53E5D3} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
|
||||||
|
{495C4643-39D4-46E7-BDC8-237589627BE4} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
|
||||||
|
{D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{65D4D033-5504-44B9-B152-0172ACD64CE6} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
|
||||||
|
{DEEC0B15-190C-4464-B469-C45C6563C592} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
|
||||||
|
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
|
||||||
|
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
|
||||||
|
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
|
||||||
|
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07} = {0D10EEF2-FBAE-4C72-B816-A52823FC299B}
|
||||||
|
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
|
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
|
{776590BA-B900-4C8B-986A-5B721FA4B306} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
|
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
|
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
|
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
|
{C8F97775-D903-4365-A4FF-3DA97E318CD2} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
|
||||||
|
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
|
||||||
|
{B8F76A6B-2EEB-4E64-9F26-D84584E16B9C} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{236B88D4-F018-4A5F-A506-7458F2308C70} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
|
||||||
|
{4FE7AC0E-91CC-4DF1-ACA7-ED83483C3F3B} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
|
||||||
|
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
|
||||||
|
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
|
||||||
|
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
|
||||||
|
{81CEA2ED-917B-41D8-BE0D-39A785B050C0} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{862CA181-BEE6-4870-82D2-B662E527ED8C} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
|
||||||
|
{DB46873F-981A-43D8-91B0-D464CCB65943} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{B79CE23C-10F8-48A5-A039-5940A188CF5A} = {DB46873F-981A-43D8-91B0-D464CCB65943}
|
||||||
|
{846B781A-B77E-4F86-A31F-0B5B57AB0775} = {DB46873F-981A-43D8-91B0-D464CCB65943}
|
||||||
|
{162821E4-8FE0-4A68-B3C0-49BD6596446F} = {DB46873F-981A-43D8-91B0-D464CCB65943}
|
||||||
|
{10273544-715D-4BB3-893C-6F010D947BDD} = {DB46873F-981A-43D8-91B0-D464CCB65943}
|
||||||
|
{5F49318F-E6C7-4194-BAE0-83D4FB8D1983} = {DB46873F-981A-43D8-91B0-D464CCB65943}
|
||||||
|
{7AD5DBAE-44F9-474B-8F7B-837EDE908934} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
|
||||||
|
{1AD10DD2-535E-4EAB-A8A4-EC3FCA206895} = {7AD5DBAE-44F9-474B-8F7B-837EDE908934}
|
||||||
|
{123D1C81-D667-4060-8E85-FFE7FB4584AD} = {7AD5DBAE-44F9-474B-8F7B-837EDE908934}
|
||||||
|
{8EB4C8BB-6B21-4811-9FAB-B98FA5CA754D} = {7AD5DBAE-44F9-474B-8F7B-837EDE908934}
|
||||||
|
{5FC6CA90-D5B4-433E-9B2C-94330FFB4C48} = {7AD5DBAE-44F9-474B-8F7B-837EDE908934}
|
||||||
|
{8698C812-4DDC-4E80-BCD6-24C5D56AEDB1} = {7AD5DBAE-44F9-474B-8F7B-837EDE908934}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
33
Yi.Abp.Net8/client/Yi.Abp.Client.Console/Program.cs
Normal file
33
Yi.Abp.Net8/client/Yi.Abp.Client.Console/Program.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Yi.Abp.Client.Console;
|
||||||
|
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IHost host = Host.CreateDefaultBuilder()
|
||||||
|
.ConfigureServices(async (host, service) =>
|
||||||
|
{
|
||||||
|
await service.AddApplicationAsync<YiAbpClientConsoleModule>();
|
||||||
|
})
|
||||||
|
.UseAutofac()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
//控制台直接调用
|
||||||
|
var account = host.Services.GetRequiredService<IAccountService>();
|
||||||
|
|
||||||
|
//获取验证码
|
||||||
|
var data1 = await account.GetCaptchaImageAsync();
|
||||||
|
|
||||||
|
//登录
|
||||||
|
var data2 = await account.PostLoginAsync(new Yi.Framework.Rbac.Application.Contracts.Dtos.Account.LoginInputVo { UserName = "cc", Password = "123456", Code = string.Empty, Uuid = string.Empty });
|
||||||
|
|
||||||
|
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
Console.WriteLine(ex.StackTrace);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\common.props" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Volo.Abp.Autofac" Version="$(AbpVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Yi.Abp.HttpApi.Client\Yi.Abp.HttpApi.Client.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Volo.Abp.Modularity;
|
||||||
|
using Yi.Abp.HttpApi.Client;
|
||||||
|
|
||||||
|
namespace Yi.Abp.Client.Console
|
||||||
|
{
|
||||||
|
[DependsOn(typeof(YiAbpHttpApiClientModule))]
|
||||||
|
public class YiAbpClientConsoleModule:AbpModule
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Yi.Framework.Rbac.Application.Contracts.Dtos.Account;
|
||||||
|
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||||
|
|
||||||
|
namespace Yi.Abp.Client.WebApi.Controllers
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("[controller]")]
|
||||||
|
public class AccountController : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
private readonly ILogger<AccountController> _logger;
|
||||||
|
private IAccountService _accountService;
|
||||||
|
public AccountController(ILogger<AccountController> logger, IAccountService accountService)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_accountService = accountService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("my-login")]
|
||||||
|
public async Task<IActionResult> Login(LoginInputVo input)
|
||||||
|
{
|
||||||
|
await _accountService.PostLoginAsync(input);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("my-captcha-image")]
|
||||||
|
public async Task<IActionResult> CaptchaImageAsync()
|
||||||
|
{
|
||||||
|
var output = await _accountService.GetCaptchaImageAsync();
|
||||||
|
return Ok(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Program.cs
Normal file
28
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Program.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Autofac.Core;
|
||||||
|
using Yi.Abp.Client.WebApi;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Add services to the container.
|
||||||
|
builder.Host.UseAutofac();
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen();
|
||||||
|
await builder.Services.AddApplicationAsync<YiAbpClientWebApiModule>();
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:35597",
|
||||||
|
"sslPort": 44322
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"applicationUrl": "http://localhost:5002",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"applicationUrl": "https://localhost:7108;http://localhost:5002",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
<Import Project="..\..\common.props" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Yi.Abp.HttpApi.Client\Yi.Abp.HttpApi.Client.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
@Yi.Abp.Client.WebApi_HostAddress = http://localhost:5002
|
||||||
|
|
||||||
|
GET {{Yi.Abp.Client.WebApi_HostAddress}}/weatherforecast/
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using Volo.Abp.Modularity;
|
||||||
|
using Yi.Abp.HttpApi.Client;
|
||||||
|
|
||||||
|
namespace Yi.Abp.Client.WebApi
|
||||||
|
{
|
||||||
|
[DependsOn(typeof(YiAbpHttpApiClientModule))]
|
||||||
|
public class YiAbpClientWebApiModule:AbpModule
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/appsettings.json
Normal file
9
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\common.props" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Volo.Abp.Http.Client" Version="$(AbpVersion)" />
|
||||||
|
<PackageReference Include="Volo.Abp.Autofac" Version="$(AbpVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Yi.Abp.Application.Contracts\Yi.Abp.Application.Contracts.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Volo.Abp.Autofac;
|
||||||
|
using Volo.Abp.Http.Client;
|
||||||
|
using Volo.Abp.Modularity;
|
||||||
|
using Yi.Framework.Rbac.Application.Contracts;
|
||||||
|
|
||||||
|
namespace Yi.Abp.HttpApi.Client
|
||||||
|
{
|
||||||
|
[DependsOn(typeof(AbpHttpClientModule),
|
||||||
|
typeof(AbpAutofacModule),
|
||||||
|
|
||||||
|
|
||||||
|
typeof(YiFrameworkRbacApplicationContractsModule))]
|
||||||
|
public class YiAbpHttpApiClientModule : AbpModule
|
||||||
|
{
|
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
//创建动态客户端代理
|
||||||
|
context.Services.AddHttpClientProxies(
|
||||||
|
typeof(YiFrameworkRbacApplicationContractsModule).Assembly
|
||||||
|
|
||||||
|
);
|
||||||
|
Configure<AbpRemoteServiceOptions>(options =>
|
||||||
|
{
|
||||||
|
options.RemoteServices.Default =
|
||||||
|
new RemoteServiceConfiguration("http://localhost:19001");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Yi.Abp.Net8/common.props
Normal file
40
Yi.Abp.Net8/common.props
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<Project>
|
||||||
|
<Import Project="usings.props" />
|
||||||
|
<Import Project="version.props" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<SatelliteResourceLanguages>en;zh-CN</SatelliteResourceLanguages>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
<NoWarn>$(NoWarn);CS1591;CS8618;CS1998;CS8604;CS8620;CS8600;CS8602</NoWarn>
|
||||||
|
<AbpProjectType>app</AbpProjectType>
|
||||||
|
|
||||||
|
<PublishDocumentationFiles>true</PublishDocumentationFiles>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target Name="NoWarnOnRazorViewImportedTypeConflicts" BeforeTargets="RazorCoreCompile">
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoWarn>$(NoWarn);0436</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="$(UserProfile)\.nuget\packages\*\*\contentFiles\any\*\*.abppkg*.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
3
Yi.Abp.Net8/end.sh
Normal file
3
Yi.Abp.Net8/end.sh
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
kill -9 $(lsof -t -i:19001)
|
||||||
|
echo "Yi-进程已关闭"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth
|
||||||
|
{
|
||||||
|
public class AuthenticationConstants
|
||||||
|
{
|
||||||
|
public const string OpenId = "urn:openid";
|
||||||
|
public const string AccessToken = "urn:access_token";
|
||||||
|
public const string Name = "urn:name";
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth
|
||||||
|
{
|
||||||
|
public class AuthenticationOAuthOptions:OAuthOptions
|
||||||
|
{
|
||||||
|
|
||||||
|
public string RedirectUri { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth
|
||||||
|
{
|
||||||
|
public class AuthticationErrCodeModel
|
||||||
|
{
|
||||||
|
public string error { get; set; }
|
||||||
|
|
||||||
|
public string error_description { get; set; }
|
||||||
|
|
||||||
|
public static void VerifyErrResponse(string content)
|
||||||
|
{
|
||||||
|
|
||||||
|
var model = Newtonsoft.Json.JsonConvert.DeserializeObject<AuthticationErrCodeModel>(content);
|
||||||
|
if (model.error != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
throw new Exception($"第三方授权返回错误,错误码:【{model.error}】,错误详情:【{model.error_description}】");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
|
||||||
|
* for more information concerning the license and the contributors participating to this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains constants specific to the <see cref="GiteeAuthenticationHandler"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class GiteeAuthenticationConstants
|
||||||
|
{
|
||||||
|
public static class Claims
|
||||||
|
{
|
||||||
|
public const string Url = "urn:gitee:url";
|
||||||
|
public const string AvatarUrl = "urn:gitee:avatarUrl";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
|
||||||
|
* for more information concerning the license and the contributors participating to this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default values used by the Gitee authentication middleware.
|
||||||
|
/// </summary>
|
||||||
|
public static class GiteeAuthenticationDefaults
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="AuthenticationScheme.Name"/>.
|
||||||
|
/// </summary>
|
||||||
|
public const string AuthenticationScheme = "Gitee";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="AuthenticationScheme.DisplayName"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string DisplayName = "Gitee";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string Issuer = "Gitee";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string CallbackPath = "/signin-gitee";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string AuthorizationEndpoint = "https://gitee.com/oauth/authorize";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string TokenEndpoint = "https://gitee.com/oauth/token";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string UserInformationEndpoint = "https://gitee.com/api/v5/user";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="GiteeAuthenticationOptions.UserEmailsEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string UserEmailsEndpoint = "https://gitee.com/api/v5/emails";
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
|
||||||
|
* for more information concerning the license and the contributors participating to this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods to add Gitee authentication capabilities to an HTTP application pipeline.
|
||||||
|
/// </summary>
|
||||||
|
public static class GiteeAuthenticationExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="GiteeAuthenticationHandler"/> to the specified
|
||||||
|
/// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The authentication builder.</param>
|
||||||
|
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
|
||||||
|
public static AuthenticationBuilder AddGitee([NotNull] this AuthenticationBuilder builder)
|
||||||
|
{
|
||||||
|
return builder.AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, options => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="GiteeAuthenticationHandler"/> to the specified
|
||||||
|
/// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The authentication builder.</param>
|
||||||
|
/// <param name="configuration">The delegate used to configure the OpenID 2.0 options.</param>
|
||||||
|
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
|
||||||
|
public static AuthenticationBuilder AddGitee(
|
||||||
|
[NotNull] this AuthenticationBuilder builder,
|
||||||
|
[NotNull] Action<GiteeAuthenticationOptions> configuration)
|
||||||
|
{
|
||||||
|
return builder.AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="GiteeAuthenticationHandler"/> to the specified
|
||||||
|
/// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The authentication builder.</param>
|
||||||
|
/// <param name="scheme">The authentication scheme associated with this instance.</param>
|
||||||
|
/// <param name="configuration">The delegate used to configure the Gitee options.</param>
|
||||||
|
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
|
||||||
|
public static AuthenticationBuilder AddGitee(
|
||||||
|
[NotNull] this AuthenticationBuilder builder,
|
||||||
|
[NotNull] string scheme,
|
||||||
|
[NotNull] Action<GiteeAuthenticationOptions> configuration)
|
||||||
|
{
|
||||||
|
return builder.AddGitee(scheme, GiteeAuthenticationDefaults.DisplayName, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="GiteeAuthenticationHandler"/> to the specified
|
||||||
|
/// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The authentication builder.</param>
|
||||||
|
/// <param name="scheme">The authentication scheme associated with this instance.</param>
|
||||||
|
/// <param name="caption">The optional display name associated with this instance.</param>
|
||||||
|
/// <param name="configuration">The delegate used to configure the Gitee options.</param>
|
||||||
|
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
|
||||||
|
public static AuthenticationBuilder AddGitee(
|
||||||
|
[NotNull] this AuthenticationBuilder builder,
|
||||||
|
[NotNull] string scheme,
|
||||||
|
[CanBeNull] string caption,
|
||||||
|
[NotNull] Action<GiteeAuthenticationOptions> configuration)
|
||||||
|
{
|
||||||
|
return builder.AddScheme<GiteeAuthenticationOptions, GiteeAuthenticationHandler>(scheme, caption, configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using static Yi.Framework.AspNetCore.Authentication.OAuth.Gitee.GiteeAuthenticationConstants;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee
|
||||||
|
{
|
||||||
|
public class GiteeAuthenticationHandler : OauthAuthenticationHandler<GiteeAuthenticationOptions>
|
||||||
|
{
|
||||||
|
public GiteeAuthenticationHandler(IOptionsMonitor<GiteeAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder, httpClientFactory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string AuthenticationSchemeNmae => GiteeAuthenticationDefaults.AuthenticationScheme;
|
||||||
|
|
||||||
|
protected override async Task<List<Claim>> GetAuthTicketAsync(string code)
|
||||||
|
{
|
||||||
|
//获取 accessToken
|
||||||
|
var tokenQueryKv = new List<KeyValuePair<string, string?>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string?>("grant_type","authorization_code"),
|
||||||
|
new KeyValuePair<string, string?>("client_id",Options.ClientId),
|
||||||
|
new KeyValuePair<string, string?>("client_secret",Options.ClientSecret),
|
||||||
|
new KeyValuePair<string, string?>("redirect_uri",Options.RedirectUri),
|
||||||
|
new KeyValuePair<string, string?>("code",code)
|
||||||
|
};
|
||||||
|
var tokenModel = await SendHttpRequestAsync<GiteeAuthticationcationTokenResponse>(GiteeAuthenticationDefaults.TokenEndpoint, tokenQueryKv,HttpMethod.Post);
|
||||||
|
|
||||||
|
//获取 userInfo
|
||||||
|
var userInfoQueryKv = new List<KeyValuePair<string, string?>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string?>("access_token",tokenModel.access_token),
|
||||||
|
};
|
||||||
|
var userInfoMdoel = await SendHttpRequestAsync<GiteeAuthticationcationUserInfoResponse>(GiteeAuthenticationDefaults.UserInformationEndpoint, userInfoQueryKv);
|
||||||
|
|
||||||
|
List<Claim> claims = new List<Claim>()
|
||||||
|
{
|
||||||
|
new Claim(Claims.AvatarUrl, userInfoMdoel.avatar_url),
|
||||||
|
new Claim(Claims.Url, userInfoMdoel.url),
|
||||||
|
|
||||||
|
new Claim(AuthenticationConstants.OpenId,userInfoMdoel.id.ToString()),
|
||||||
|
new Claim(AuthenticationConstants.Name, userInfoMdoel.name),
|
||||||
|
new Claim(AuthenticationConstants.AccessToken, tokenModel.access_token)
|
||||||
|
};
|
||||||
|
return claims;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
|
||||||
|
* for more information concerning the license and the contributors participating to this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using static Yi.Framework.AspNetCore.Authentication.OAuth.Gitee.GiteeAuthenticationConstants;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a set of options used by <see cref="GiteeAuthenticationHandler"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class GiteeAuthenticationOptions : AuthenticationOAuthOptions
|
||||||
|
{
|
||||||
|
public GiteeAuthenticationOptions()
|
||||||
|
{
|
||||||
|
ClaimsIssuer = GiteeAuthenticationDefaults.Issuer;
|
||||||
|
|
||||||
|
CallbackPath = GiteeAuthenticationDefaults.CallbackPath;
|
||||||
|
|
||||||
|
AuthorizationEndpoint = GiteeAuthenticationDefaults.AuthorizationEndpoint;
|
||||||
|
TokenEndpoint = GiteeAuthenticationDefaults.TokenEndpoint;
|
||||||
|
UserInformationEndpoint = GiteeAuthenticationDefaults.UserInformationEndpoint;
|
||||||
|
UserEmailsEndpoint = GiteeAuthenticationDefaults.UserEmailsEndpoint;
|
||||||
|
|
||||||
|
Scope.Add("user_info");
|
||||||
|
Scope.Add("emails");
|
||||||
|
|
||||||
|
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
|
||||||
|
ClaimActions.MapJsonKey(ClaimTypes.Name, "login");
|
||||||
|
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
|
||||||
|
ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
|
||||||
|
ClaimActions.MapJsonKey(Claims.Url, "url");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the address of the endpoint exposing
|
||||||
|
/// the email addresses associated with the logged in user.
|
||||||
|
/// </summary>
|
||||||
|
public string UserEmailsEndpoint { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee
|
||||||
|
{
|
||||||
|
public class GiteeAuthticationcationTokenResponse
|
||||||
|
{
|
||||||
|
public string access_token { get; set; }
|
||||||
|
public string token_type { get; set; }
|
||||||
|
public int expires_in { get; set; }
|
||||||
|
public string refresh_token { get; set; }
|
||||||
|
public string scope { get; set; }
|
||||||
|
public long created_at { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class GiteeAuthticationcationOpenIdResponse
|
||||||
|
{
|
||||||
|
public string client_id { get; set; }
|
||||||
|
|
||||||
|
public string openid { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GiteeAuthticationcationUserInfoResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 也可以等于openId
|
||||||
|
/// </summary>
|
||||||
|
public int id { get; set; }
|
||||||
|
public string login { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
public string avatar_url { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
public string html_url { get; set; }
|
||||||
|
public string remark { get; set; }
|
||||||
|
public string followers_url { get; set; }
|
||||||
|
public string following_url { get; set; }
|
||||||
|
public string gists_url { get; set; }
|
||||||
|
public string starred_url { get; set; }
|
||||||
|
public string subscriptions_url { get; set; }
|
||||||
|
public string organizations_url { get; set; }
|
||||||
|
public string repos_url { get; set; }
|
||||||
|
public string events_url { get; set; }
|
||||||
|
public string received_events_url { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string blog { get; set; }
|
||||||
|
public string weibo { get; set; }
|
||||||
|
public string bio { get; set; }
|
||||||
|
public int public_repos { get; set; }
|
||||||
|
public int public_gists { get; set; }
|
||||||
|
public int followers { get; set; }
|
||||||
|
public int following { get; set; }
|
||||||
|
public int stared { get; set; }
|
||||||
|
public int watched { get; set; }
|
||||||
|
public DateTime created_at { get; set; }
|
||||||
|
public DateTime updated_at { get; set; }
|
||||||
|
public string email { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth
|
||||||
|
{
|
||||||
|
public abstract class OauthAuthenticationHandler<TOptions> : AuthenticationHandler<TOptions> where TOptions : AuthenticationSchemeOptions, new()
|
||||||
|
{
|
||||||
|
public abstract string AuthenticationSchemeNmae { get; }
|
||||||
|
private AuthenticationScheme _scheme;
|
||||||
|
|
||||||
|
public OauthAuthenticationHandler(IOptionsMonitor<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder)
|
||||||
|
{
|
||||||
|
HttpClientFactory = httpClientFactory;
|
||||||
|
HttpClient = HttpClientFactory.CreateClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected IHttpClientFactory HttpClientFactory { get; }
|
||||||
|
|
||||||
|
protected HttpClient HttpClient { get; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成认证票据
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private AuthenticationTicket TicketConver(List<Claim> claims)
|
||||||
|
{
|
||||||
|
var claimsIdentity = new ClaimsIdentity(claims.ToArray(), AuthenticationSchemeNmae);
|
||||||
|
var principal = new ClaimsPrincipal(claimsIdentity);
|
||||||
|
return new AuthenticationTicket(principal, AuthenticationSchemeNmae);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task<HttpModel> SendHttpRequestAsync<HttpModel>(string url, IEnumerable<KeyValuePair<string, string?>> query, HttpMethod? httpMethod = null)
|
||||||
|
{
|
||||||
|
httpMethod = httpMethod ?? HttpMethod.Get;
|
||||||
|
|
||||||
|
var queryUrl = QueryHelpers.AddQueryString(url, query);
|
||||||
|
HttpResponseMessage response = null;
|
||||||
|
if (httpMethod == HttpMethod.Get)
|
||||||
|
{
|
||||||
|
response = await HttpClient.GetAsync(queryUrl);
|
||||||
|
}
|
||||||
|
else if (httpMethod == HttpMethod.Post)
|
||||||
|
{
|
||||||
|
response = await HttpClient.PostAsync(queryUrl, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new Exception($"授权服务器请求错误,请求地址:{queryUrl},错误信息:{content}");
|
||||||
|
}
|
||||||
|
VerifyErrResponse(content);
|
||||||
|
var model = Newtonsoft.Json.JsonConvert.DeserializeObject<HttpModel>(content);
|
||||||
|
return model!;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void VerifyErrResponse(string content)
|
||||||
|
{
|
||||||
|
AuthticationErrCodeModel.VerifyErrResponse(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Task<List<Claim>> GetAuthTicketAsync(string code);
|
||||||
|
|
||||||
|
|
||||||
|
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
|
{
|
||||||
|
if (!Context.Request.Query.ContainsKey("code"))
|
||||||
|
{
|
||||||
|
return AuthenticateResult.Fail("回调未包含code参数");
|
||||||
|
}
|
||||||
|
var code = Context.Request.Query["code"].ToString();
|
||||||
|
|
||||||
|
List<Claim> authTicket = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
authTicket = await GetAuthTicketAsync(code);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return AuthenticateResult.Fail(ex.Message ?? "未知错误");
|
||||||
|
}
|
||||||
|
//成功
|
||||||
|
var result = AuthenticateResult.Success(TicketConver(authTicket));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
|
||||||
|
* for more information concerning the license and the contributors participating to this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains constants specific to the <see cref="QQAuthenticationHandler"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class QQAuthenticationConstants
|
||||||
|
{
|
||||||
|
public static class Claims
|
||||||
|
{
|
||||||
|
public const string AvatarFullUrl = "urn:qq:avatar_full";
|
||||||
|
public const string AvatarUrl = "urn:qq:avatar";
|
||||||
|
public const string PictureFullUrl = "urn:qq:picture_full";
|
||||||
|
public const string PictureMediumUrl = "urn:qq:picture_medium";
|
||||||
|
public const string PictureUrl = "urn:qq:picture";
|
||||||
|
public const string UnionId = "urn:qq:unionid";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
|
||||||
|
* for more information concerning the license and the contributors participating to this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default values for QQ authentication.
|
||||||
|
/// </summary>
|
||||||
|
public static class QQAuthenticationDefaults
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="AuthenticationScheme.Name"/>.
|
||||||
|
/// </summary>
|
||||||
|
public const string AuthenticationScheme = "QQ";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="AuthenticationScheme.DisplayName"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string DisplayName = "QQ";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string Issuer = "QQ";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string CallbackPath = "/signin-qq";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string AuthorizationEndpoint = "https://graph.qq.com/oauth2.0/authorize";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string TokenEndpoint = "https://graph.qq.com/oauth2.0/token";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="QQAuthenticationOptions.UserIdentificationEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string UserIdentificationEndpoint = "https://graph.qq.com/oauth2.0/me";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string UserInformationEndpoint = "https://graph.qq.com/user/get_user_info";
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
|
||||||
|
* for more information concerning the license and the contributors participating to this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods to add QQ authentication capabilities to an HTTP application pipeline.
|
||||||
|
/// </summary>
|
||||||
|
public static class QQAuthenticationExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="QQAuthenticationHandler"/> to the specified
|
||||||
|
/// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The authentication builder.</param>
|
||||||
|
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
|
||||||
|
public static AuthenticationBuilder AddQQ([NotNull] this AuthenticationBuilder builder)
|
||||||
|
{
|
||||||
|
return builder.AddQQ(QQAuthenticationDefaults.AuthenticationScheme, options => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="QQAuthenticationHandler"/> to the specified
|
||||||
|
/// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The authentication builder.</param>
|
||||||
|
/// <param name="configuration">The delegate used to configure the OpenID 2.0 options.</param>
|
||||||
|
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
|
||||||
|
public static AuthenticationBuilder AddQQ(
|
||||||
|
[NotNull] this AuthenticationBuilder builder,
|
||||||
|
[NotNull] Action<QQAuthenticationOptions> configuration)
|
||||||
|
{
|
||||||
|
return builder.AddQQ(QQAuthenticationDefaults.AuthenticationScheme, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="QQAuthenticationHandler"/> to the specified
|
||||||
|
/// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The authentication builder.</param>
|
||||||
|
/// <param name="scheme">The authentication scheme associated with this instance.</param>
|
||||||
|
/// <param name="configuration">The delegate used to configure the QQ options.</param>
|
||||||
|
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
|
||||||
|
public static AuthenticationBuilder AddQQ(
|
||||||
|
[NotNull] this AuthenticationBuilder builder,
|
||||||
|
[NotNull] string scheme,
|
||||||
|
[NotNull] Action<QQAuthenticationOptions> configuration)
|
||||||
|
{
|
||||||
|
return builder.AddQQ(scheme, QQAuthenticationDefaults.DisplayName, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds <see cref="QQAuthenticationHandler"/> to the specified
|
||||||
|
/// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The authentication builder.</param>
|
||||||
|
/// <param name="scheme">The authentication scheme associated with this instance.</param>
|
||||||
|
/// <param name="caption">The optional display name associated with this instance.</param>
|
||||||
|
/// <param name="configuration">The delegate used to configure the QQ options.</param>
|
||||||
|
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
|
||||||
|
public static AuthenticationBuilder AddQQ(
|
||||||
|
[NotNull] this AuthenticationBuilder builder,
|
||||||
|
[NotNull] string scheme,
|
||||||
|
[CanBeNull] string caption,
|
||||||
|
[NotNull] Action<QQAuthenticationOptions> configuration)
|
||||||
|
{
|
||||||
|
return builder.AddScheme<QQAuthenticationOptions, QQAuthenticationHandler>(scheme, caption, configuration);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using static Yi.Framework.AspNetCore.Authentication.OAuth.QQ.QQAuthenticationConstants;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ
|
||||||
|
{
|
||||||
|
public class QQAuthenticationHandler : OauthAuthenticationHandler<QQAuthenticationOptions>
|
||||||
|
{
|
||||||
|
public QQAuthenticationHandler(IOptionsMonitor<QQAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder, httpClientFactory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string AuthenticationSchemeNmae => QQAuthenticationDefaults.AuthenticationScheme;
|
||||||
|
|
||||||
|
protected override async Task<List<Claim>> GetAuthTicketAsync(string code)
|
||||||
|
{
|
||||||
|
|
||||||
|
//获取 accessToken
|
||||||
|
var tokenQueryKv = new List<KeyValuePair<string, string?>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string?>("grant_type","authorization_code"),
|
||||||
|
new KeyValuePair<string, string?>("client_id",Options.ClientId),
|
||||||
|
new KeyValuePair<string, string?>("client_secret",Options.ClientSecret),
|
||||||
|
new KeyValuePair<string, string?>("redirect_uri",Options.RedirectUri),
|
||||||
|
new KeyValuePair<string, string?>("fmt","json"),
|
||||||
|
new KeyValuePair<string, string?>("need_openid","1"),
|
||||||
|
new KeyValuePair<string, string?>("code",code)
|
||||||
|
};
|
||||||
|
var tokenModel = await SendHttpRequestAsync<QQAuthticationcationTokenResponse>(QQAuthenticationDefaults.TokenEndpoint, tokenQueryKv);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//获取 userInfo
|
||||||
|
var userInfoQueryKv = new List<KeyValuePair<string, string?>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string?>("access_token",tokenModel.access_token),
|
||||||
|
new KeyValuePair<string, string?>("oauth_consumer_key",Options.ClientId),
|
||||||
|
new KeyValuePair<string, string?>("openid",tokenModel.openid),
|
||||||
|
};
|
||||||
|
|
||||||
|
var userInfoMdoel = await SendHttpRequestAsync<QQAuthticationcationUserInfoResponse>(QQAuthenticationDefaults.UserInformationEndpoint, userInfoQueryKv);
|
||||||
|
|
||||||
|
|
||||||
|
List<Claim> claims = new List<Claim>()
|
||||||
|
{
|
||||||
|
|
||||||
|
new Claim(Claims.AvatarFullUrl, userInfoMdoel.figureurl_qq_2),
|
||||||
|
new Claim(Claims.AvatarUrl, userInfoMdoel.figureurl_qq_1),
|
||||||
|
new Claim(Claims.PictureFullUrl, userInfoMdoel.figureurl_2),
|
||||||
|
new Claim(Claims.PictureMediumUrl, userInfoMdoel.figureurl_qq_1),
|
||||||
|
new Claim(Claims.PictureUrl, userInfoMdoel.figureurl),
|
||||||
|
|
||||||
|
new Claim(AuthenticationConstants.OpenId, tokenModel.openid),
|
||||||
|
new Claim(AuthenticationConstants.Name, userInfoMdoel.nickname),
|
||||||
|
new Claim(AuthenticationConstants.AccessToken, tokenModel.access_token),
|
||||||
|
|
||||||
|
};
|
||||||
|
return claims;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
|
||||||
|
* for more information concerning the license and the contributors participating to this project.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using static Yi.Framework.AspNetCore.Authentication.OAuth.QQ.QQAuthenticationConstants;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a set of options used by <see cref="QQAuthenticationHandler"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class QQAuthenticationOptions : AuthenticationOAuthOptions
|
||||||
|
{
|
||||||
|
public QQAuthenticationOptions()
|
||||||
|
{
|
||||||
|
ClaimsIssuer = QQAuthenticationDefaults.Issuer;
|
||||||
|
CallbackPath = QQAuthenticationDefaults.CallbackPath;
|
||||||
|
|
||||||
|
AuthorizationEndpoint = QQAuthenticationDefaults.AuthorizationEndpoint;
|
||||||
|
TokenEndpoint = QQAuthenticationDefaults.TokenEndpoint;
|
||||||
|
UserIdentificationEndpoint = QQAuthenticationDefaults.UserIdentificationEndpoint;
|
||||||
|
UserInformationEndpoint = QQAuthenticationDefaults.UserInformationEndpoint;
|
||||||
|
|
||||||
|
Scope.Add("get_user_info");
|
||||||
|
|
||||||
|
ClaimActions.MapJsonKey(ClaimTypes.Name, "nickname");
|
||||||
|
ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender");
|
||||||
|
ClaimActions.MapJsonKey(Claims.PictureUrl, "figureurl");
|
||||||
|
ClaimActions.MapJsonKey(Claims.PictureMediumUrl, "figureurl_1");
|
||||||
|
ClaimActions.MapJsonKey(Claims.PictureFullUrl, "figureurl_2");
|
||||||
|
ClaimActions.MapJsonKey(Claims.AvatarUrl, "figureurl_qq_1");
|
||||||
|
ClaimActions.MapJsonKey(Claims.AvatarFullUrl, "figureurl_qq_2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the union Id (the primary key of an owner for different apps of the QQ platform) should be put into the user claims.
|
||||||
|
/// </summary>
|
||||||
|
public bool ApplyForUnionId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the URL of the user identification endpoint (a.k.a. the "OpenID endpoint").
|
||||||
|
/// </summary>
|
||||||
|
public string UserIdentificationEndpoint { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ
|
||||||
|
{
|
||||||
|
public class QQAuthticationcationTokenResponse
|
||||||
|
{
|
||||||
|
public string access_token { get; set; }
|
||||||
|
|
||||||
|
public string expires_in { get; set; }
|
||||||
|
|
||||||
|
public string refresh_token { get; set; }
|
||||||
|
|
||||||
|
public string openid { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class QQAuthticationcationOpenIdResponse
|
||||||
|
{
|
||||||
|
public string client_id { get; set; }
|
||||||
|
|
||||||
|
public string openid { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QQAuthticationcationUserInfoResponse
|
||||||
|
{
|
||||||
|
// 返回码
|
||||||
|
public int ret { get; set; }
|
||||||
|
|
||||||
|
// 如果ret<0,会有相应的错误信息提示
|
||||||
|
// 返回数据全部用UTF-8编码
|
||||||
|
public string msg { get; set; }
|
||||||
|
|
||||||
|
// 判断是否有数据丢失
|
||||||
|
// 0或者不返回:没有数据丢失,可以缓存
|
||||||
|
// 1:有部分数据丢失或错误,不要缓存
|
||||||
|
public int is_lost { get; set; }
|
||||||
|
|
||||||
|
// 用户在QQ空间的昵称
|
||||||
|
public string nickname { get; set; }
|
||||||
|
|
||||||
|
// 大小为30x30像素的QQ空间头像URL
|
||||||
|
public string figureurl { get; set; }
|
||||||
|
|
||||||
|
// 大小为50x50像素的QQ空间头像URL
|
||||||
|
public string figureurl_1 { get; set; }
|
||||||
|
|
||||||
|
// 大小为100x100像素的QQ空间头像URL
|
||||||
|
public string figureurl_2 { get; set; }
|
||||||
|
|
||||||
|
// 大小为40x40像素的QQ头像URL
|
||||||
|
public string figureurl_qq_1 { get; set; }
|
||||||
|
|
||||||
|
// 大小为100x100像素的QQ头像URL
|
||||||
|
// 需要注意,不是所有的用户都拥有QQ的100x100的头像,但40x40像素则是一定会有
|
||||||
|
public string figureurl_qq_2 { get; set; }
|
||||||
|
|
||||||
|
// 性别。如果获取不到则默认返回"男"
|
||||||
|
public string gender { get; set; }
|
||||||
|
|
||||||
|
// 性别类型。默认返回2
|
||||||
|
public int gender_type { get; set; }
|
||||||
|
|
||||||
|
// 省
|
||||||
|
public string province { get; set; }
|
||||||
|
|
||||||
|
// 市
|
||||||
|
public string city { get; set; }
|
||||||
|
|
||||||
|
// 年
|
||||||
|
public int year { get; set; }
|
||||||
|
|
||||||
|
// 星座
|
||||||
|
public string constellation { get; set; }
|
||||||
|
|
||||||
|
// 标识用户是否为黄钻用户
|
||||||
|
public int is_yellow_vip { get; set; }
|
||||||
|
|
||||||
|
// 黄钻等级
|
||||||
|
public int yellow_vip_level { get; set; }
|
||||||
|
|
||||||
|
// 是否为年费黄钻用户
|
||||||
|
public int is_yellow_year_vip { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\common.props" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Volo.Abp.Modularity;
|
||||||
|
using Yi.Framework.Core;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Authentication.OAuth
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 本模块轮子来自 AspNet.Security.OAuth.QQ;
|
||||||
|
/// </summary>
|
||||||
|
[DependsOn(typeof(YiFrameworkAspNetCoreModule))]
|
||||||
|
public class YiFrameworkAspNetCoreAuthenticationOAuthModule:AbpModule
|
||||||
|
{
|
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
var service = context.Services;
|
||||||
|
service.AddHttpClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Yi.Framework.Core.Authentication;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Authentication;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 可刷新的鉴权提供者
|
||||||
|
/// </summary>
|
||||||
|
public class RefreshAuthenticationHandlerProvider : IRefreshAuthenticationHandlerProvider
|
||||||
|
{
|
||||||
|
private Dictionary<string, IAuthenticationHandler> _handlerMap =
|
||||||
|
new Dictionary<string, IAuthenticationHandler>((IEqualityComparer<string>)StringComparer.Ordinal);
|
||||||
|
|
||||||
|
/// <summary>Constructor.</summary>
|
||||||
|
/// <param name="schemes">The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider" />.</param>
|
||||||
|
public RefreshAuthenticationHandlerProvider(IAuthenticationSchemeProvider schemes)
|
||||||
|
{
|
||||||
|
this.Schemes = schemes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="T:Microsoft.AspNetCore.Authentication.IAuthenticationHandlerProvider" />.
|
||||||
|
/// </summary>
|
||||||
|
public IAuthenticationSchemeProvider Schemes { get; }
|
||||||
|
|
||||||
|
/// <summary>Returns the handler instance that will be used.</summary>
|
||||||
|
/// <param name="context">The context.</param>
|
||||||
|
/// <param name="authenticationScheme">The name of the authentication scheme being handled.</param>
|
||||||
|
/// <returns>The handler instance.</returns>
|
||||||
|
public async Task<IAuthenticationHandler?> GetHandlerAsync(
|
||||||
|
HttpContext context,
|
||||||
|
string authenticationScheme)
|
||||||
|
{
|
||||||
|
IAuthenticationHandler handlerAsync;
|
||||||
|
if (this._handlerMap.TryGetValue(authenticationScheme, out handlerAsync))
|
||||||
|
return handlerAsync;
|
||||||
|
AuthenticationScheme schemeAsync = await this.Schemes.GetSchemeAsync(authenticationScheme);
|
||||||
|
if (schemeAsync == null)
|
||||||
|
return (IAuthenticationHandler)null;
|
||||||
|
|
||||||
|
if ((context.RequestServices.GetService(schemeAsync.HandlerType) ??
|
||||||
|
ActivatorUtilities.CreateInstance(context.RequestServices, schemeAsync.HandlerType)) is
|
||||||
|
IAuthenticationHandler handler)
|
||||||
|
{
|
||||||
|
handlerAsync = handler;
|
||||||
|
await handler.InitializeAsync(schemeAsync, context);
|
||||||
|
this._handlerMap[authenticationScheme] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handlerAsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新鉴权
|
||||||
|
/// </summary>
|
||||||
|
public void RefreshAuthentication()
|
||||||
|
{
|
||||||
|
_handlerMap = new Dictionary<string, IAuthenticationHandler>((IEqualityComparer<string>)StringComparer.Ordinal);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 提供API信息处理的应用程序构建器扩展方法
|
||||||
|
/// </summary>
|
||||||
|
public static class ApiInfoBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 使用Yi框架的API信息处理中间件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">应用程序构建器实例</param>
|
||||||
|
/// <returns>配置后的应用程序构建器实例</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">当builder参数为null时抛出</exception>
|
||||||
|
public static IApplicationBuilder UseApiInfoHandling([NotNull] this IApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
// 添加API信息处理中间件到请求管道
|
||||||
|
builder.UseMiddleware<ApiInfoMiddleware>();
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Swagger构建器扩展类
|
||||||
|
/// </summary>
|
||||||
|
public static class SwaggerBuilderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 配置并使用Yi框架的Swagger中间件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="app">应用程序构建器</param>
|
||||||
|
/// <param name="swaggerConfigs">Swagger配置模型数组</param>
|
||||||
|
/// <returns>应用程序构建器</returns>
|
||||||
|
public static IApplicationBuilder UseYiSwagger(
|
||||||
|
this IApplicationBuilder app,
|
||||||
|
params SwaggerConfiguration[] swaggerConfigs)
|
||||||
|
{
|
||||||
|
if (app == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(app));
|
||||||
|
}
|
||||||
|
|
||||||
|
var mvcOptions = app.ApplicationServices
|
||||||
|
.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>()
|
||||||
|
.Value;
|
||||||
|
|
||||||
|
// 启用Swagger中间件
|
||||||
|
app.UseSwagger();
|
||||||
|
|
||||||
|
// 配置SwaggerUI
|
||||||
|
app.UseSwaggerUI(options =>
|
||||||
|
{
|
||||||
|
// 添加约定控制器的Swagger终结点
|
||||||
|
var conventionalSettings = mvcOptions.ConventionalControllers.ConventionalControllerSettings;
|
||||||
|
foreach (var setting in conventionalSettings)
|
||||||
|
{
|
||||||
|
options.SwaggerEndpoint(
|
||||||
|
$"/swagger/{setting.RemoteServiceName}/swagger.json",
|
||||||
|
setting.RemoteServiceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有配置任何终结点,使用默认配置
|
||||||
|
if (!conventionalSettings.Any() && (swaggerConfigs == null || !swaggerConfigs.Any()))
|
||||||
|
{
|
||||||
|
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Yi.Framework");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加自定义Swagger配置的终结点
|
||||||
|
if (swaggerConfigs != null)
|
||||||
|
{
|
||||||
|
foreach (var config in swaggerConfigs)
|
||||||
|
{
|
||||||
|
options.SwaggerEndpoint(config.Url, config.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Swagger配置模型
|
||||||
|
/// </summary>
|
||||||
|
public class SwaggerConfiguration
|
||||||
|
{
|
||||||
|
private const string DefaultSwaggerUrl = "/swagger/v1/swagger.json";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Swagger JSON文档的URL
|
||||||
|
/// </summary>
|
||||||
|
public string Url { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Swagger文档的显示名称
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用默认URL创建Swagger配置
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">文档显示名称</param>
|
||||||
|
public SwaggerConfiguration(string name)
|
||||||
|
: this(DefaultSwaggerUrl, name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建自定义Swagger配置
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">Swagger JSON文档URL</param>
|
||||||
|
/// <param name="name">文档显示名称</param>
|
||||||
|
public SwaggerConfiguration(string url, string name)
|
||||||
|
{
|
||||||
|
Url = url ?? throw new ArgumentNullException(nameof(url));
|
||||||
|
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Yi.Framework.Core.Extensions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// API响应信息处理中间件
|
||||||
|
/// 主要用于处理特定文件类型的响应头信息
|
||||||
|
/// </summary>
|
||||||
|
[DebuggerStepThrough]
|
||||||
|
public class ApiInfoMiddleware : IMiddleware, ITransientDependency
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 处理HTTP请求的中间件方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP上下文</param>
|
||||||
|
/// <param name="next">请求处理委托</param>
|
||||||
|
/// <returns>异步任务</returns>
|
||||||
|
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||||
|
{
|
||||||
|
// 在响应开始时处理文件下载相关的响应头
|
||||||
|
context.Response.OnStarting(() =>
|
||||||
|
{
|
||||||
|
HandleFileDownloadResponse(context);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 继续处理管道中的下一个中间件
|
||||||
|
await next(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理文件下载响应的响应头信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP上下文</param>
|
||||||
|
private static void HandleFileDownloadResponse(HttpContext context)
|
||||||
|
{
|
||||||
|
// 仅处理状态码为200的响应
|
||||||
|
if (context.Response.StatusCode != StatusCodes.Status200OK)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentType = context.Response.Headers["Content-Type"].ToString();
|
||||||
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||||
|
|
||||||
|
// 处理Excel文件下载
|
||||||
|
if (contentType == "application/vnd.ms-excel")
|
||||||
|
{
|
||||||
|
context.FileAttachmentHandle($"{timestamp}.xlsx");
|
||||||
|
}
|
||||||
|
// 处理ZIP文件下载
|
||||||
|
else if (contentType == "application/x-zip-compressed")
|
||||||
|
{
|
||||||
|
context.FileAttachmentHandle($"{timestamp}.zip");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.OpenApi.Any;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc.Conventions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Swagger生成器扩展类
|
||||||
|
/// </summary>
|
||||||
|
public static class SwaggerAddExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 添加Yi框架的Swagger生成器服务
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TProgram">程序入口类型</typeparam>
|
||||||
|
/// <param name="services">服务集合</param>
|
||||||
|
/// <param name="setupAction">自定义配置动作</param>
|
||||||
|
/// <returns>服务集合</returns>
|
||||||
|
public static IServiceCollection AddYiSwaggerGen<TProgram>(
|
||||||
|
this IServiceCollection services,
|
||||||
|
Action<SwaggerGenOptions>? setupAction = null)
|
||||||
|
{
|
||||||
|
// 获取MVC配置选项
|
||||||
|
var mvcOptions = services.GetPreConfigureActions<AbpAspNetCoreMvcOptions>().Configure();
|
||||||
|
|
||||||
|
// 获取并去重远程服务名称
|
||||||
|
var remoteServiceSettings = mvcOptions.ConventionalControllers
|
||||||
|
.ConventionalControllerSettings
|
||||||
|
.DistinctBy(x => x.RemoteServiceName);
|
||||||
|
|
||||||
|
services.AddAbpSwaggerGen(
|
||||||
|
options =>
|
||||||
|
{
|
||||||
|
// 应用外部配置
|
||||||
|
setupAction?.Invoke(options);
|
||||||
|
|
||||||
|
// 配置API文档分组
|
||||||
|
ConfigureApiGroups(options, remoteServiceSettings);
|
||||||
|
|
||||||
|
// 配置API文档过滤器
|
||||||
|
ConfigureApiFilter(options, remoteServiceSettings);
|
||||||
|
|
||||||
|
// 配置Schema ID生成规则
|
||||||
|
options.CustomSchemaIds(type => type.FullName);
|
||||||
|
|
||||||
|
// 包含XML注释文档
|
||||||
|
IncludeXmlComments<TProgram>(options);
|
||||||
|
|
||||||
|
// 配置JWT认证
|
||||||
|
ConfigureJwtAuthentication(options);
|
||||||
|
|
||||||
|
// 添加自定义过滤器
|
||||||
|
ConfigureCustomFilters(options);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置API分组
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigureApiGroups(
|
||||||
|
SwaggerGenOptions options,
|
||||||
|
IEnumerable<ConventionalControllerSetting> settings)
|
||||||
|
{
|
||||||
|
foreach (var setting in settings.OrderBy(x => x.RemoteServiceName))
|
||||||
|
{
|
||||||
|
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
|
||||||
|
{
|
||||||
|
options.SwaggerDoc(setting.RemoteServiceName, new OpenApiInfo
|
||||||
|
{
|
||||||
|
Title = setting.RemoteServiceName,
|
||||||
|
Version = "v1"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置API文档过滤器
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigureApiFilter(
|
||||||
|
SwaggerGenOptions options,
|
||||||
|
IEnumerable<ConventionalControllerSetting> settings)
|
||||||
|
{
|
||||||
|
options.DocInclusionPredicate((docName, apiDesc) =>
|
||||||
|
{
|
||||||
|
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerDesc)
|
||||||
|
{
|
||||||
|
var matchedSetting = settings
|
||||||
|
.FirstOrDefault(x => x.Assembly == controllerDesc.ControllerTypeInfo.Assembly);
|
||||||
|
return matchedSetting?.RemoteServiceName == docName;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 包含XML注释文档
|
||||||
|
/// </summary>
|
||||||
|
private static void IncludeXmlComments<TProgram>(SwaggerGenOptions options)
|
||||||
|
{
|
||||||
|
var basePath = Path.GetDirectoryName(typeof(TProgram).Assembly.Location);
|
||||||
|
if (basePath is not null)
|
||||||
|
{
|
||||||
|
foreach (var xmlFile in Directory.GetFiles(basePath, "*.xml"))
|
||||||
|
{
|
||||||
|
options.IncludeXmlComments(xmlFile, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置JWT认证
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigureJwtAuthentication(SwaggerGenOptions options)
|
||||||
|
{
|
||||||
|
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Description = "请在此输入JWT Token",
|
||||||
|
Name = "Authorization",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Type = SecuritySchemeType.Http,
|
||||||
|
Scheme = "bearer"
|
||||||
|
});
|
||||||
|
|
||||||
|
var scheme = new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "JwtBearer"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
[scheme] = Array.Empty<string>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置自定义过滤器
|
||||||
|
/// </summary>
|
||||||
|
private static void ConfigureCustomFilters(SwaggerGenOptions options)
|
||||||
|
{
|
||||||
|
options.OperationFilter<TenantHeaderOperationFilter>();
|
||||||
|
options.SchemaFilter<EnumSchemaFilter>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Swagger文档枚举字段显示过滤器
|
||||||
|
/// </summary>
|
||||||
|
public class EnumSchemaFilter : ISchemaFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 应用枚举架构过滤器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="schema">OpenAPI架构</param>
|
||||||
|
/// <param name="context">架构过滤器上下文</param>
|
||||||
|
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
|
||||||
|
{
|
||||||
|
if (!context.Type.IsEnum) return;
|
||||||
|
|
||||||
|
schema.Enum.Clear();
|
||||||
|
schema.Type = "string";
|
||||||
|
schema.Format = null;
|
||||||
|
|
||||||
|
var enumDescriptions = new StringBuilder();
|
||||||
|
foreach (var enumName in Enum.GetNames(context.Type))
|
||||||
|
{
|
||||||
|
var enumValue = (Enum)Enum.Parse(context.Type, enumName);
|
||||||
|
var description = GetEnumDescription(enumValue);
|
||||||
|
var enumIntValue = Convert.ToInt64(enumValue);
|
||||||
|
|
||||||
|
schema.Enum.Add(new OpenApiString(enumName));
|
||||||
|
enumDescriptions.AppendLine(
|
||||||
|
$"【枚举:{enumName}{(description is null ? string.Empty : $"({description})")}={enumIntValue}】");
|
||||||
|
}
|
||||||
|
schema.Description = enumDescriptions.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取枚举描述特性值
|
||||||
|
/// </summary>
|
||||||
|
private static string? GetEnumDescription(Enum value)
|
||||||
|
{
|
||||||
|
var fieldInfo = value.GetType().GetField(value.ToString());
|
||||||
|
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||||
|
return attributes.Length > 0 ? attributes[0].Description : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 租户头部参数过滤器
|
||||||
|
/// </summary>
|
||||||
|
public class TenantHeaderOperationFilter : IOperationFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 租户标识键名
|
||||||
|
/// </summary>
|
||||||
|
private const string TenantHeaderKey = "__tenant";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用租户头部参数过滤器
|
||||||
|
/// </summary>
|
||||||
|
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||||
|
{
|
||||||
|
operation.Parameters ??= new List<OpenApiParameter>();
|
||||||
|
|
||||||
|
operation.Parameters.Add(new OpenApiParameter
|
||||||
|
{
|
||||||
|
Name = TenantHeaderKey,
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Required = false,
|
||||||
|
AllowEmptyValue = true,
|
||||||
|
Description = "租户ID或租户名称(留空表示默认租户)"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc.Conventions;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Reflection;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义路由构建器,用于生成API路由规则
|
||||||
|
/// </summary>
|
||||||
|
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
|
||||||
|
[ExposeServices(typeof(IConventionalRouteBuilder))]
|
||||||
|
public class YiConventionalRouteBuilder : ConventionalRouteBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">ABP约定控制器配置选项</param>
|
||||||
|
public YiConventionalRouteBuilder(IOptions<AbpConventionalControllerOptions> options)
|
||||||
|
: base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建API路由
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rootPath">根路径</param>
|
||||||
|
/// <param name="controllerName">控制器名称</param>
|
||||||
|
/// <param name="action">Action模型</param>
|
||||||
|
/// <param name="httpMethod">HTTP方法</param>
|
||||||
|
/// <param name="configuration">控制器配置</param>
|
||||||
|
/// <returns>构建的路由URL</returns>
|
||||||
|
public override string Build(
|
||||||
|
string rootPath,
|
||||||
|
string controllerName,
|
||||||
|
ActionModel action,
|
||||||
|
string httpMethod,
|
||||||
|
[CanBeNull] ConventionalControllerSetting configuration)
|
||||||
|
{
|
||||||
|
// 获取API路由前缀
|
||||||
|
var apiRoutePrefix = GetApiRoutePrefix(action, configuration);
|
||||||
|
|
||||||
|
// 规范化控制器名称
|
||||||
|
var normalizedControllerName = NormalizeUrlControllerName(
|
||||||
|
rootPath,
|
||||||
|
controllerName,
|
||||||
|
action,
|
||||||
|
httpMethod,
|
||||||
|
configuration);
|
||||||
|
|
||||||
|
// 构建基础URL
|
||||||
|
var url = $"{rootPath}/{NormalizeControllerNameCase(normalizedControllerName, configuration)}";
|
||||||
|
|
||||||
|
// 处理ID参数路由
|
||||||
|
url = BuildIdParameterRoute(url, action, configuration);
|
||||||
|
|
||||||
|
// 处理Action名称路由
|
||||||
|
url = BuildActionNameRoute(url, rootPath, controllerName, action, httpMethod, configuration);
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建ID参数路由部分
|
||||||
|
/// </summary>
|
||||||
|
private string BuildIdParameterRoute(
|
||||||
|
string baseUrl,
|
||||||
|
ActionModel action,
|
||||||
|
ConventionalControllerSetting configuration)
|
||||||
|
{
|
||||||
|
var idParameter = action.Parameters.FirstOrDefault(p => p.ParameterName == "id");
|
||||||
|
if (idParameter == null)
|
||||||
|
{
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理原始类型ID
|
||||||
|
if (TypeHelper.IsPrimitiveExtended(idParameter.ParameterType, includeEnums: true))
|
||||||
|
{
|
||||||
|
return $"{baseUrl}/{{id}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理复杂类型ID
|
||||||
|
var properties = idParameter.ParameterType
|
||||||
|
.GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
|
||||||
|
foreach (var property in properties)
|
||||||
|
{
|
||||||
|
baseUrl += $"/{{{NormalizeIdPropertyNameCase(property, configuration)}}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建Action名称路由部分
|
||||||
|
/// </summary>
|
||||||
|
private string BuildActionNameRoute(
|
||||||
|
string baseUrl,
|
||||||
|
string rootPath,
|
||||||
|
string controllerName,
|
||||||
|
ActionModel action,
|
||||||
|
string httpMethod,
|
||||||
|
ConventionalControllerSetting configuration)
|
||||||
|
{
|
||||||
|
var actionNameInUrl = NormalizeUrlActionName(
|
||||||
|
rootPath,
|
||||||
|
controllerName,
|
||||||
|
action,
|
||||||
|
httpMethod,
|
||||||
|
configuration);
|
||||||
|
|
||||||
|
if (actionNameInUrl.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
baseUrl += $"/{NormalizeActionNameCase(actionNameInUrl, configuration)}";
|
||||||
|
|
||||||
|
// 处理次要ID参数
|
||||||
|
var secondaryIds = action.Parameters
|
||||||
|
.Where(p => p.ParameterName.EndsWith("Id", StringComparison.Ordinal))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (secondaryIds.Count == 1)
|
||||||
|
{
|
||||||
|
baseUrl += $"/{{{NormalizeSecondaryIdNameCase(secondaryIds[0], configuration)}}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
using JetBrains.Annotations;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Volo.Abp;
|
||||||
|
using Volo.Abp.AspNetCore;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc.Conventions;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Reflection;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义服务约定实现,用于处理API路由和HTTP方法约束
|
||||||
|
/// </summary>
|
||||||
|
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
|
||||||
|
[ExposeServices(typeof(IAbpServiceConvention))]
|
||||||
|
public class YiServiceConvention : AbpServiceConvention
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化服务约定的新实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">ABP AspNetCore MVC 配置选项</param>
|
||||||
|
/// <param name="conventionalRouteBuilder">约定路由构建器</param>
|
||||||
|
public YiServiceConvention(
|
||||||
|
IOptions<AbpAspNetCoreMvcOptions> options,
|
||||||
|
IConventionalRouteBuilder conventionalRouteBuilder)
|
||||||
|
: base(options, conventionalRouteBuilder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置选择器,处理路由和HTTP方法约束
|
||||||
|
/// </summary>
|
||||||
|
protected override void ConfigureSelector(
|
||||||
|
string rootPath,
|
||||||
|
string controllerName,
|
||||||
|
ActionModel action,
|
||||||
|
ConventionalControllerSetting? configuration)
|
||||||
|
{
|
||||||
|
// 移除空选择器
|
||||||
|
RemoveEmptySelectors(action.Selectors);
|
||||||
|
|
||||||
|
// 检查远程服务特性
|
||||||
|
var remoteServiceAttr = ReflectionHelper
|
||||||
|
.GetSingleAttributeOrDefault<RemoteServiceAttribute>(action.ActionMethod);
|
||||||
|
if (remoteServiceAttr != null && !remoteServiceAttr.IsEnabledFor(action.ActionMethod))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据选择器是否存在执行不同的配置
|
||||||
|
if (!action.Selectors.Any())
|
||||||
|
{
|
||||||
|
AddAbpServiceSelector(rootPath, controllerName, action, configuration);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NormalizeSelectorRoutes(rootPath, controllerName, action, configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 规范化选择器路由
|
||||||
|
/// </summary>
|
||||||
|
protected override void NormalizeSelectorRoutes(
|
||||||
|
string rootPath,
|
||||||
|
string controllerName,
|
||||||
|
ActionModel action,
|
||||||
|
ConventionalControllerSetting? configuration)
|
||||||
|
{
|
||||||
|
foreach (var selector in action.Selectors)
|
||||||
|
{
|
||||||
|
// 获取HTTP方法约束
|
||||||
|
var httpMethod = GetOrCreateHttpMethod(selector, action, configuration);
|
||||||
|
|
||||||
|
// 处理路由模板
|
||||||
|
ConfigureRouteTemplate(selector, rootPath, controllerName, action, httpMethod, configuration);
|
||||||
|
|
||||||
|
// 确保HTTP方法约束存在
|
||||||
|
EnsureHttpMethodConstraint(selector, httpMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或创建HTTP方法
|
||||||
|
/// </summary>
|
||||||
|
private string GetOrCreateHttpMethod(
|
||||||
|
SelectorModel selector,
|
||||||
|
ActionModel action,
|
||||||
|
ConventionalControllerSetting? configuration)
|
||||||
|
{
|
||||||
|
return selector.ActionConstraints
|
||||||
|
.OfType<HttpMethodActionConstraint>()
|
||||||
|
.FirstOrDefault()?
|
||||||
|
.HttpMethods?
|
||||||
|
.FirstOrDefault()
|
||||||
|
?? SelectHttpMethod(action, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置路由模板
|
||||||
|
/// </summary>
|
||||||
|
private void ConfigureRouteTemplate(
|
||||||
|
SelectorModel selector,
|
||||||
|
string rootPath,
|
||||||
|
string controllerName,
|
||||||
|
ActionModel action,
|
||||||
|
string httpMethod,
|
||||||
|
ConventionalControllerSetting? configuration)
|
||||||
|
{
|
||||||
|
if (selector.AttributeRouteModel == null)
|
||||||
|
{
|
||||||
|
selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel(
|
||||||
|
rootPath,
|
||||||
|
controllerName,
|
||||||
|
action,
|
||||||
|
httpMethod,
|
||||||
|
configuration);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NormalizeAttributeRouteTemplate(selector, rootPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 规范化特性路由模板
|
||||||
|
/// </summary>
|
||||||
|
private void NormalizeAttributeRouteTemplate(SelectorModel selector, string rootPath)
|
||||||
|
{
|
||||||
|
var template = selector.AttributeRouteModel.Template;
|
||||||
|
if (!template.StartsWith("/"))
|
||||||
|
{
|
||||||
|
selector.AttributeRouteModel.Template = $"{rootPath}/{template}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确保HTTP方法约束存在
|
||||||
|
/// </summary>
|
||||||
|
private void EnsureHttpMethodConstraint(SelectorModel selector, string httpMethod)
|
||||||
|
{
|
||||||
|
if (!selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Any())
|
||||||
|
{
|
||||||
|
selector.ActionConstraints.Add(
|
||||||
|
new HttpMethodActionConstraint(new[] { httpMethod }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Volo.Abp.AspNetCore.WebClientInfo;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 真实IP地址提供程序,支持代理服务器场景
|
||||||
|
/// </summary>
|
||||||
|
public class RealIpHttpContextWebClientInfoProvider : HttpContextWebClientInfoProvider
|
||||||
|
{
|
||||||
|
private const string XForwardedForHeader = "X-Forwarded-For";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化真实IP地址提供程序的新实例
|
||||||
|
/// </summary>
|
||||||
|
public RealIpHttpContextWebClientInfoProvider(
|
||||||
|
ILogger<HttpContextWebClientInfoProvider> logger,
|
||||||
|
IHttpContextAccessor httpContextAccessor)
|
||||||
|
: base(logger, httpContextAccessor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取客户端IP地址,优先从X-Forwarded-For头部获取
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>客户端IP地址</returns>
|
||||||
|
protected override string? GetClientIpAddress()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var httpContext = HttpContextAccessor.HttpContext;
|
||||||
|
if (httpContext == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var headers = httpContext.Request?.Headers;
|
||||||
|
if (headers != null && headers.ContainsKey(XForwardedForHeader))
|
||||||
|
{
|
||||||
|
// 从X-Forwarded-For获取真实客户端IP
|
||||||
|
var forwardedIp = headers[XForwardedForHeader].FirstOrDefault();
|
||||||
|
if (!string.IsNullOrEmpty(forwardedIp))
|
||||||
|
{
|
||||||
|
httpContext.Connection.RemoteIpAddress = IPAddress.Parse(forwardedIp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return httpContext.Connection?.RemoteIpAddress?.ToString();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogWarning(ex, "获取客户端IP地址时发生异常");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
namespace Yi.Framework.AspNetCore
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 远程服务成功响应信息
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class RemoteServiceSuccessInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置响应代码
|
||||||
|
/// </summary>
|
||||||
|
public string? Code { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置响应消息
|
||||||
|
/// </summary>
|
||||||
|
public string? Message { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置详细信息
|
||||||
|
/// </summary>
|
||||||
|
public string? Details { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置响应数据
|
||||||
|
/// </summary>
|
||||||
|
public object? Data { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化远程服务成功响应信息的新实例
|
||||||
|
/// </summary>
|
||||||
|
public RemoteServiceSuccessInfo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用指定参数初始化远程服务成功响应信息的新实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">响应消息</param>
|
||||||
|
/// <param name="details">详细信息</param>
|
||||||
|
/// <param name="code">响应代码</param>
|
||||||
|
/// <param name="data">响应数据</param>
|
||||||
|
public RemoteServiceSuccessInfo(
|
||||||
|
string message,
|
||||||
|
string? details = null,
|
||||||
|
string? code = null,
|
||||||
|
object? data = null)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
Details = details;
|
||||||
|
Code = code;
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// MIT 许可证
|
||||||
|
//
|
||||||
|
// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者
|
||||||
|
//
|
||||||
|
// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,
|
||||||
|
// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,
|
||||||
|
// 以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||||
|
//
|
||||||
|
// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||||
|
//
|
||||||
|
// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||||
|
// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,
|
||||||
|
// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异常元数据
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ExceptionMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 状态码
|
||||||
|
/// </summary>
|
||||||
|
public int StatusCode { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误码
|
||||||
|
/// </summary>
|
||||||
|
public object ErrorCode { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误码(没被复写过的 ErrorCode )
|
||||||
|
/// </summary>
|
||||||
|
public object OriginErrorCode { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误对象(信息)
|
||||||
|
/// </summary>
|
||||||
|
public object Errors { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外数据
|
||||||
|
/// </summary>
|
||||||
|
public object Data { get; internal set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
// MIT 许可证
|
||||||
|
//
|
||||||
|
// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者
|
||||||
|
//
|
||||||
|
// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,
|
||||||
|
// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,
|
||||||
|
// 以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||||
|
//
|
||||||
|
// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||||
|
//
|
||||||
|
// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||||
|
// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,
|
||||||
|
// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.Validation;
|
||||||
|
using Yi.Framework.Core.Extensions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult.Fiters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 友好异常拦截器
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FriendlyExceptionFilter : IAsyncExceptionFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异常拦截
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task OnExceptionAsync(ExceptionContext context)
|
||||||
|
{
|
||||||
|
// 排除 WebSocket 请求处理
|
||||||
|
if (context.HttpContext.IsWebSocketRequest()) return;
|
||||||
|
|
||||||
|
// 如果异常在其他地方被标记了处理,那么这里不再处理
|
||||||
|
if (context.ExceptionHandled) return;
|
||||||
|
|
||||||
|
// 解析异常信息
|
||||||
|
var exceptionMetadata = GetExceptionMetadata(context);
|
||||||
|
var unifyResult = context.GetRequiredService<IUnifyResultProvider>();
|
||||||
|
// 执行规范化异常处理
|
||||||
|
context.Result = unifyResult.OnException(context, exceptionMetadata);
|
||||||
|
|
||||||
|
// 创建日志记录器
|
||||||
|
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<FriendlyExceptionFilter>>();
|
||||||
|
|
||||||
|
var errorMsg = "";
|
||||||
|
if (exceptionMetadata.Errors != null) errorMsg = "\n" + JsonConvert.SerializeObject(exceptionMetadata.Errors);
|
||||||
|
|
||||||
|
|
||||||
|
// 记录拦截日常
|
||||||
|
logger.LogError(context.Exception, context.Exception.Message + errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取异常元数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ExceptionMetadata GetExceptionMetadata(ActionContext context)
|
||||||
|
{
|
||||||
|
object errorCode = default;
|
||||||
|
object originErrorCode = default;
|
||||||
|
object errors = default;
|
||||||
|
object data = default;
|
||||||
|
var statusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
var isValidationException = false; // 判断是否是验证异常
|
||||||
|
var isFriendlyException = false;
|
||||||
|
|
||||||
|
// 判断是否是 ExceptionContext 或者 ActionExecutedContext
|
||||||
|
var exception = context is ExceptionContext exContext
|
||||||
|
? exContext.Exception
|
||||||
|
: context is ActionExecutedContext edContext
|
||||||
|
? edContext.Exception
|
||||||
|
: default;
|
||||||
|
|
||||||
|
if (exception is AbpValidationException validationException)
|
||||||
|
{
|
||||||
|
errors = validationException.ValidationErrors;
|
||||||
|
isValidationException = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是友好异常
|
||||||
|
if (exception is UserFriendlyException friendlyException)
|
||||||
|
{
|
||||||
|
var statusCode2 = 500;
|
||||||
|
int.TryParse(friendlyException.Code, out statusCode2);
|
||||||
|
isFriendlyException = true;
|
||||||
|
errorCode = friendlyException.Code;
|
||||||
|
originErrorCode = friendlyException.Code;
|
||||||
|
statusCode = statusCode2 == 0 ? 403 : statusCode2;
|
||||||
|
errors = friendlyException.Message;
|
||||||
|
data = friendlyException.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ExceptionMetadata
|
||||||
|
{
|
||||||
|
StatusCode = statusCode,
|
||||||
|
ErrorCode = errorCode,
|
||||||
|
OriginErrorCode = originErrorCode,
|
||||||
|
Errors = errors,
|
||||||
|
Data = data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Yi.Framework.Core.Extensions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult.Fiters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 规范化结构(请求成功)过滤器
|
||||||
|
/// </summary>
|
||||||
|
public class SucceededUnifyResultFilter : IAsyncActionFilter, IOrderedFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 过滤器排序
|
||||||
|
/// </summary>
|
||||||
|
private const int FilterOrder = 8888;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排序属性
|
||||||
|
/// </summary>
|
||||||
|
public int Order => FilterOrder;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理规范化结果
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="next"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||||
|
{
|
||||||
|
// 执行 Action 并获取结果
|
||||||
|
var actionExecutedContext = await next();
|
||||||
|
|
||||||
|
// 排除 WebSocket 请求处理
|
||||||
|
if (actionExecutedContext.HttpContext.IsWebSocketRequest()) return;
|
||||||
|
|
||||||
|
// 处理已经含有状态码结果的 Result
|
||||||
|
if (actionExecutedContext.Result is IStatusCodeActionResult statusCodeResult &&
|
||||||
|
statusCodeResult.StatusCode != null)
|
||||||
|
{
|
||||||
|
// 小于 200 或者 大于 299 都不是成功值,直接跳过
|
||||||
|
if (statusCodeResult.StatusCode.Value < 200 || statusCodeResult.StatusCode.Value > 299)
|
||||||
|
{
|
||||||
|
// 处理规范化结果
|
||||||
|
if (!CheckStatusCodeNonUnify(context.HttpContext, out var unifyRes))
|
||||||
|
{
|
||||||
|
var httpContext = context.HttpContext;
|
||||||
|
var statusCode = statusCodeResult.StatusCode.Value;
|
||||||
|
|
||||||
|
// 解决刷新 Token 时间和 Token 时间相近问题
|
||||||
|
if (statusCodeResult.StatusCode.Value == StatusCodes.Status401Unauthorized
|
||||||
|
&& httpContext.Response.Headers.ContainsKey("access-token")
|
||||||
|
&& httpContext.Response.Headers.ContainsKey("x-access-token"))
|
||||||
|
{
|
||||||
|
httpContext.Response.StatusCode = statusCode = StatusCodes.Status403Forbidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 Response 已经完成输出,则禁止写入
|
||||||
|
if (httpContext.Response.HasStarted) return;
|
||||||
|
await unifyRes.OnResponseStatusCodes(httpContext, statusCode,
|
||||||
|
httpContext.RequestServices.GetService<IOptions<UnifyResultSettingsOptions>>()?.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果出现异常,则不会进入该过滤器
|
||||||
|
if (actionExecutedContext.Exception != null) return;
|
||||||
|
|
||||||
|
// 获取控制器信息
|
||||||
|
var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
|
||||||
|
|
||||||
|
// 判断是否支持 MVC 规范化处理,检测配置而已
|
||||||
|
// if (!UnifyContext.CheckSupportMvcController(context.HttpContext, actionDescriptor, out _)) return;
|
||||||
|
|
||||||
|
// 判断是否跳过规范化处理,检测NonUnifyAttribute而已
|
||||||
|
if (CheckSucceededNonUnify(actionDescriptor.MethodInfo))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IUnifyResultProvider unifyResult = context.GetRequiredService<IUnifyResultProvider>();
|
||||||
|
|
||||||
|
// 处理 BadRequestObjectResult 类型规范化处理
|
||||||
|
if (actionExecutedContext.Result is BadRequestObjectResult badRequestObjectResult)
|
||||||
|
{
|
||||||
|
// 解析验证消息
|
||||||
|
var validationMetadata = GetValidationMetadata(badRequestObjectResult.Value);
|
||||||
|
|
||||||
|
var result = unifyResult.OnValidateFailed(context, validationMetadata);
|
||||||
|
if (result != null) actionExecutedContext.Result = result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IActionResult result = default;
|
||||||
|
|
||||||
|
// 检查是否是有效的结果(可进行规范化的结果)
|
||||||
|
if (CheckVaildResult(actionExecutedContext.Result, out var data))
|
||||||
|
{
|
||||||
|
result = unifyResult.OnSucceeded(actionExecutedContext, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是不能规范化的结果类型,则跳过
|
||||||
|
if (result == null) return;
|
||||||
|
|
||||||
|
actionExecutedContext.Result = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取验证错误信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="errors"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static ValidationMetadata GetValidationMetadata(object errors)
|
||||||
|
{
|
||||||
|
ModelStateDictionary _modelState = null;
|
||||||
|
object validationResults = null;
|
||||||
|
(string message, string firstErrorMessage, string firstErrorProperty) = (default, default, default);
|
||||||
|
|
||||||
|
// 判断是否是集合类型
|
||||||
|
if (errors is IEnumerable && errors is not string)
|
||||||
|
{
|
||||||
|
// 如果是模型验证字典类型
|
||||||
|
if (errors is ModelStateDictionary modelState)
|
||||||
|
{
|
||||||
|
_modelState = modelState;
|
||||||
|
// 将验证错误信息转换成字典并序列化成 Json
|
||||||
|
validationResults = modelState.Where(u => modelState[u.Key].ValidationState == ModelValidationState.Invalid)
|
||||||
|
.ToDictionary(u => u.Key, u => modelState[u.Key].Errors.Select(c => c.ErrorMessage).ToArray());
|
||||||
|
}
|
||||||
|
// 如果是 ValidationProblemDetails 特殊类型
|
||||||
|
else if (errors is ValidationProblemDetails validation)
|
||||||
|
{
|
||||||
|
validationResults = validation.Errors
|
||||||
|
.ToDictionary(u => u.Key, u => u.Value.ToArray());
|
||||||
|
}
|
||||||
|
// 如果是字典类型
|
||||||
|
else if (errors is Dictionary<string, string[]> dicResults)
|
||||||
|
{
|
||||||
|
validationResults = dicResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
message = JsonSerializer.Serialize(validationResults, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
|
WriteIndented = true
|
||||||
|
});
|
||||||
|
firstErrorMessage = (validationResults as Dictionary<string, string[]>).First().Value[0];
|
||||||
|
firstErrorProperty = (validationResults as Dictionary<string, string[]>).First().Key;
|
||||||
|
}
|
||||||
|
// 其他类型
|
||||||
|
else
|
||||||
|
{
|
||||||
|
validationResults = firstErrorMessage = message = errors?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ValidationMetadata
|
||||||
|
{
|
||||||
|
ValidationResult = validationResults,
|
||||||
|
Message = message,
|
||||||
|
ModelState = _modelState,
|
||||||
|
FirstErrorProperty = firstErrorProperty,
|
||||||
|
FirstErrorMessage = firstErrorMessage
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查是否是有效的结果(可进行规范化的结果)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool CheckVaildResult(IActionResult result, out object data)
|
||||||
|
{
|
||||||
|
data = default;
|
||||||
|
|
||||||
|
// 排除以下结果,跳过规范化处理
|
||||||
|
var isDataResult = result switch
|
||||||
|
{
|
||||||
|
ViewResult => false,
|
||||||
|
PartialViewResult => false,
|
||||||
|
FileResult => false,
|
||||||
|
ChallengeResult => false,
|
||||||
|
SignInResult => false,
|
||||||
|
SignOutResult => false,
|
||||||
|
RedirectToPageResult => false,
|
||||||
|
RedirectToRouteResult => false,
|
||||||
|
RedirectResult => false,
|
||||||
|
RedirectToActionResult => false,
|
||||||
|
LocalRedirectResult => false,
|
||||||
|
ForbidResult => false,
|
||||||
|
ViewComponentResult => false,
|
||||||
|
PageResult => false,
|
||||||
|
NotFoundResult => false,
|
||||||
|
NotFoundObjectResult => false,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 目前支持返回值 ActionResult
|
||||||
|
if (isDataResult) data = result switch
|
||||||
|
{
|
||||||
|
// 处理内容结果
|
||||||
|
ContentResult content => content.Content,
|
||||||
|
// 处理对象结果
|
||||||
|
ObjectResult obj => obj.Value,
|
||||||
|
// 处理 JSON 对象
|
||||||
|
JsonResult json => json.Value,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
return isDataResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查短路状态码(>=400)是否进行规范化处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="unifyResult"></param>
|
||||||
|
/// <returns>返回 true 跳过处理,否则进行规范化处理</returns>
|
||||||
|
internal static bool CheckStatusCodeNonUnify(HttpContext context, out IUnifyResultProvider unifyResult)
|
||||||
|
{
|
||||||
|
// 获取终点路由特性
|
||||||
|
var endpointFeature = context.Features.Get<IEndpointFeature>();
|
||||||
|
if (endpointFeature == null) return (unifyResult = null) == null;
|
||||||
|
|
||||||
|
// 判断是否跳过规范化处理
|
||||||
|
var isSkip = context.GetEndpoint()?.Metadata?.GetMetadata<NonUnifyAttribute>()!= null
|
||||||
|
|| endpointFeature?.Endpoint?.Metadata?.GetMetadata<NonUnifyAttribute>() != null
|
||||||
|
|| context.Request.Headers["accept"].ToString().Contains("odata.metadata=", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| context.Request.Headers["accept"].ToString().Contains("odata.streaming=", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (isSkip == true) unifyResult = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unifyResult = context.RequestServices.GetRequiredService<IUnifyResultProvider>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return unifyResult == null || isSkip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查请求成功是否进行规范化处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="method"></param>
|
||||||
|
/// <param name="isWebRequest"></param>
|
||||||
|
/// <returns>返回 true 跳过处理,否则进行规范化处理</returns>
|
||||||
|
private bool CheckSucceededNonUnify(MethodInfo method, bool isWebRequest = true)
|
||||||
|
{
|
||||||
|
// 判断是否跳过规范化处理
|
||||||
|
var isSkip = method.CustomAttributes.Any(x => typeof(NonUnifyAttribute).IsAssignableFrom(x.AttributeType) || typeof(ProducesResponseTypeAttribute).IsAssignableFrom(x.AttributeType) || typeof(IApiResponseMetadataProvider).IsAssignableFrom(x.AttributeType))
|
||||||
|
|| method.ReflectedType.IsDefined(typeof(NonUnifyAttribute), true)
|
||||||
|
|| method.DeclaringType.Assembly.GetName().Name.StartsWith("Microsoft.AspNetCore.OData");
|
||||||
|
|
||||||
|
if (!isWebRequest)
|
||||||
|
{
|
||||||
|
return isSkip;
|
||||||
|
}
|
||||||
|
return isSkip;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// MIT 许可证
|
||||||
|
//
|
||||||
|
// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者
|
||||||
|
//
|
||||||
|
// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,
|
||||||
|
// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,
|
||||||
|
// 以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||||
|
//
|
||||||
|
// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||||
|
//
|
||||||
|
// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||||
|
// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,
|
||||||
|
// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 规范化结果提供器
|
||||||
|
/// </summary>
|
||||||
|
public interface IUnifyResultProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异常返回值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="metadata"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 成功返回值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IActionResult OnSucceeded(ActionExecutedContext context, object data);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证失败返回值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="metadata"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 拦截返回状态码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="statusCode"></param>
|
||||||
|
/// <param name="unifyResultSettings"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings = default);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// MIT 许可证
|
||||||
|
//
|
||||||
|
// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者
|
||||||
|
//
|
||||||
|
// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,
|
||||||
|
// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,
|
||||||
|
// 以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||||
|
//
|
||||||
|
// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||||
|
//
|
||||||
|
// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||||
|
// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,
|
||||||
|
// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 禁止规范化处理
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
|
||||||
|
public sealed class NonUnifyAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
// MIT 许可证
|
||||||
|
//
|
||||||
|
// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者
|
||||||
|
//
|
||||||
|
// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,
|
||||||
|
// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,
|
||||||
|
// 以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||||
|
//
|
||||||
|
// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||||
|
//
|
||||||
|
// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||||
|
// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,
|
||||||
|
// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult.Providers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RESTful 风格返回值
|
||||||
|
/// </summary>
|
||||||
|
[Dependency(TryRegister = true)]
|
||||||
|
[ExposeServices(typeof(IUnifyResultProvider))]
|
||||||
|
public class RESTfulResultProvider : IUnifyResultProvider,ITransientDependency
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设置响应状态码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="statusCode"></param>
|
||||||
|
/// <param name="unifyResultSettings"></param>
|
||||||
|
public static void SetResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings)
|
||||||
|
{
|
||||||
|
if (unifyResultSettings == null) return;
|
||||||
|
|
||||||
|
// 篡改响应状态码
|
||||||
|
if (unifyResultSettings.AdaptStatusCodes != null && unifyResultSettings.AdaptStatusCodes.Length > 0)
|
||||||
|
{
|
||||||
|
var adaptStatusCode = unifyResultSettings.AdaptStatusCodes.FirstOrDefault(u => u[0] == statusCode);
|
||||||
|
if (adaptStatusCode != null && adaptStatusCode.Length > 0 && adaptStatusCode[0] > 0)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = adaptStatusCode[1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果为 null,则所有请求错误的状态码设置为 200
|
||||||
|
if (unifyResultSettings.Return200StatusCodes == null) context.Response.StatusCode = 200;
|
||||||
|
// 否则只有里面的才设置为 200
|
||||||
|
else if (unifyResultSettings.Return200StatusCodes.Contains(statusCode)) context.Response.StatusCode = 200;
|
||||||
|
else { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异常返回值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="metadata"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
|
||||||
|
{
|
||||||
|
return new JsonResult(RESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 成功返回值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IActionResult OnSucceeded(ActionExecutedContext context, object data)
|
||||||
|
{
|
||||||
|
return new JsonResult(RESTfulResult(StatusCodes.Status200OK, true, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证失败/业务异常返回值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="metadata"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
|
||||||
|
{
|
||||||
|
return new JsonResult(RESTfulResult(metadata.StatusCode ?? StatusCodes.Status400BadRequest, data: metadata.Data, errors: metadata.ValidationResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 特定状态码返回值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="statusCode"></param>
|
||||||
|
/// <param name="unifyResultSettings"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings)
|
||||||
|
{
|
||||||
|
// 设置响应状态码
|
||||||
|
SetResponseStatusCodes(context, statusCode, unifyResultSettings);
|
||||||
|
|
||||||
|
switch (statusCode)
|
||||||
|
{
|
||||||
|
// 处理 401 状态码
|
||||||
|
case StatusCodes.Status401Unauthorized:
|
||||||
|
await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "401 Unauthorized"));
|
||||||
|
break;
|
||||||
|
// 处理 403 状态码
|
||||||
|
case StatusCodes.Status403Forbidden:
|
||||||
|
await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "403 Forbidden"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回 RESTful 风格结果集
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="statusCode"></param>
|
||||||
|
/// <param name="succeeded"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="errors"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static RESTfulResult<object> RESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default)
|
||||||
|
{
|
||||||
|
return new RESTfulResult<object>
|
||||||
|
{
|
||||||
|
StatusCode = statusCode,
|
||||||
|
Succeeded = succeeded,
|
||||||
|
Data = data,
|
||||||
|
Errors = errors,
|
||||||
|
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// MIT 许可证
|
||||||
|
//
|
||||||
|
// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者
|
||||||
|
//
|
||||||
|
// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,
|
||||||
|
// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,
|
||||||
|
// 以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||||
|
//
|
||||||
|
// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||||
|
//
|
||||||
|
// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||||
|
// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,
|
||||||
|
// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RESTful 风格结果集
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public class RESTfulResult<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 状态码
|
||||||
|
/// </summary>
|
||||||
|
public int? StatusCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据
|
||||||
|
/// </summary>
|
||||||
|
public T Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行成功
|
||||||
|
/// </summary>
|
||||||
|
public bool Succeeded { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误信息
|
||||||
|
/// </summary>
|
||||||
|
public object Errors { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 附加数据
|
||||||
|
/// </summary>
|
||||||
|
public object Extras { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时间戳
|
||||||
|
/// </summary>
|
||||||
|
public long Timestamp { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc.Response;
|
||||||
|
using Yi.Framework.AspNetCore.UnifyResult.Fiters;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 规范化接口
|
||||||
|
/// 由于太多人反应,想兼容一套类似furion的返回情况,200状态码包一层更符合国内习惯,既然如此,不如直接搬过来
|
||||||
|
/// </summary>
|
||||||
|
public static class UnifyResultExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddFurionUnifyResultApi(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
//成功规范接口
|
||||||
|
services.AddTransient<SucceededUnifyResultFilter>();
|
||||||
|
//异常规范接口
|
||||||
|
services.AddTransient<FriendlyExceptionFilter>();
|
||||||
|
services.AddMvc(options =>
|
||||||
|
{
|
||||||
|
options.Filters.RemoveAll(x => (x as ServiceFilterAttribute)?.ServiceType == typeof(AbpExceptionFilter));
|
||||||
|
options.Filters.RemoveAll(x => (x as ServiceFilterAttribute)?.ServiceType == typeof(AbpNoContentActionFilter));
|
||||||
|
options.Filters.AddService<SucceededUnifyResultFilter>(99);
|
||||||
|
options.Filters.AddService<FriendlyExceptionFilter>(100);
|
||||||
|
});
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// MIT 许可证
|
||||||
|
//
|
||||||
|
// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者
|
||||||
|
//
|
||||||
|
// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,
|
||||||
|
// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,
|
||||||
|
// 以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||||
|
//
|
||||||
|
// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||||
|
//
|
||||||
|
// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||||
|
// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,
|
||||||
|
// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 规范化配置选项
|
||||||
|
/// </summary>
|
||||||
|
public sealed class UnifyResultSettingsOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设置返回 200 状态码列表
|
||||||
|
/// <para>默认:401,403,如果设置为 null,则标识所有状态码都返回 200 </para>
|
||||||
|
/// </summary>
|
||||||
|
public int[] Return200StatusCodes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 适配(篡改)Http 状态码(只支持短路状态码,比如 401,403,500 等)
|
||||||
|
/// </summary>
|
||||||
|
public int[][] AdaptStatusCodes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否支持 MVC 控制台规范化处理
|
||||||
|
/// </summary>
|
||||||
|
public bool? SupportMvcController { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选项后期配置
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
|
public void PostConfigure(UnifyResultSettingsOptions options, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
options.Return200StatusCodes ??= new[] { 401, 403 };
|
||||||
|
options.SupportMvcController ??= false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// MIT 许可证
|
||||||
|
//
|
||||||
|
// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者
|
||||||
|
//
|
||||||
|
// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利,
|
||||||
|
// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本,
|
||||||
|
// 以及再授权被配发了本软件的人如上的权利,须在下列条件下:
|
||||||
|
//
|
||||||
|
// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。
|
||||||
|
//
|
||||||
|
// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。
|
||||||
|
// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中,
|
||||||
|
// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore.UnifyResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证信息元数据
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ValidationMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 验证结果
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>返回字典或字符串类型</remarks>
|
||||||
|
public object ValidationResult { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异常消息
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证状态
|
||||||
|
/// </summary>
|
||||||
|
public ModelStateDictionary ModelState { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误码
|
||||||
|
/// </summary>
|
||||||
|
public object ErrorCode { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误码(没被复写过的 ErrorCode )
|
||||||
|
/// </summary>
|
||||||
|
public object OriginErrorCode { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 状态码
|
||||||
|
/// </summary>
|
||||||
|
public int? StatusCode { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 首个错误属性
|
||||||
|
/// </summary>
|
||||||
|
public string FirstErrorProperty { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 首个错误消息
|
||||||
|
/// </summary>
|
||||||
|
public string FirstErrorMessage { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外数据
|
||||||
|
/// </summary>
|
||||||
|
public object Data { get; internal set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Cors\**" />
|
||||||
|
<EmbeddedResource Remove="Cors\**" />
|
||||||
|
<None Remove="Cors\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Volo.Abp.Json" Version="$(AbpVersion)" />
|
||||||
|
<PackageReference Include="Volo.Abp.Swashbuckle" Version="$(AbpVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Volo.Abp.AspNetCore.WebClientInfo;
|
||||||
|
using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Authentication;
|
||||||
|
using Yi.Framework.Core;
|
||||||
|
using Yi.Framework.Core.Authentication;
|
||||||
|
|
||||||
|
namespace Yi.Framework.AspNetCore
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Yi框架ASP.NET Core模块
|
||||||
|
/// </summary>
|
||||||
|
[DependsOn(typeof(YiFrameworkCoreModule))]
|
||||||
|
public class YiFrameworkAspNetCoreModule : AbpModule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 配置服务后的处理
|
||||||
|
/// </summary>
|
||||||
|
public override void PostConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
var services = context.Services;
|
||||||
|
|
||||||
|
// 替换默认的WebClientInfoProvider为支持代理的实现
|
||||||
|
services.Replace(new ServiceDescriptor(
|
||||||
|
typeof(IWebClientInfoProvider),
|
||||||
|
typeof(RealIpHttpContextWebClientInfoProvider),
|
||||||
|
ServiceLifetime.Transient));
|
||||||
|
|
||||||
|
// 替换默认的AuthenticationHandlerProvider为支持刷新鉴权
|
||||||
|
services.Replace(new ServiceDescriptor(
|
||||||
|
typeof(IAuthenticationHandlerProvider),
|
||||||
|
typeof(RefreshAuthenticationHandlerProvider),
|
||||||
|
ServiceLifetime.Scoped));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
using Hangfire.Server;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Threading;
|
||||||
|
using Volo.Abp.Uow;
|
||||||
|
|
||||||
|
namespace Yi.Framework.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hangfire 工作单元过滤器
|
||||||
|
/// 用于管理后台任务的事务处理
|
||||||
|
/// </summary>
|
||||||
|
public sealed class UnitOfWorkHangfireFilter : IServerFilter, ISingletonDependency
|
||||||
|
{
|
||||||
|
private const string UnitOfWorkItemKey = "HangfireUnitOfWork";
|
||||||
|
private readonly IUnitOfWorkManager _unitOfWorkManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化工作单元过滤器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="unitOfWorkManager">工作单元管理器</param>
|
||||||
|
public UnitOfWorkHangfireFilter(IUnitOfWorkManager unitOfWorkManager)
|
||||||
|
{
|
||||||
|
_unitOfWorkManager = unitOfWorkManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 任务执行前的处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">执行上下文</param>
|
||||||
|
public void OnPerforming(PerformingContext context)
|
||||||
|
{
|
||||||
|
// 开启一个工作单元并存储到上下文中
|
||||||
|
var uow = _unitOfWorkManager.Begin();
|
||||||
|
context.Items.Add(UnitOfWorkItemKey, uow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 任务执行后的处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">执行上下文</param>
|
||||||
|
public void OnPerformed(PerformedContext context)
|
||||||
|
{
|
||||||
|
AsyncHelper.RunSync(() => OnPerformedAsync(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 任务执行后的异步处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">执行上下文</param>
|
||||||
|
private async Task OnPerformedAsync(PerformedContext context)
|
||||||
|
{
|
||||||
|
if (!context.Items.TryGetValue(UnitOfWorkItemKey, out var obj) ||
|
||||||
|
obj is not IUnitOfWork uow)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 如果没有异常且工作单元未完成,则提交事务
|
||||||
|
if (context.Exception == null && !uow.IsCompleted)
|
||||||
|
{
|
||||||
|
await uow.CompleteAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 否则回滚事务
|
||||||
|
await uow.RollbackAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// 确保工作单元被释放
|
||||||
|
uow.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Volo.Abp.BackgroundJobs.Hangfire" Version="$(AbpVersion)" />
|
||||||
|
<PackageReference Include="Volo.Abp.BackgroundWorkers.Hangfire" Version="$(AbpVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using Hangfire;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Volo.Abp.BackgroundJobs.Hangfire;
|
||||||
|
using Volo.Abp.BackgroundWorkers;
|
||||||
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
|
using Volo.Abp.DynamicProxy;
|
||||||
|
|
||||||
|
namespace Yi.Framework.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hangfire 后台任务模块
|
||||||
|
/// </summary>
|
||||||
|
[DependsOn(typeof(AbpBackgroundWorkersHangfireModule),
|
||||||
|
typeof(AbpBackgroundJobsHangfireModule))]
|
||||||
|
public sealed class YiFrameworkBackgroundWorkersHangfireModule : AbpModule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 配置服务前的预处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">服务配置上下文</param>
|
||||||
|
public override void PreConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
// 添加 Hangfire 后台任务约定注册器
|
||||||
|
context.Services.AddConventionalRegistrar(new YiHangfireConventionalRegistrar());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用程序初始化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">应用程序初始化上下文</param>
|
||||||
|
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||||
|
{
|
||||||
|
if (!context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundWorkerOptions>>().Value.IsEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 获取后台任务管理器和所有 Hangfire 后台任务
|
||||||
|
var backgroundWorkerManager = context.ServiceProvider.GetRequiredService<IBackgroundWorkerManager>();
|
||||||
|
var workers = context.ServiceProvider.GetServices<IHangfireBackgroundWorker>();
|
||||||
|
|
||||||
|
// 获取配置
|
||||||
|
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
|
||||||
|
|
||||||
|
// 检查是否启用 Redis
|
||||||
|
var isRedisEnabled = configuration.GetValue<bool>("Redis:IsEnabled");
|
||||||
|
|
||||||
|
foreach (var worker in workers)
|
||||||
|
{
|
||||||
|
// 设置时区为本地时区(上海)
|
||||||
|
worker.TimeZone = TimeZoneInfo.Local;
|
||||||
|
|
||||||
|
if (isRedisEnabled)
|
||||||
|
{
|
||||||
|
// Redis 模式:使用 ABP 后台任务管理器
|
||||||
|
await backgroundWorkerManager.AddAsync(worker);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 内存模式:直接使用 Hangfire
|
||||||
|
var unProxyWorker = ProxyHelper.UnProxy(worker);
|
||||||
|
|
||||||
|
// 添加或更新循环任务
|
||||||
|
RecurringJob.AddOrUpdate(
|
||||||
|
worker.RecurringJobId,
|
||||||
|
(Expression<Func<Task>>)(() =>
|
||||||
|
((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(default)),
|
||||||
|
worker.CronExpression,
|
||||||
|
new RecurringJobOptions
|
||||||
|
{
|
||||||
|
TimeZone = worker.TimeZone
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用程序初始化前的预处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">应用程序初始化上下文</param>
|
||||||
|
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
|
||||||
|
{
|
||||||
|
// 添加工作单元过滤器
|
||||||
|
var services = context.ServiceProvider;
|
||||||
|
GlobalJobFilters.Filters.Add(services.GetRequiredService<UnitOfWorkHangfireFilter>());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using Volo.Abp.BackgroundWorkers.Hangfire;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Yi.Framework.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hangfire 后台任务约定注册器
|
||||||
|
/// </summary>
|
||||||
|
public sealed class YiHangfireConventionalRegistrar : DefaultConventionalRegistrar
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 检查类型是否禁用约定注册
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">要检查的类型</param>
|
||||||
|
/// <returns>如果类型不是 IHangfireBackgroundWorker 或已被禁用则返回 true</returns>
|
||||||
|
protected override bool IsConventionalRegistrationDisabled(Type type)
|
||||||
|
{
|
||||||
|
return !typeof(IHangfireBackgroundWorker).IsAssignableFrom(type) ||
|
||||||
|
base.IsConventionalRegistrationDisabled(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取要暴露的服务类型列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">实现类型</param>
|
||||||
|
/// <returns>服务类型列表</returns>
|
||||||
|
protected override List<Type> GetExposedServiceTypes(Type type)
|
||||||
|
{
|
||||||
|
return new List<Type>
|
||||||
|
{
|
||||||
|
typeof(IHangfireBackgroundWorker)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
using Hangfire.Dashboard;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Users;
|
||||||
|
|
||||||
|
namespace Yi.Framework.BackgroundWorkers.Hangfire;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hangfire 仪表盘的令牌认证过滤器
|
||||||
|
/// </summary>
|
||||||
|
public sealed class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, ITransientDependency
|
||||||
|
{
|
||||||
|
private const string BearerPrefix = "Bearer ";
|
||||||
|
private const string TokenCookieKey = "Token";
|
||||||
|
private const string HtmlContentType = "text/html";
|
||||||
|
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private string _requiredUsername = "cc";
|
||||||
|
private TimeSpan _tokenExpiration = TimeSpan.FromMinutes(10);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化令牌认证过滤器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceProvider">服务提供者</param>
|
||||||
|
public YiTokenAuthorizationFilter(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置需要的用户名
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">允许访问的用户名</param>
|
||||||
|
/// <returns>当前实例,支持链式调用</returns>
|
||||||
|
public YiTokenAuthorizationFilter SetRequiredUsername(string username)
|
||||||
|
{
|
||||||
|
_requiredUsername = username ?? throw new ArgumentNullException(nameof(username));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置令牌过期时间
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="expiration">过期时间间隔</param>
|
||||||
|
/// <returns>当前实例,支持链式调用</returns>
|
||||||
|
public YiTokenAuthorizationFilter SetTokenExpiration(TimeSpan expiration)
|
||||||
|
{
|
||||||
|
_tokenExpiration = expiration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 授权验证
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">仪表盘上下文</param>
|
||||||
|
/// <returns>是否通过授权</returns>
|
||||||
|
public bool Authorize(DashboardContext context)
|
||||||
|
{
|
||||||
|
var httpContext = context.GetHttpContext();
|
||||||
|
var currentUser = _serviceProvider.GetRequiredService<ICurrentUser>();
|
||||||
|
|
||||||
|
if (!currentUser.IsAuthenticated)
|
||||||
|
{
|
||||||
|
SetChallengeResponse(httpContext);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果验证通过,设置 cookie
|
||||||
|
var authorization = httpContext.Request.Headers.Authorization.ToString();
|
||||||
|
if (!string.IsNullOrWhiteSpace(authorization) && authorization.StartsWith(BearerPrefix))
|
||||||
|
{
|
||||||
|
var token = authorization[BearerPrefix.Length..];
|
||||||
|
SetTokenCookie(httpContext, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentUser.UserName == _requiredUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置认证挑战响应
|
||||||
|
/// 当用户未认证时,返回一个包含令牌输入表单的HTML页面
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext">HTTP 上下文</param>
|
||||||
|
private void SetChallengeResponse(HttpContext httpContext)
|
||||||
|
{
|
||||||
|
httpContext.Response.StatusCode = 401;
|
||||||
|
httpContext.Response.ContentType = HtmlContentType;
|
||||||
|
|
||||||
|
var html = @"
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Hangfire Dashboard Authorization</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 40px; }
|
||||||
|
.container { max-width: 400px; margin: 0 auto; }
|
||||||
|
.form-group { margin-bottom: 15px; }
|
||||||
|
input[type='text'] { width: 100%; padding: 8px; }
|
||||||
|
button { background: #337ab7; color: white; border: none; padding: 10px 15px; cursor: pointer; }
|
||||||
|
button:hover { background: #286090; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class='container'>
|
||||||
|
<h2>Authorization Required</h2>
|
||||||
|
<div class='form-group'>
|
||||||
|
<input type='text' id='token' placeholder='Enter your Bearer token...' />
|
||||||
|
</div>
|
||||||
|
<button onclick='authorize()'>Authorize</button>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function authorize() {
|
||||||
|
var token = document.getElementById('token').value;
|
||||||
|
if (token) {
|
||||||
|
document.cookie = 'Token=' + token + '; path=/';
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>";
|
||||||
|
|
||||||
|
httpContext.Response.WriteAsync(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置令牌 Cookie
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext">HTTP 上下文</param>
|
||||||
|
/// <param name="token">令牌值</param>
|
||||||
|
private void SetTokenCookie(HttpContext httpContext, string token)
|
||||||
|
{
|
||||||
|
var cookieOptions = new CookieOptions
|
||||||
|
{
|
||||||
|
Expires = DateTimeOffset.Now.Add(_tokenExpiration),
|
||||||
|
HttpOnly = true,
|
||||||
|
Secure = httpContext.Request.IsHttps,
|
||||||
|
SameSite = SameSiteMode.Lax
|
||||||
|
};
|
||||||
|
|
||||||
|
httpContext.Response.Cookies.Append(TokenCookieKey, token, cookieOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> AuthorizeAsync(DashboardContext context)
|
||||||
|
{
|
||||||
|
return Task.FromResult(Authorize(context));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FreeRedis;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Caching.FreeRedis
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 便于转到定义
|
||||||
|
/// </summary>
|
||||||
|
public class FreeSqlOptions: ConnectionStringBuilder
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\common.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FreeRedis" Version="1.2.14" />
|
||||||
|
<PackageReference Include="FreeRedis.DistributedCache" Version="1.2.5" />
|
||||||
|
<PackageReference Include="Volo.Abp.Caching" Version="$(AbpVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Volo.Abp.Caching;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Caching.FreeRedis
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存键标准化处理器
|
||||||
|
/// 用于处理缓存键的格式化和多租户支持
|
||||||
|
/// </summary>
|
||||||
|
[Dependency(ReplaceServices = true)]
|
||||||
|
public class YiDistributedCacheKeyNormalizer : IDistributedCacheKeyNormalizer, ITransientDependency
|
||||||
|
{
|
||||||
|
private readonly ICurrentTenant _currentTenant;
|
||||||
|
private readonly AbpDistributedCacheOptions _distributedCacheOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentTenant">当前租户服务</param>
|
||||||
|
/// <param name="distributedCacheOptions">分布式缓存配置选项</param>
|
||||||
|
public YiDistributedCacheKeyNormalizer(
|
||||||
|
ICurrentTenant currentTenant,
|
||||||
|
IOptions<AbpDistributedCacheOptions> distributedCacheOptions)
|
||||||
|
{
|
||||||
|
_currentTenant = currentTenant;
|
||||||
|
_distributedCacheOptions = distributedCacheOptions.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标准化缓存键
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">缓存键标准化参数</param>
|
||||||
|
/// <returns>标准化后的缓存键</returns>
|
||||||
|
public virtual string NormalizeKey(DistributedCacheKeyNormalizeArgs args)
|
||||||
|
{
|
||||||
|
// 添加全局缓存前缀
|
||||||
|
var normalizedKey = $"{_distributedCacheOptions.KeyPrefix}{args.Key}";
|
||||||
|
|
||||||
|
//todo 多租户支持已注释,如需启用取消注释即可
|
||||||
|
//if (!args.IgnoreMultiTenancy && _currentTenant.Id.HasValue)
|
||||||
|
//{
|
||||||
|
// normalizedKey = $"t:{_currentTenant.Id.Value},{normalizedKey}";
|
||||||
|
//}
|
||||||
|
|
||||||
|
return normalizedKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using FreeRedis;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Volo.Abp.Caching;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Caching.FreeRedis
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// FreeRedis缓存模块
|
||||||
|
/// 提供基于FreeRedis的分布式缓存实现
|
||||||
|
/// </summary>
|
||||||
|
[DependsOn(typeof(AbpCachingModule))]
|
||||||
|
public class YiFrameworkCachingFreeRedisModule : AbpModule
|
||||||
|
{
|
||||||
|
private const string RedisEnabledKey = "Redis:IsEnabled";
|
||||||
|
private const string RedisConfigurationKey = "Redis:Configuration";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置服务
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">服务配置上下文</param>
|
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
var configuration = context.Services.GetConfiguration();
|
||||||
|
|
||||||
|
// 检查Redis是否启用
|
||||||
|
if (!IsRedisEnabled(configuration))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册Redis服务
|
||||||
|
RegisterRedisServices(context, configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查Redis是否启用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration">配置</param>
|
||||||
|
/// <returns>是否启用Redis</returns>
|
||||||
|
private static bool IsRedisEnabled(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var redisEnabled = configuration[RedisEnabledKey];
|
||||||
|
return redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册Redis相关服务
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">服务配置上下文</param>
|
||||||
|
/// <param name="configuration">配置</param>
|
||||||
|
private static void RegisterRedisServices(ServiceConfigurationContext context, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var redisConfiguration = configuration[RedisConfigurationKey];
|
||||||
|
var redisClient = new RedisClient(redisConfiguration);
|
||||||
|
|
||||||
|
context.Services.AddSingleton<IRedisClient>(redisClient);
|
||||||
|
context.Services.Replace(ServiceDescriptor.Singleton<IDistributedCache>(
|
||||||
|
new DistributedCache(redisClient)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Authentication;
|
||||||
|
|
||||||
|
public static class AuthenticationExtensions
|
||||||
|
{
|
||||||
|
public static void RefreshAuthentication(this HttpContext context)
|
||||||
|
{
|
||||||
|
var currentAuthenticationHandler =
|
||||||
|
context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
|
||||||
|
if (currentAuthenticationHandler is IRefreshAuthenticationHandlerProvider refreshAuthenticationHandler)
|
||||||
|
{
|
||||||
|
refreshAuthenticationHandler.RefreshAuthentication();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Authentication;
|
||||||
|
|
||||||
|
public interface IRefreshAuthenticationHandlerProvider: IAuthenticationHandlerProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新鉴权
|
||||||
|
/// </summary>
|
||||||
|
void RefreshAuthentication();
|
||||||
|
}
|
||||||
26
Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IOrderNum.cs
Normal file
26
Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IOrderNum.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Data
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 排序接口
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 实现此接口的实体类将支持排序功能
|
||||||
|
/// 通常用于列表数据的展示顺序控制
|
||||||
|
/// </remarks>
|
||||||
|
public interface IOrderNum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 排序号
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 数字越小越靠前,默认为0
|
||||||
|
/// </remarks>
|
||||||
|
int OrderNum { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IState.cs
Normal file
26
Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IState.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Data
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 状态接口
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 实现此接口的实体类将支持启用/禁用状态管理
|
||||||
|
/// 用于控制数据记录的可用状态
|
||||||
|
/// </remarks>
|
||||||
|
public interface IState
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 状态标识
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// true表示启用,false表示禁用
|
||||||
|
/// </remarks>
|
||||||
|
bool State { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Enums
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 文件类型枚举
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 用于定义系统支持的文件类型分类
|
||||||
|
/// 主要用于文件上传和存储时的类型区分
|
||||||
|
/// </remarks>
|
||||||
|
public enum FileTypeEnum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 普通文件
|
||||||
|
/// </summary>
|
||||||
|
file = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图片文件
|
||||||
|
/// </summary>
|
||||||
|
image = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缩略图文件
|
||||||
|
/// </summary>
|
||||||
|
thumbnail = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Excel文件
|
||||||
|
/// </summary>
|
||||||
|
excel = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 临时文件
|
||||||
|
/// </summary>
|
||||||
|
temp = 4
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/OrderByEnum.cs
Normal file
28
Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/OrderByEnum.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Enums
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 排序方向枚举
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 用于定义数据查询时的排序方向
|
||||||
|
/// 常用于列表数据排序
|
||||||
|
/// </remarks>
|
||||||
|
public enum OrderByEnum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 升序排列
|
||||||
|
/// </summary>
|
||||||
|
Asc = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 降序排列
|
||||||
|
/// </summary>
|
||||||
|
Desc = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Enums
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 查询操作符枚举
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 定义查询条件中支持的操作符类型
|
||||||
|
/// 用于构建动态查询条件
|
||||||
|
/// </remarks>
|
||||||
|
public enum QueryOperatorEnum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 等于
|
||||||
|
/// </summary>
|
||||||
|
Equal = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模糊匹配
|
||||||
|
/// </summary>
|
||||||
|
Like = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 大于
|
||||||
|
/// </summary>
|
||||||
|
GreaterThan = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 大于或等于
|
||||||
|
/// </summary>
|
||||||
|
GreaterThanOrEqual = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 小于
|
||||||
|
/// </summary>
|
||||||
|
LessThan = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 小于或等于
|
||||||
|
/// </summary>
|
||||||
|
LessThanOrEqual = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在指定集合中
|
||||||
|
/// </summary>
|
||||||
|
In = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 不在指定集合中
|
||||||
|
/// </summary>
|
||||||
|
NotIn = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 左侧模糊匹配
|
||||||
|
/// </summary>
|
||||||
|
LikeLeft = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 右侧模糊匹配
|
||||||
|
/// </summary>
|
||||||
|
LikeRight = 9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 不等于
|
||||||
|
/// </summary>
|
||||||
|
NoEqual = 10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为null或空
|
||||||
|
/// </summary>
|
||||||
|
IsNullOrEmpty = 11,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 不为null
|
||||||
|
/// </summary>
|
||||||
|
IsNot = 12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 不匹配
|
||||||
|
/// </summary>
|
||||||
|
NoLike = 13,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 日期范围
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 使用"|"分隔起始和结束日期
|
||||||
|
/// </remarks>
|
||||||
|
DateRange = 14
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Enums
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// API返回状态码枚举
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 定义API接口统一的返回状态码
|
||||||
|
/// 遵循HTTP状态码规范
|
||||||
|
/// </remarks>
|
||||||
|
public enum ResultCodeEnum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 操作成功
|
||||||
|
/// </summary>
|
||||||
|
Success = 200,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 未授权访问
|
||||||
|
/// </summary>
|
||||||
|
NoPermission = 401,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 访问被拒绝
|
||||||
|
/// </summary>
|
||||||
|
Denied = 403,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 操作失败
|
||||||
|
/// </summary>
|
||||||
|
NotSuccess = 500
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HttpContext扩展方法类
|
||||||
|
/// </summary>
|
||||||
|
public static class HttpContextExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设置内联文件下载响应头
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext">HTTP上下文</param>
|
||||||
|
/// <param name="fileName">文件名</param>
|
||||||
|
public static void FileInlineHandle(this HttpContext httpContext, string fileName)
|
||||||
|
{
|
||||||
|
var encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.UTF8);
|
||||||
|
httpContext.Response.Headers.Add("Content-Disposition", $"inline;filename={encodeFilename}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置附件下载响应头
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext">HTTP上下文</param>
|
||||||
|
/// <param name="fileName">文件名</param>
|
||||||
|
public static void FileAttachmentHandle(this HttpContext httpContext, string fileName)
|
||||||
|
{
|
||||||
|
var encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.UTF8);
|
||||||
|
httpContext.Response.Headers.Add("Content-Disposition", $"attachment;filename={encodeFilename}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取客户端首选语言
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext">HTTP上下文</param>
|
||||||
|
/// <returns>语言代码,默认返回zh-CN</returns>
|
||||||
|
public static string GetLanguage(this HttpContext httpContext)
|
||||||
|
{
|
||||||
|
const string defaultLanguage = "zh-CN";
|
||||||
|
var acceptLanguage = httpContext.Request.Headers["Accept-Language"].FirstOrDefault();
|
||||||
|
|
||||||
|
return string.IsNullOrEmpty(acceptLanguage)
|
||||||
|
? defaultLanguage
|
||||||
|
: acceptLanguage.Split(',')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断是否为Ajax请求
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">HTTP请求</param>
|
||||||
|
/// <returns>是否为Ajax请求</returns>
|
||||||
|
public static bool IsAjaxRequest(this HttpRequest request)
|
||||||
|
{
|
||||||
|
const string ajaxHeader = "XMLHttpRequest";
|
||||||
|
return ajaxHeader.Equals(request.Headers["X-Requested-With"],
|
||||||
|
StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取客户端IP地址
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP上下文</param>
|
||||||
|
/// <returns>客户端IP地址</returns>
|
||||||
|
public static string GetClientIp(this HttpContext context)
|
||||||
|
{
|
||||||
|
const string localhost = "127.0.0.1";
|
||||||
|
if (context == null) return string.Empty;
|
||||||
|
|
||||||
|
// 尝试获取X-Forwarded-For头
|
||||||
|
var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||||
|
|
||||||
|
// 如果没有代理头,则获取远程IP
|
||||||
|
if (string.IsNullOrEmpty(ip))
|
||||||
|
{
|
||||||
|
ip = context.Connection.RemoteIpAddress?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理特殊IP
|
||||||
|
if (string.IsNullOrEmpty(ip) || ip.Contains("::1"))
|
||||||
|
{
|
||||||
|
return localhost;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理IPv6格式
|
||||||
|
ip = ip.Replace("::ffff:", localhost);
|
||||||
|
|
||||||
|
// 移除端口号
|
||||||
|
ip = Regex.Replace(ip, @":\d{1,5}$", "");
|
||||||
|
|
||||||
|
// 验证IP格式
|
||||||
|
var isValidIp = Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$") ||
|
||||||
|
Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?):\d{1,5}$");
|
||||||
|
|
||||||
|
return isValidIp ? ip : localhost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取User-Agent信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP上下文</param>
|
||||||
|
/// <returns>User-Agent字符串</returns>
|
||||||
|
public static string GetUserAgent(this HttpContext context)
|
||||||
|
{
|
||||||
|
return context.Request.Headers["User-Agent"].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取用户权限声明值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP上下文</param>
|
||||||
|
/// <param name="permissionsName">权限声明名称</param>
|
||||||
|
/// <returns>权限值数组</returns>
|
||||||
|
public static string[]? GetUserPermissions(this HttpContext context, string permissionsName)
|
||||||
|
{
|
||||||
|
return context.User.Claims
|
||||||
|
.Where(x => x.Type == permissionsName)
|
||||||
|
.Select(x => x.Value)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断是否为WebSocket请求
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP上下文</param>
|
||||||
|
/// <returns>是否为WebSocket请求</returns>
|
||||||
|
public static bool IsWebSocketRequest(this HttpContext context)
|
||||||
|
{
|
||||||
|
return context.WebSockets.IsWebSocketRequest ||
|
||||||
|
context.Request.Path == "/ws";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class AssemblyHelper
|
public static class AssemblyHelper
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public sealed class Base32Helper
|
public sealed class Base32Helper
|
||||||
{
|
{
|
||||||
405
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ComputerHelper.cs
Normal file
405
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ComputerHelper.cs
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Helper
|
||||||
|
{
|
||||||
|
public class ComputerHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将object转换为long,若转换失败,则返回0。不抛出异常。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static long ParseToLong( object obj)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return long.Parse(obj.ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将string转换为DateTime,若转换失败,则返回日期最小值。不抛出异常。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static DateTime ParseToDateTime( string str)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(str))
|
||||||
|
{
|
||||||
|
return DateTime.MinValue;
|
||||||
|
}
|
||||||
|
if (str.Contains("-") || str.Contains("/"))
|
||||||
|
{
|
||||||
|
return DateTime.Parse(str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int length = str.Length;
|
||||||
|
switch (length)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture);
|
||||||
|
case 6:
|
||||||
|
return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture);
|
||||||
|
case 8:
|
||||||
|
return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
|
||||||
|
case 10:
|
||||||
|
return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture);
|
||||||
|
case 12:
|
||||||
|
return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture);
|
||||||
|
case 14:
|
||||||
|
return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
|
||||||
|
default:
|
||||||
|
return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return DateTime.MinValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static double ParseToDouble(object obj)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return double.Parse(obj.ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// CPU使用情况
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static CPUMetrics GetCPUMetrics()
|
||||||
|
{
|
||||||
|
CPUMetrics cpuMetrics = new CPUMetrics();
|
||||||
|
var cpudetail = GetCPUDetails();
|
||||||
|
cpuMetrics.CoreTotal = cpudetail.Cores;
|
||||||
|
cpuMetrics.LogicalProcessors =cpudetail.LogicalProcessors;
|
||||||
|
cpuMetrics.CPURate = Math.Ceiling(ParseToDouble(GetCPURate()));
|
||||||
|
cpuMetrics.FreeRate = 1 - cpuMetrics.CPURate;
|
||||||
|
return cpuMetrics;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 内存使用情况
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static MemoryMetrics GetMemoryMetrics()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MemoryMetricsClient client = new();
|
||||||
|
MemoryMetrics memoryMetrics = IsUnix() ? client.GetUnixMetrics() : client.GetWindowsMetrics();
|
||||||
|
|
||||||
|
memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB";
|
||||||
|
memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB";
|
||||||
|
memoryMetrics.TotalRAM = Math.Round(memoryMetrics.Total / 1024, 2) + "GB";
|
||||||
|
memoryMetrics.RAMRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + "%";
|
||||||
|
|
||||||
|
return memoryMetrics;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("获取内存使用出错,msg=" + ex.Message + "," + ex.StackTrace);
|
||||||
|
}
|
||||||
|
return new MemoryMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取磁盘信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static List<DiskInfo> GetDiskInfos()
|
||||||
|
{
|
||||||
|
List<DiskInfo> diskInfos = new();
|
||||||
|
|
||||||
|
if (IsUnix())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string output = ShellHelper.Bash("df -m / | awk '{print $2,$3,$4,$5,$6}'");
|
||||||
|
var arr = output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (arr.Length == 0) return diskInfos;
|
||||||
|
|
||||||
|
var rootDisk = arr[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (rootDisk == null || rootDisk.Length == 0)
|
||||||
|
{
|
||||||
|
return diskInfos;
|
||||||
|
}
|
||||||
|
DiskInfo diskInfo = new()
|
||||||
|
{
|
||||||
|
DiskName = "/",
|
||||||
|
TotalSize = long.Parse(rootDisk[0]) / 1024,
|
||||||
|
Used = long.Parse(rootDisk[1]) / 1024,
|
||||||
|
AvailableFreeSpace = long.Parse(rootDisk[2]) / 1024,
|
||||||
|
AvailablePercent = decimal.Parse(rootDisk[3].Replace("%", ""))
|
||||||
|
};
|
||||||
|
diskInfos.Add(diskInfo);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("获取磁盘信息出错了" + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var driv = DriveInfo.GetDrives();
|
||||||
|
foreach (var item in driv)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var obj = new DiskInfo()
|
||||||
|
{
|
||||||
|
DiskName = item.Name,
|
||||||
|
TypeName = item.DriveType.ToString(),
|
||||||
|
TotalSize = item.TotalSize / 1024 / 1024 / 1024,
|
||||||
|
AvailableFreeSpace = item.AvailableFreeSpace / 1024 / 1024 / 1024,
|
||||||
|
};
|
||||||
|
obj.Used = obj.TotalSize - obj.AvailableFreeSpace;
|
||||||
|
obj.AvailablePercent = decimal.Ceiling(obj.Used / (decimal)obj.TotalSize * 100);
|
||||||
|
diskInfos.Add(obj);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("获取磁盘信息出错了" + ex.Message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return diskInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsUnix()
|
||||||
|
{
|
||||||
|
var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||||
|
return isUnix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetCPURate()
|
||||||
|
{
|
||||||
|
string cpuRate;
|
||||||
|
if (IsUnix())
|
||||||
|
{
|
||||||
|
string output = ShellHelper.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'");
|
||||||
|
cpuRate = output.Trim();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string output = ShellHelper.Cmd("wmic", "cpu get LoadPercentage");
|
||||||
|
cpuRate = output.Replace("LoadPercentage", string.Empty).Trim();
|
||||||
|
}
|
||||||
|
return cpuRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取系统运行时间
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetRunTime()
|
||||||
|
{
|
||||||
|
string runTime = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (IsUnix())
|
||||||
|
{
|
||||||
|
string output = ShellHelper.Bash("uptime -s").Trim();
|
||||||
|
runTime = DateTimeHelper.FormatTime(ParseToLong((DateTime.Now - ParseToDateTime(output)).TotalMilliseconds.ToString().Split('.')[0]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string output = ShellHelper.Cmd("wmic", "OS get LastBootUpTime/Value");
|
||||||
|
string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (outputArr.Length == 2)
|
||||||
|
{
|
||||||
|
runTime = DateTimeHelper.FormatTime(ParseToLong((DateTime.Now - ParseToDateTime( outputArr[1].Split('.')[0])).TotalMilliseconds.ToString().Split('.')[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("获取runTime出错" + ex.Message);
|
||||||
|
}
|
||||||
|
return runTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static CPUInfo GetCPUDetails()
|
||||||
|
{
|
||||||
|
int logicalProcessors = 0;
|
||||||
|
int cores = 0;
|
||||||
|
|
||||||
|
if (IsUnix())
|
||||||
|
{
|
||||||
|
string logicalOutput = ShellHelper.Bash("lscpu | grep '^CPU(s):' | awk '{print $2}'");
|
||||||
|
logicalProcessors = int.Parse(logicalOutput.Trim());
|
||||||
|
|
||||||
|
string coresOutput = ShellHelper.Bash("lscpu | grep 'Core(s) per socket:' | awk '{print $4}'");
|
||||||
|
string socketsOutput = ShellHelper.Bash("lscpu | grep 'Socket(s):' | awk '{print $2}'");
|
||||||
|
cores = int.Parse(coresOutput.Trim()) * int.Parse(socketsOutput.Trim());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string output = ShellHelper.Cmd("wmic", "cpu get NumberOfCores,NumberOfLogicalProcessors /format:csv");
|
||||||
|
var lines = output.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
if (lines.Length > 1)
|
||||||
|
{
|
||||||
|
var values = lines[1].Split(',');
|
||||||
|
|
||||||
|
cores = int.Parse(values[1].Trim());
|
||||||
|
logicalProcessors =int.Parse(values[2].Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CPUInfo
|
||||||
|
{
|
||||||
|
LogicalProcessors = logicalProcessors,
|
||||||
|
Cores = cores
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class CPUInfo
|
||||||
|
{
|
||||||
|
public int LogicalProcessors { get; set; }
|
||||||
|
public int Cores { get; set; }
|
||||||
|
}
|
||||||
|
public class CPUMetrics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内核数
|
||||||
|
/// </summary>
|
||||||
|
public int CoreTotal { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 逻辑处理器数
|
||||||
|
/// </summary>
|
||||||
|
public int LogicalProcessors { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// CPU使用率%
|
||||||
|
/// </summary>
|
||||||
|
public double CPURate { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// CPU空闲率%
|
||||||
|
/// </summary>
|
||||||
|
public double FreeRate { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 内存信息
|
||||||
|
/// </summary>
|
||||||
|
public class MemoryMetrics
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public double Total { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public double Used { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public double Free { get; set; }
|
||||||
|
|
||||||
|
public string UsedRam { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 总内存 GB
|
||||||
|
/// </summary>
|
||||||
|
public string TotalRAM { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 内存使用率 %
|
||||||
|
/// </summary>
|
||||||
|
public string RAMRate { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 空闲内存
|
||||||
|
/// </summary>
|
||||||
|
public string FreeRam { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DiskInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 磁盘名
|
||||||
|
/// </summary>
|
||||||
|
public string DiskName { get; set; }
|
||||||
|
public string TypeName { get; set; }
|
||||||
|
public long TotalFree { get; set; }
|
||||||
|
public long TotalSize { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 已使用
|
||||||
|
/// </summary>
|
||||||
|
public long Used { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 可使用
|
||||||
|
/// </summary>
|
||||||
|
public long AvailableFreeSpace { get; set; }
|
||||||
|
public decimal AvailablePercent { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MemoryMetricsClient
|
||||||
|
{
|
||||||
|
#region 获取内存信息
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// windows系统获取内存信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MemoryMetrics GetWindowsMetrics()
|
||||||
|
{
|
||||||
|
string output = ShellHelper.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value");
|
||||||
|
var metrics = new MemoryMetrics();
|
||||||
|
var lines = output.Trim().Split('\n', (char)StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
if (lines.Length <= 0) return metrics;
|
||||||
|
|
||||||
|
var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
|
||||||
|
metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);//m
|
||||||
|
metrics.Used = metrics.Total - metrics.Free;
|
||||||
|
|
||||||
|
return metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unix系统获取
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MemoryMetrics GetUnixMetrics()
|
||||||
|
{
|
||||||
|
string output = ShellHelper.Bash(@"
|
||||||
|
# 从 /proc/meminfo 文件中提取总内存
|
||||||
|
total_mem=$(cat /proc/meminfo | grep -i ""MemTotal"" | awk '{print $2}')
|
||||||
|
# 从 /proc/meminfo 文件中提取剩余内存
|
||||||
|
free_mem=$(cat /proc/meminfo | grep -i ""MemFree"" | awk '{print $2}')
|
||||||
|
# 显示提取的信息
|
||||||
|
echo $total_mem $used_mem $free_mem
|
||||||
|
");
|
||||||
|
var metrics = new MemoryMetrics();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(output))
|
||||||
|
{
|
||||||
|
var memory = output.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (memory.Length >= 2)
|
||||||
|
{
|
||||||
|
metrics.Total = Math.Round(double.Parse(memory[0]) / 1024, 0);
|
||||||
|
|
||||||
|
metrics.Free = Math.Round(double.Parse(memory[1])/ 1024, 0);//m
|
||||||
|
metrics.Used = metrics.Total - metrics.Free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metrics;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class ConsoleHelper
|
public static class ConsoleHelper
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class DateHelper
|
public class DateHelper
|
||||||
{
|
{
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class DateTimeHelper
|
public class DateTimeHelper
|
||||||
{
|
{
|
||||||
@@ -5,7 +5,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class Compare<T, C> : IEqualityComparer<T>
|
public class Compare<T, C> : IEqualityComparer<T>
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class EnumHelper
|
public static class EnumHelper
|
||||||
{
|
{
|
||||||
@@ -5,7 +5,7 @@ using System.Linq.Expressions;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class ExpressionHelper
|
public static class ExpressionHelper
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class FileHelper : IDisposable
|
public class FileHelper : IDisposable
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class HtmlHelper
|
public static class HtmlHelper
|
||||||
{
|
{
|
||||||
@@ -10,7 +10,7 @@ using System.Text.Json;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class HttpHelper
|
public static class HttpHelper
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class IdHelper
|
public static class IdHelper
|
||||||
{
|
{
|
||||||
@@ -3,7 +3,7 @@ using System.Net;
|
|||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class IpHelper
|
public class IpHelper
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class JsonHelper
|
public class JsonHelper
|
||||||
{
|
{
|
||||||
@@ -37,7 +34,6 @@ namespace Yi.Framework.Infrastructure.Helper
|
|||||||
string result = string.Empty;
|
string result = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
System.Text.Json.JsonSerializer.Serialize("");
|
|
||||||
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer =
|
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer =
|
||||||
new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
|
new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
|
||||||
using (MemoryStream ms = new MemoryStream())
|
using (MemoryStream ms = new MemoryStream())
|
||||||
@@ -454,7 +450,7 @@ namespace Yi.Framework.Infrastructure.Helper
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//示例 ["aa",{"bbbb":123,"fff","ddd"}]
|
//示例 ["aa",{"bbbb":123,"fff","Ddd"}]
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
|
case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
|
||||||
@@ -3,7 +3,7 @@ using System.IO;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class MD5Helper
|
public class MD5Helper
|
||||||
{
|
{
|
||||||
@@ -4,9 +4,9 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Yi.Framework.Infrastructure.Enums;
|
using Yi.Framework.Core.Enums;
|
||||||
|
|
||||||
namespace Yi.Framework.Infrastructure.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class MimeHelper
|
public static class MimeHelper
|
||||||
{
|
{
|
||||||
@@ -45,8 +45,8 @@ namespace Yi.Framework.Infrastructure.Helper
|
|||||||
{
|
{
|
||||||
var extension = Path.GetExtension(fileName);
|
var extension = Path.GetExtension(fileName);
|
||||||
if (ImageType.Contains(extension.ToLower()))
|
if (ImageType.Contains(extension.ToLower()))
|
||||||
return FileTypeEnum.Image;
|
return FileTypeEnum.image;
|
||||||
return FileTypeEnum.File;
|
return FileTypeEnum.file;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user