mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-03-03 00:00:58 +08:00
Compare commits
2147 Commits
v1.0.4
...
invitation
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e4f520dac | ||
|
|
067b25b9af | ||
|
|
36370c215d | ||
|
|
e24731acfe | ||
|
|
927e9df7de | ||
|
|
114b41144e | ||
|
|
5019a36138 | ||
|
|
e15eb6149b | ||
|
|
9d401a9c93 | ||
|
|
eacf86e118 | ||
|
|
c4b631c815 | ||
|
|
fb25e75a3a | ||
|
|
e9099bbe04 | ||
|
|
f02fb91175 | ||
|
|
efd917d184 | ||
|
|
e906208f4a | ||
|
|
e6b991fe86 | ||
|
|
dd3f6325bb | ||
|
|
c6425ca206 | ||
|
|
acb359ec33 | ||
|
|
a1395d9a33 | ||
|
|
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 | ||
|
|
fa3ac91ba4 | ||
|
|
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 | ||
|
|
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 | ||
|
|
23cecb9360 | ||
|
|
7e4c835ced | ||
|
|
aff460f555 | ||
|
|
52961b459e | ||
|
|
0af2f867fc | ||
|
|
85e291e0b8 | ||
|
|
6d8a859b20 | ||
|
|
a70dfb0769 | ||
|
|
c637d412e6 | ||
|
|
e996bc2d7f | ||
|
|
15be047371 | ||
|
|
0a0e0bca10 | ||
|
|
9a8f3bd161 | ||
|
|
7e2c035692 | ||
|
|
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 | ||
|
|
098d4bc85f | ||
|
|
26f7d67c50 | ||
|
|
42d2525b46 | ||
|
|
d9305c7620 | ||
|
|
185d87c24e | ||
|
|
a4080490bd | ||
|
|
714bcbdbb1 | ||
|
|
9158a38496 | ||
|
|
1f1f7f167f | ||
|
|
9453cc1c3b | ||
|
|
33a03d8119 | ||
|
|
2292fd1df6 | ||
|
|
18ac428a95 | ||
|
|
f0d0c304d6 | ||
|
|
7f041c96fb | ||
|
|
53ca11f85b | ||
|
|
a9f2a0c2ac | ||
|
|
181e2b21bb | ||
|
|
04bc6b4cb8 | ||
|
|
6058a1741b | ||
|
|
455f11af34 | ||
|
|
0b8848d63f | ||
|
|
1b7d6d09a8 | ||
|
|
c9592446c8 | ||
|
|
f2d2055f72 | ||
|
|
21ce0789ef | ||
|
|
794a8fc6aa | ||
|
|
408ef4a7df | ||
|
|
ab9b357c9b | ||
|
|
68d072cd60 | ||
|
|
aae1d37505 | ||
|
|
e927f2ff78 | ||
|
|
c271f3005a | ||
|
|
ca5697fb9c | ||
|
|
9150101498 | ||
|
|
6d0e6d0d16 | ||
|
|
c4236937b7 | ||
|
|
c1c0774572 | ||
|
|
fcb0ea9574 | ||
|
|
f095fde5a7 | ||
|
|
8bc2db1e6e | ||
|
|
7cbc15ea85 | ||
|
|
c2a9c670c4 | ||
|
|
4e5bdf6847 | ||
|
|
0aa6443a20 | ||
|
|
04278f553e | ||
|
|
349a041d71 | ||
|
|
58bf5062bf | ||
|
|
878f24ecae | ||
|
|
a15a374fb0 | ||
|
|
8a90f9d089 | ||
|
|
3007267951 | ||
|
|
710bb97cd3 | ||
|
|
18eb3a7fbf | ||
|
|
1d499b7052 | ||
|
|
36b28d83ed | ||
|
|
04fc03ccf5 | ||
|
|
ffb5898ea1 | ||
|
|
2c2eb0cb8d | ||
|
|
15dd8a60d7 | ||
|
|
65a0a6fb92 | ||
|
|
a0b35f4233 | ||
|
|
a271bc25c6 | ||
|
|
c988ed7988 | ||
|
|
c2ca0b1f29 | ||
|
|
efee87e4c5 | ||
|
|
98a990d9ea | ||
|
|
3a61df42ea | ||
|
|
d62baa0e51 | ||
|
|
dfe8806344 | ||
|
|
f1e95b960a | ||
|
|
7d0fa7f5d1 | ||
|
|
174f247a8e | ||
|
|
9cc41e8558 | ||
|
|
1fe8b9c5c9 | ||
|
|
496861587d | ||
|
|
93764fc5b5 | ||
|
|
22fab8dee0 | ||
|
|
dcbd729944 | ||
|
|
327a7b2a48 | ||
|
|
ad6bd8f39b | ||
|
|
95a91a10b3 | ||
|
|
b50f2b4c7e | ||
|
|
a1e0dac85c | ||
|
|
027f6dd538 | ||
|
|
94f902f788 | ||
|
|
bc5aaff9c9 | ||
|
|
770e8d7310 | ||
|
|
6a881e4613 | ||
|
|
0f36672783 | ||
|
|
7d5a7e0fe8 | ||
|
|
6977e233bb | ||
|
|
dbcb27e41a | ||
|
|
4b5b4464f4 | ||
|
|
4b6241e0b0 | ||
|
|
17fb60c481 | ||
|
|
51575b9f2d | ||
|
|
c943c1fc74 | ||
|
|
b55a45baa2 | ||
|
|
ae5db16d67 | ||
|
|
8f143be4b0 | ||
|
|
9ebafff392 | ||
|
|
e904c3df69 | ||
|
|
8ed1c958af | ||
|
|
a93e65df0a | ||
|
|
2fd861025a | ||
|
|
654c7d650a | ||
|
|
cb75196455 | ||
|
|
dd2b584c3d | ||
|
|
85d1cbff34 | ||
|
|
92d9c532c2 | ||
|
|
24bc61396e | ||
|
|
1655870d4d | ||
|
|
9b1a978cb5 | ||
|
|
fb27fb8aa4 | ||
|
|
a612af4f68 | ||
|
|
eb8e076732 | ||
|
|
0401e97ed3 | ||
|
|
c4f25b7a41 | ||
|
|
ef5b628b31 | ||
|
|
543c13d94b | ||
|
|
b9dad93c9d | ||
|
|
18696ec542 | ||
|
|
5efdffcda8 | ||
|
|
ccd39474c7 | ||
|
|
386ec5ade0 | ||
|
|
ee6b3b535c | ||
|
|
d5ee57f04d | ||
|
|
b6c70bad45 | ||
|
|
921d35367b | ||
|
|
253bd47c75 | ||
|
|
8fa10cd8c1 | ||
|
|
01e5b52500 | ||
|
|
9c921adc5b | ||
|
|
b90962943a | ||
|
|
ad4fc6ea9b | ||
|
|
62310ab863 | ||
|
|
ef7b8cd98f | ||
|
|
5e128ebf04 | ||
|
|
b324d98125 | ||
|
|
8329728b81 | ||
|
|
ba220e9d55 | ||
|
|
6b2ef71296 | ||
|
|
bcf7802f94 | ||
|
|
769e2cb897 | ||
|
|
d55caf2278 | ||
|
|
69ca6677e9 | ||
|
|
3d94626ff1 | ||
|
|
5458819ef5 | ||
|
|
2ff8aef1bf | ||
|
|
16556ddb84 | ||
|
|
aef6fe9229 | ||
|
|
e5460ae3cc | ||
|
|
b6f4cbfb4f | ||
|
|
c83fcb7f26 | ||
|
|
ab0d126c49 | ||
|
|
fd3142bc19 | ||
|
|
af80d8e89b | ||
|
|
c98eefe3ec | ||
|
|
84ec0a7e1c | ||
|
|
4babe3e05d | ||
|
|
8213f6f8d7 | ||
|
|
30329ea4db | ||
|
|
4b856c4905 | ||
|
|
418f4a4785 | ||
|
|
2d31aeecd1 | ||
|
|
b3b3ca3fe4 | ||
|
|
5a4ac549f6 | ||
|
|
f4cdeb3dc5 | ||
|
|
7b01d4722f | ||
|
|
019c73ceca | ||
|
|
10fef4e2d9 | ||
|
|
c613b185da | ||
|
|
1bb7ce6805 | ||
|
|
9b3d8b5a06 | ||
|
|
5f603e6652 | ||
|
|
a20bd6933b | ||
|
|
13ea3ae9b3 | ||
|
|
a73920f4c3 | ||
|
|
543d54f844 | ||
|
|
4bd374e747 | ||
|
|
295cf5e066 | ||
|
|
2824e1325d | ||
|
|
cd9e27bcf3 | ||
|
|
9600e450af | ||
|
|
8e56667760 | ||
|
|
1eac218910 | ||
|
|
27962cd25f | ||
|
|
3de32945f2 | ||
|
|
9593b68d33 | ||
|
|
9166fc50aa | ||
|
|
fb5342594f | ||
|
|
733ff867e9 | ||
|
|
d3f9b43b12 | ||
|
|
30ab479315 | ||
|
|
9d3559cddb | ||
|
|
6d3edff5b6 | ||
|
|
619471369d | ||
|
|
2d328234a1 | ||
|
|
06acfe1ee3 | ||
|
|
a55cba4c1f | ||
|
|
61f8a07753 | ||
|
|
e0da9e1a87 | ||
|
|
3ba3ea6317 | ||
|
|
834e40d6f2 | ||
|
|
f93cccd849 | ||
|
|
0127b43374 | ||
|
|
5cea38e95c | ||
|
|
964b8aa5f6 | ||
|
|
33616de6c8 | ||
|
|
6bf490f7da | ||
|
|
3e31f7783f | ||
|
|
05f5122c0b | ||
|
|
93de208ac0 | ||
|
|
272466bbbf | ||
|
|
8639372513 | ||
|
|
49acf0c7c9 | ||
|
|
232cbad5bd | ||
|
|
aa2f9d4f50 | ||
|
|
99aa7d3361 | ||
|
|
72decd970a | ||
|
|
fa4e0b3752 | ||
|
|
6615229003 | ||
|
|
24300e6e50 | ||
|
|
f8445ab2e4 | ||
|
|
9645decf59 | ||
|
|
f34c33b0d8 | ||
|
|
5cd20b1e22 | ||
|
|
d65c565127 | ||
|
|
2f654a1772 | ||
|
|
380f728de2 | ||
|
|
dffdaa8d68 | ||
|
|
1f33204697 | ||
|
|
0566606bfb | ||
|
|
e6f95d0cd8 | ||
|
|
8eda2cd814 | ||
|
|
961634981a | ||
|
|
50aadb574d | ||
|
|
a114457c6f | ||
|
|
9274d88c76 | ||
|
|
97bf39f031 | ||
|
|
158cab9f9b | ||
|
|
bc42efe703 | ||
|
|
e2e1d2ad78 | ||
|
|
772f2695e7 | ||
|
|
5df1144cd0 | ||
|
|
943a7344f6 | ||
|
|
5867559502 | ||
|
|
fdd1eda9ec | ||
|
|
1d7c17e253 | ||
|
|
95484877a3 | ||
|
|
b01d242cbc | ||
|
|
cfd25b0a8d | ||
|
|
2f08c07c20 | ||
|
|
fd5e02c1f4 | ||
|
|
a549edb174 | ||
|
|
1c8f20440c | ||
|
|
5fb09c1c4a | ||
|
|
b7260ed982 | ||
|
|
aec0150a26 | ||
|
|
5c5dfcac89 | ||
|
|
32b9611eb5 | ||
|
|
12881db9ef | ||
|
|
bb8508abbd | ||
|
|
d6565bd2d9 | ||
|
|
b4633efcba | ||
|
|
0a003359ea | ||
|
|
c7e74774de | ||
|
|
dfefd0452d | ||
|
|
38d69c9e6f | ||
|
|
ac26df6827 | ||
|
|
99787950a8 | ||
|
|
80723496d0 | ||
|
|
ec440f13b1 | ||
|
|
8a9c7e54e2 | ||
|
|
67ca25cec4 | ||
|
|
4ca7b2e023 | ||
|
|
aea8b55e82 | ||
|
|
55a4b0ad1b | ||
|
|
f4124db320 | ||
|
|
e23e5a292d | ||
|
|
1f702c20ae | ||
|
|
9b1b915925 | ||
|
|
11bfefcd04 | ||
|
|
fceefac0ee | ||
|
|
98375f8629 | ||
|
|
d4e0cf7e18 | ||
|
|
62af066234 | ||
|
|
00d368080b | ||
|
|
e43b0d1522 | ||
|
|
400b14cd75 | ||
|
|
f88655e214 | ||
|
|
fc74a000a6 | ||
|
|
eb1a86e5b2 | ||
|
|
2fa3570f85 | ||
|
|
da2cf2acc5 | ||
|
|
f68ffefaa9 | ||
|
|
617fbdf8f7 | ||
|
|
034abb06ad | ||
|
|
46b176fc59 | ||
|
|
506686b11e | ||
|
|
1314cf1c19 | ||
|
|
f1e314fa13 | ||
|
|
3bce7de015 | ||
|
|
1bd035e1ca | ||
|
|
3a9ad5adb8 | ||
|
|
022d5bbd7d | ||
|
|
c905489ea5 | ||
|
|
65377d9236 | ||
|
|
8ead6c59c0 | ||
|
|
ea4e8856c2 | ||
|
|
318cfb5fe2 | ||
|
|
7706126479 | ||
|
|
ba84d0ead3 | ||
|
|
5604c6ece5 | ||
|
|
140f2970c4 | ||
|
|
b2ac98d25e | ||
|
|
1ed37897d5 | ||
|
|
29df3d658b | ||
|
|
576397a042 | ||
|
|
b7c9b84449 | ||
|
|
efbf799218 | ||
|
|
7d578ce363 | ||
|
|
e03e584684 | ||
|
|
e8e6b928cf | ||
|
|
5f6d29a3f8 | ||
|
|
a27d83a5e3 | ||
|
|
ef1154d6f3 | ||
|
|
ae2400fd0b | ||
|
|
fbcd004b7e | ||
|
|
cb307f95ce | ||
|
|
7838cd1a6a | ||
|
|
03dcb7d860 | ||
|
|
62c5470efe | ||
|
|
53b4674da4 | ||
|
|
ff2cf68b08 | ||
|
|
8b55373794 | ||
|
|
dba67d7127 | ||
|
|
762c455b53 | ||
|
|
714d1a36c4 | ||
|
|
0e0ddbbd99 | ||
|
|
497f8cfd1f | ||
|
|
1ff709e6f8 | ||
|
|
ea35871aba | ||
|
|
0e78857645 | ||
|
|
5d7d115910 | ||
|
|
b9384afd5d | ||
|
|
dbe020dc94 | ||
|
|
9673aa7690 | ||
|
|
ec06d30d59 | ||
|
|
356d2e592b | ||
|
|
521c2e7ca6 | ||
|
|
c4014c9333 | ||
|
|
2908a8d8a9 | ||
|
|
c964b98240 | ||
|
|
f7c74b5c96 | ||
|
|
d34c9818b4 | ||
|
|
6414c93116 | ||
|
|
5a12c4a3ce | ||
|
|
97a6ee39e5 | ||
|
|
44db5ab150 | ||
|
|
e9bcd29e36 | ||
|
|
a2ca897fca | ||
|
|
9a34e63d5f | ||
|
|
e501b894c3 | ||
|
|
d97ef84b7e | ||
|
|
0f2dc4d3ba | ||
|
|
49a9eb5460 | ||
|
|
7e7780a754 | ||
|
|
d0770970f0 | ||
|
|
d5a10a5817 | ||
|
|
7b63d8b2ba | ||
|
|
c544de8909 | ||
|
|
89da2ab50f | ||
|
|
a1a6b5967b | ||
|
|
53ffb1b565 | ||
|
|
6efecd123f | ||
|
|
1ec5349a96 | ||
|
|
187abcd10c | ||
|
|
d6ca4429d5 | ||
|
|
86e869ff16 | ||
|
|
dc58f9397f | ||
|
|
97b4ab2f15 | ||
|
|
23a9d02aba | ||
|
|
32ed6c3e97 | ||
|
|
102556dd2a | ||
|
|
2df3f7c56d | ||
|
|
d6fd02ec19 | ||
|
|
c901b4bc06 | ||
|
|
e19c89ccd9 | ||
|
|
a667f1a65e | ||
|
|
9f5829876c | ||
|
|
189d7c4719 | ||
|
|
dfe877c438 | ||
|
|
3a634d7888 | ||
|
|
fd9f3d04d9 | ||
|
|
ac70fc37f6 | ||
|
|
c29aeeee41 | ||
|
|
51c13c7b52 | ||
|
|
fec8c0fe53 | ||
|
|
5da2143212 | ||
|
|
30158ac145 | ||
|
|
ff7eecee55 | ||
|
|
0755a4026a | ||
|
|
9aaf363584 | ||
|
|
0a27cd7403 | ||
|
|
ab8cdd88b9 | ||
|
|
dab4a092d9 | ||
|
|
9d365dbf1e | ||
|
|
16d25fb60d | ||
|
|
50d43a2fc5 | ||
|
|
6d99539730 | ||
|
|
cf43dc8e70 | ||
|
|
95c506c638 | ||
|
|
464b768c55 | ||
|
|
00ca4cc5bd | ||
|
|
bfb81ef60d | ||
|
|
420701bf23 | ||
|
|
88073aaa20 | ||
|
|
8456320884 | ||
|
|
3555b08fe8 | ||
|
|
55ad046e96 | ||
|
|
ea4ddb68f3 | ||
|
|
edde5f8a88 | ||
|
|
de28fd4ca4 | ||
|
|
dd7bbb138a | ||
|
|
4a54eb56a7 | ||
|
|
24cda70cbc | ||
|
|
a0c869d0a1 | ||
|
|
58f85992b0 | ||
|
|
f11f5e1ca4 | ||
|
|
0672698ba7 | ||
|
|
cf37f7c950 | ||
|
|
c7d64554ad | ||
|
|
039021532e | ||
|
|
e39ae170c3 | ||
|
|
8a44fe9d1c | ||
|
|
70649653fb | ||
|
|
db1f241c33 | ||
|
|
c9ed317e62 | ||
|
|
afde26a7ae | ||
|
|
1a2d9ba2b2 | ||
|
|
3943536485 | ||
|
|
e963a4051f | ||
|
|
2b02194a18 | ||
|
|
dd1aec3b60 | ||
|
|
0b05d4d186 | ||
|
|
8f0327604f | ||
|
|
40dddb3316 | ||
|
|
be7ea64c5a | ||
|
|
8eef0e410e | ||
|
|
63f0b20fd6 | ||
|
|
87a685b823 | ||
|
|
4796a494de | ||
|
|
a329ff3796 | ||
|
|
00ab65e720 | ||
|
|
4997e25cdc | ||
|
|
6ce05984d5 | ||
|
|
26e08774b0 | ||
|
|
83ce9fb4c4 | ||
|
|
ac946f4903 | ||
|
|
d6480db609 | ||
|
|
9f9c191240 | ||
|
|
cb781aa4ad | ||
|
|
6a31e88855 | ||
|
|
f862e5ea1b | ||
|
|
b8de3e9867 | ||
|
|
1959160681 | ||
|
|
b665ec5717 | ||
|
|
8ef2c12be1 | ||
|
|
d85e7f0bcb | ||
|
|
544d65c7d0 | ||
|
|
1bd5fc389a | ||
|
|
9149d6de9a | ||
|
|
261d9fcd79 | ||
|
|
5ecac4223d | ||
|
|
215c21ad8a | ||
|
|
5772de888c | ||
|
|
55979e90dc | ||
|
|
5785f5beea | ||
|
|
e8bb256a8d | ||
|
|
729a563545 | ||
|
|
1b38ed5c78 | ||
|
|
483aea5c4f | ||
|
|
a64d493a29 | ||
|
|
2a8d436267 | ||
|
|
7905f82d65 | ||
|
|
dcf82d041a | ||
|
|
9618bd891f | ||
|
|
c63f9de5c5 | ||
|
|
0e6113f0a6 | ||
|
|
71cf85f535 | ||
|
|
2a4f646181 | ||
|
|
0cc326836c | ||
|
|
52b8bc8909 | ||
|
|
844a7b455c | ||
|
|
489a0b6fb8 | ||
|
|
e535133eca | ||
|
|
ea2be7609c | ||
|
|
011d9d639b | ||
|
|
e78e9d8e55 | ||
|
|
89762cad78 | ||
|
|
4788562241 | ||
|
|
5b1ad450d3 | ||
|
|
7b6d8671cf | ||
|
|
01631860f4 | ||
|
|
c65e76bbc3 | ||
|
|
ef35e1cfd9 | ||
|
|
1d535b5d61 | ||
|
|
004cb20132 | ||
|
|
909bdf60e7 | ||
|
|
0cd3bea6bd | ||
|
|
d001a0de15 | ||
|
|
0dca7acee6 | ||
|
|
b5ad7a1721 | ||
|
|
9f23b911c1 | ||
|
|
1db8bb4d13 | ||
|
|
eebafda9e5 | ||
|
|
0fb57a0a2c | ||
|
|
d4c55620f1 | ||
|
|
ef26567850 | ||
|
|
c15c43dba4 | ||
|
|
5d738d99fe | ||
|
|
43120b0017 | ||
|
|
23dc82f042 | ||
|
|
49330536c7 | ||
|
|
781fa7ea1b | ||
|
|
bf17312a5f | ||
|
|
e4da8d4f15 | ||
|
|
cc26bd09e6 | ||
|
|
9dc1c5c9e9 | ||
|
|
442ae94ad5 | ||
|
|
43820f71a3 | ||
|
|
63920e034a | ||
|
|
cddc47305f | ||
|
|
583bebd10c | ||
|
|
7fe9a6c900 | ||
|
|
670e457dc6 | ||
|
|
300d8224ec | ||
|
|
924f5320bb | ||
|
|
dd09fb2283 | ||
|
|
3e18af626b | ||
|
|
89dd5b79d6 | ||
|
|
356f71f13e | ||
|
|
2f5d71a299 | ||
|
|
b581c12edb | ||
|
|
d4d6aeb0b4 | ||
|
|
77114e6cfc | ||
|
|
e14a078440 | ||
|
|
3b38a0d628 | ||
|
|
927d8cb6c9 | ||
|
|
eb8ea2f549 | ||
|
|
208c93bc8f | ||
|
|
93180faa23 | ||
|
|
816858f231 | ||
|
|
fa1d68848f | ||
|
|
bce955a1e1 | ||
|
|
82f70e0ac9 | ||
|
|
fc9b78cfef | ||
|
|
72400a48da | ||
|
|
537b39b3c4 | ||
|
|
47e6e48729 | ||
|
|
d252229777 | ||
|
|
7f4c7f607d | ||
|
|
994ba5dd1a | ||
|
|
e3a06b28dd | ||
|
|
10d512470e | ||
|
|
c1d8040fd5 | ||
|
|
e4b81da386 | ||
|
|
fd7360e6f4 | ||
|
|
62f15e218e | ||
|
|
5c1b91f348 | ||
|
|
378cbd580f | ||
|
|
3994f14010 | ||
|
|
e7f4e743e3 | ||
|
|
b934ce2893 | ||
|
|
5eec076ea2 | ||
|
|
ada36ebff5 | ||
|
|
d9543ca23c | ||
|
|
3871eb3c84 | ||
|
|
4ba696d289 | ||
|
|
2f69e0b96c | ||
|
|
d6b0c56c35 | ||
|
|
d8fe983b9d | ||
|
|
76079faca0 | ||
|
|
5d5c62123c | ||
|
|
6c7b2224b1 | ||
|
|
4d80ae2372 | ||
|
|
c651b60c59 | ||
|
|
90b39d075d | ||
|
|
5099c7e462 | ||
|
|
2f8b5dd229 | ||
|
|
7e427605ab | ||
|
|
512e640c13 | ||
|
|
acb1c6cc99 | ||
|
|
d01c3ff9ca | ||
|
|
3720644153 | ||
|
|
630cfb6769 | ||
|
|
f3061ed643 | ||
|
|
2556c037ba | ||
|
|
0b4626a5a2 | ||
|
|
1c9e993194 | ||
|
|
dc3a465f09 | ||
|
|
6d008efd54 | ||
|
|
6aa970c375 | ||
|
|
1ecd01204b | ||
|
|
33bd8d1cd1 | ||
|
|
31d2c3c98e | ||
|
|
b082ec19aa | ||
|
|
9ccb496069 |
9
.claude/settings.local.json
Normal file
9
.claude/settings.local.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"WebFetch(domain:www.donet5.com)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
63
.gitattributes
vendored
63
.gitattributes
vendored
@@ -1,63 +0,0 @@
|
|||||||
###############################################################################
|
|
||||||
# Set default behavior to automatically normalize line endings.
|
|
||||||
###############################################################################
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set default behavior for command prompt diff.
|
|
||||||
#
|
|
||||||
# This is need for earlier builds of msysgit that does not have it on by
|
|
||||||
# default for csharp files.
|
|
||||||
# Note: This is only used by command line
|
|
||||||
###############################################################################
|
|
||||||
#*.cs diff=csharp
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set the merge driver for project and solution files
|
|
||||||
#
|
|
||||||
# Merging from the command prompt will add diff markers to the files if there
|
|
||||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
|
||||||
# the diff markers are never inserted). Diff markers may cause the following
|
|
||||||
# file extensions to fail to load in VS. An alternative would be to treat
|
|
||||||
# these files as binary and thus will always conflict and require user
|
|
||||||
# intervention with every merge. To do so, just uncomment the entries below
|
|
||||||
###############################################################################
|
|
||||||
#*.sln merge=binary
|
|
||||||
#*.csproj merge=binary
|
|
||||||
#*.vbproj merge=binary
|
|
||||||
#*.vcxproj merge=binary
|
|
||||||
#*.vcproj merge=binary
|
|
||||||
#*.dbproj merge=binary
|
|
||||||
#*.fsproj merge=binary
|
|
||||||
#*.lsproj merge=binary
|
|
||||||
#*.wixproj merge=binary
|
|
||||||
#*.modelproj merge=binary
|
|
||||||
#*.sqlproj merge=binary
|
|
||||||
#*.wwaproj merge=binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# behavior for image files
|
|
||||||
#
|
|
||||||
# image files are treated as binary by default.
|
|
||||||
###############################################################################
|
|
||||||
#*.jpg binary
|
|
||||||
#*.png binary
|
|
||||||
#*.gif binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# diff behavior for common document formats
|
|
||||||
#
|
|
||||||
# Convert binary document formats to text before diffing them. This feature
|
|
||||||
# is only available from the command line. Turn it on by uncommenting the
|
|
||||||
# entries below.
|
|
||||||
###############################################################################
|
|
||||||
#*.doc diff=astextplain
|
|
||||||
#*.DOC diff=astextplain
|
|
||||||
#*.docx diff=astextplain
|
|
||||||
#*.DOCX diff=astextplain
|
|
||||||
#*.dot diff=astextplain
|
|
||||||
#*.DOT diff=astextplain
|
|
||||||
#*.pdf diff=astextplain
|
|
||||||
#*.PDF diff=astextplain
|
|
||||||
#*.rtf diff=astextplain
|
|
||||||
#*.RTF diff=astextplain
|
|
||||||
143
.gitignore
vendored
143
.gitignore
vendored
@@ -1,20 +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
|
|
||||||
WebFirst/SoEasyPlatform.exe
|
|
||||||
WebFirst/excel
|
|
||||||
WebFirst/wwwroot
|
|
||||||
WebFirst/SoEasyPlatform.exe
|
|
||||||
WebFirst/appsettings.Development.json
|
|
||||||
WebFirst/appsettings.json
|
|
||||||
WebFirst/SoEasyPlatform.pdb
|
|
||||||
WebFirst/SoEasyPlatform.Views.pdb
|
|
||||||
WebFirst/web.config
|
|
||||||
WebFirst/WebFirst.exe
|
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
@@ -30,21 +17,16 @@ WebFirst/WebFirst.exe
|
|||||||
[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.*
|
||||||
@@ -58,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
|
||||||
@@ -89,7 +61,6 @@ StyleCopReport.xml
|
|||||||
*.tlh
|
*.tlh
|
||||||
*.tmp
|
*.tmp
|
||||||
*.tmp_proj
|
*.tmp_proj
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
*.log
|
||||||
*.vspscc
|
*.vspscc
|
||||||
*.vssscc
|
*.vssscc
|
||||||
@@ -118,9 +89,6 @@ ipch/
|
|||||||
*.vspx
|
*.vspx
|
||||||
*.sap
|
*.sap
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
# TFS 2012 Local Workspace
|
||||||
$tf/
|
$tf/
|
||||||
|
|
||||||
@@ -141,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
|
||||||
@@ -180,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
|
||||||
@@ -193,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
|
||||||
|
|
||||||
@@ -215,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/
|
||||||
@@ -229,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/
|
||||||
@@ -252,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/
|
||||||
@@ -275,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
|
||||||
@@ -283,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
|
||||||
@@ -305,48 +251,29 @@ 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
|
||||||
|
.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
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|||||||
214
LICENSE
214
LICENSE
@@ -1,201 +1,21 @@
|
|||||||
Apache License
|
MIT License
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
Copyright (c) 2023 橙子
|
||||||
|
|
||||||
1. Definitions.
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
The above copyright notice and this permission notice shall be included in all
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
the copyright owner that is granting the License.
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
other entities that control, are controlled by, or are under common
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
control with that entity. For the purposes of this definition,
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
SOFTWARE.
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|||||||
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)
|
||||||
361
README.md
361
README.md
@@ -1,220 +1,279 @@
|
|||||||
|
<h1 align="center"><img align="left" height="150px" src="https://ccnetcore.com/prod-api/wwwroot/logo.png"> Yi框架</h1>
|
||||||
|
<h4 align="center">一套以用户体验出发的.Net8 Web开源框架</h4>
|
||||||
<h1 align="center"><img align="left" height="100px" src="https://user-images.githubusercontent.com/68722157/138828506-f58b7c57-5e10-4178-8f7d-5d5e12050113.png"> Yi框架</h1>
|
<h5 align="center">支持Abp.vNext 版本原生版本、Furion版本,前端接入Ruoyi/Pure Vue</h5>
|
||||||
<h4 align="center">一套与SqlSugar一样爽的.Net6低代码开源框架</h4>
|
|
||||||
<h2 align="center">集大成者,终究轮子</h2>
|
<h2 align="center">集大成者,终究轮子</h2>
|
||||||
|
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
[](https://gitee.com/ccnetcore/Yi)
|
||||||
|
|
||||||
[English](README-en.md) | 简体中文
|
[English](README-en.md) | 简体中文
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
****
|
****
|
||||||
### 简介:
|
## 🍍 简介:
|
||||||
**中文:意框架**(和他的名字一样“简易”)
|
YiFramework是一个基于.Net8+Abp.vNext+SqlSugar的DDD领域驱动设计后端开源框架
|
||||||
|
|
||||||
|
谁说Abp复杂?谁说DDD难?`打破常规,化繁为简`,新人入门,项目二开,最佳方式之一
|
||||||
|
|
||||||
|
**中文:意框架**(和他的名字一样“简易”,同时接入Java的Ruoyi Vue3.0前端)
|
||||||
|
|
||||||
|
模块化,可根据业务自行引用或抛弃,集大成者,大而全乎,也许你能从中学习到一些独特见解
|
||||||
|
|
||||||
**英文:YiFramework**
|
**英文:YiFramework**
|
||||||
|
|
||||||
Yi框架-一套与SqlSugar一样爽的.Net6低代码开源框架。
|
Yi框架-一套与SqlSugar一样爽的.Net8开源框架。
|
||||||
与Sqlsugar理念一致,以用户体验出发。
|
与Sqlsugar理念一致,以用户体验出发。
|
||||||
架构干净整洁、无业务代码、采用微软风格原生框架封装、WebFrist开发。
|
全生态拥抱AI,接入AI,100%代码经过AI洗礼
|
||||||
适合.Net6学习、Sqlsugar学习 、项目二次开发。
|
|
||||||
集大成者,终究轮子
|
集大成者,终究轮子
|
||||||
|
|
||||||
Yi框架最新版本标签:`v1.0.3`
|
(更新频繁,可watching持续关注。)
|
||||||
|
|
||||||
(项目与Sqlsugar同步更新,但这作者老杰哥代码天天爆肝到凌晨两点,我们也尽量会跟上他的脚步。更新频繁,所以可watching持续关注。)
|
|
||||||
|
|
||||||
————这不仅仅是一个程序,更是一个艺术品,面向艺术的开发!
|
————这不仅仅是一个程序,更是一个艺术品,面向艺术的开发!
|
||||||
|
|
||||||
**分支**:
|
> 核心特点:简单好用,框架不以打包形式引用,而是直接以项目附带源码给出,自由度拉满,遵循Mit协议,允许随意修改(请注明来源即可)
|
||||||
|
|
||||||
(本项目由EFCore版本历经3年不断迭代至Sqlsugar版本,现EFcore版本已弃用,目前sqlsugar不带任何业务,之后会更新业务功能)
|
**分支目录:**
|
||||||
|
|
||||||
**SqlSugar**:.Net6 DDD领域驱动设计 简单分层微服务架构
|
- 分支**Abp**: 基于Abp.vNext分支,DDD领域驱动设计,回归开发本质,极度简单,一个后台支持以下多个前端
|
||||||
|
|
||||||
**ec**:EFcore完整电商项目
|
- Yi.Abp.Net8:后端
|
||||||
|
- Yi.Bbs.Vue3:Bbs社区 前端
|
||||||
|
- Yi.Doc.Md: 开源文档教程
|
||||||
|
- Yi.Pure.Vue3:Pure ts后台前端
|
||||||
|
- Yi.RuoYi.Vue3:RuoYi js后台前端
|
||||||
|
|
||||||
|
****
|
||||||
|
## 🍉 docker 一键启动
|
||||||
|
|
||||||
|
完整内容在:README-Docker.md
|
||||||
|
|
||||||
|
后端:`docker run -d --name yi.admin -p 19001:19001 jiftcc/yi.admin:last`
|
||||||
|
|
||||||
|
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操作,我们更希望你能通过此种方式二开构建属于自己的镜像
|
||||||
|
|
||||||
****
|
****
|
||||||
|
|
||||||
### 演示地址:
|
## 🍊 官网及演示地址:
|
||||||
|
|
||||||
废话少说直接上地址,**请不要**更改里面的数据
|
废话少说直接上地址
|
||||||
|
|
||||||
API服务:~~[yi.ccnetcore.com](http://yi.ccnetcore.com) 管理员账号:admin 、 123~~
|
Yi社区官网网址(Bbs社区正式):[ccnetcore.com](https://ccnetcore.com) (已上线,欢迎加入)
|
||||||
|
|
||||||
网关地址:~~[gate.ccnetcore.com/swagger](http://gate.ccnetcore.com/swagger)~~
|
Rbac后台演示地址:https://ccnetcore.com:1000 (用户cc、密码123456)
|
||||||
|
|
||||||
WebFirst开发:所有代码生成器已经配置完成,无需任何操作数据库及任何代码,只需要网页表格上点点点即可
|
Pure后台演示地址:https://ccnetcore.com:1001 (用户cc、密码123456)
|
||||||
|
|
||||||
[https://www.donet5.com/Doc/11](https://www.donet5.com/Doc/11)
|
## 🍏 支持:
|
||||||
|
|
||||||
谁能把持的住Sqlsugar作者自己都依赖成瘾的东西呢?这是继DbFirst、CodeFirst下一代的划时代产品!无脑爽!
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
(首次添加实体后,生成代码记得修改对应的路径哦~~)
|
|
||||||
|
|
||||||
### 支持:
|
|
||||||
|
|
||||||
- [x] 完全支持单体应用架构
|
- [x] 完全支持单体应用架构
|
||||||
- [x] 完全支持分布式应用架构
|
- [x] 完全支持分布式应用架构
|
||||||
- [x] 完全支持微服务架构
|
- [x] 完全支持微服务架构
|
||||||
- [ ] 即将支持网格服务架构(我们将在后续版本加入dapr)
|
|
||||||
|
|
||||||
****
|
****
|
||||||
### 软件架构:
|
|
||||||
|
|
||||||
**架构**:后端.NET6(Asp.NetCore 6)、WebFirst代码生成器~~与.NET5(Asp.NetCore 5)、前端Vue(2.0)~~
|
## 🍇 详细到爆炸的Yi框架教程导航:
|
||||||
|
|
||||||
**关系型数据库**:mysql、sql server、sqlite、oracle(正在兼容中)
|
0. [社区导航大全](https://ccnetcore.com/article/aaa00329-7f35-d3fe-d258-3a0f8380b742/fb8c871b-41fc-21bc-474f-3a154498f42b)
|
||||||
|
|
||||||
**操作系统**:Windows、Linux
|
1. [框架快速开始教程](https://ccnetcore.com/article/aaa00329-7f35-d3fe-d258-3a0f8380b742)(已完成)
|
||||||
|
2. [框架功能模块教程](https://ccnetcore.com/article/8c464ab3-8ba5-2761-a4b0-3a0f83a9f312)(已完成)
|
||||||
**身份验证**:JWT、IdentityServer4
|
3. [实战演练开发教程](https://ccnetcore.com/article/e89c9593-f337-ada7-d108-3a0f83ae48e6)(已完成)
|
||||||
|
4. [橙子运维CICD教程](https://ccnetcore.com/article/6b80ed42-50cd-db15-c073-3a0fa8f7fd77)(已完成)
|
||||||
**组件**:~~EFcore~~SqlSugar、Autofac、Castle、Swagger、Log4Net、Redis、RabbitMq、ES、Quartz.net、~~T4~~
|
5. [版本更新日志](https://ccnetcore.com/article/e9e69a38-ce1e-06f5-7944-3a0fdc942ef3)(已完成)
|
||||||
|
|
||||||
**分布式**:CAP、Lock
|
|
||||||
|
|
||||||
**微服务**:Consul、Ocelot、IdentityService、Apollo、Docker、Jenkins、Nginx、K8s、ELK、Polly
|
|
||||||
|
|
||||||
**封装**:Json处理模块,滑动验证码模块,base64图片处理模块,异常捕捉模块、邮件处理模块、linq封装模块、随机数模块、统一接口模块、基于策略的jwt验证、过滤器、数据库连接、跨域、初始化种子数据、Base32、Console输出、日期处理、文件传输、html筛选、http请求、ip过滤、md5加密、Rsa加密、序列化、雪花算法、字符串处理、编码处理、地址处理、xml处理、心跳检查。。。
|
|
||||||
|
|
||||||
****
|
****
|
||||||
### 支持模块:
|
## 🍓 它的理念:
|
||||||
|
谁说Abp复杂?谁说DDD难?打破常规,化繁为简,新人入门,项目二开,最佳方式之一
|
||||||
|
|
||||||
大致如图:
|
> 一百个人,就有一百种DDD,Yi框架不一定是极度严格的DDD,而是站在巨人的肩膀上,经过极多项目的提炼,摸索出一种最佳实践
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
(删除线代表已实现功能还未迁移过来)
|
优雅的进行快速开发,通常,简单程度与优雅程度不可兼得,Yi框架并不一昧的追求极致的解耦,会站在用户使用角度上,在使用难易度进行考虑衡量
|
||||||
- [x] 支持大致`DDD领域驱动设计`进行分层,支持微服务扩展
|
|
||||||
- [x] 支持采用`异步`开发awit/async
|
> 一个面向用户的快速开发后端框架
|
||||||
- [x] 支持数据库主从`读写分离`
|
|
||||||
- [x] 支持功能替换,无需改动代码,只需配置`json文件`进行装配即可
|
在真正的使用过,你会明白这一点,极致的简单,也是优雅的一种体现。
|
||||||
- [x] ~~-支持采用DbFirst开发方式,使用`T4模板代码生成器`,自动映射模型一键生成Service及IService所有代码~~
|
****
|
||||||
- [x] 支持WebFirst,无需改动代码,自动生成全套代码与数据库,只需点点点
|
|
||||||
- [x] ~~-支持`用户-角色-菜单-接口`以及vue2.0前端全部逻辑代码,下载无需修改直接使用~~
|
## 🍍 特点
|
||||||
- [x] 支持`Aop封装`,FilterAop、IocAop、LogAop、SqlAop
|
- 面向用户的后端框架,使用简单,适合小型、中型、企业级项目
|
||||||
- [x] 支持`Log4Net日志`记录,自动生成至bin目录下的logs文件夹
|
- 项目直接内置源码,不打包,非常适合进行二开改造
|
||||||
- [x] 支持`DbSeed数据库种子数据`接入
|
- 内置包含大量通用场景模块
|
||||||
- [x] 支持主流`数据库随意切换`,Mysql/Sqlite/Sqlserver/Oracle
|
- 优雅支持分布式及微服务架构
|
||||||
- [x] 支持上海杰哥官方`SqlSugar ORM`封装
|
- 等等
|
||||||
- [x] 支持新版`SwaggerWebAPI`,jwt身份认证接入
|
|
||||||
- [x] 支持`Cors`跨域
|
## 🍍 基础设施简介
|
||||||
- [x] 支持`AutoFac`自动映射依赖注入
|
|
||||||
- [x] 支持`consul`服务器注册与发现
|
以下全部功能可直接使用:
|
||||||
- [x] 支持`健康检查`
|
|
||||||
- [x] 支持`RabbitMQ`消息队列
|
- [Abp.vNext官网](https://docs.abp.io/zh-Hans/abp/latest/)
|
||||||
- [x] 支持`Redis`多级缓存
|
|
||||||
- [x] 支持`Ocelot`网关,路由、服务聚合、服务发现、认证、鉴权、限流、熔断、缓存、Header头传递
|
- [SqlSugar官网](https://www.donet5.com/home/doc)
|
||||||
- [x] 支持`Apollo`全局配置中心;
|
|
||||||
- [x] 支持`docker`镜像制作
|
## 🍅 内置模块简介
|
||||||
- [x] ~~-支持页面`静态化处理`,将动态页面生成静态页面~~
|
- Rbac权限管理系统(已上线)(支持pure、ruoyi前端)
|
||||||
- [x] 支持`Quartz.net`任务调度,实现任意接口被调度
|
- Bbs论坛社区系统(已上线)
|
||||||
- [x] 支持`ELK`,log4net+kafka+es+logstach+kibana
|
|
||||||
- [x] 支持`IdentityService4`授权中心
|
> 重复的东西,无需再写一遍,这也是优雅的体现之一
|
||||||
- [x] 支持`Es`分词查询
|
|
||||||
- [x] 支持多级`缓存`
|
|
||||||
- [x] 支持`CAP`分布式事务,mysql+rabbitMq
|
|
||||||
- [x] 支持`Docker+k8s`部署
|
|
||||||
- [x] 支持`Jenkins+CI/CD`
|
|
||||||
- [x] 支持`AutoMapper`模块映射
|
|
||||||
- [ ] 支持`微信支付`(没账号)
|
|
||||||
- [x] 支持`单表多租户`常用功能
|
|
||||||
- [x] 支持`逻辑删除`常用功能
|
|
||||||
- [x] 支持`操作日志`常用功能
|
|
||||||
- [x] 支持`自动分表`
|
|
||||||
- [x] 支持 太多了忘了
|
|
||||||
|
|
||||||
****
|
****
|
||||||
### 目录结构:
|
## 🥭 核心技术
|
||||||
|
#### 后端
|
||||||
|
C# Asp.NetCore 8.0
|
||||||
|
- [x] 动态Api:Abp.vNext
|
||||||
|
- [x] 鉴权授权:Jwt
|
||||||
|
- [x] 日志:Serilog
|
||||||
|
- [x] 模块化:Abp.vNext
|
||||||
|
- [x] 依赖注入:Autofac
|
||||||
|
- [x] 对象映射:Mapster
|
||||||
|
- [x] ORM: SqlsugarCore
|
||||||
|
- [x] 多租户:Abp.vNext
|
||||||
|
- [x] 后台任务:Quartz.Net
|
||||||
|
- [x] 本地缓存:Abp.vNext
|
||||||
|
- [x] 分布式缓存:Abp.vNext
|
||||||
|
- [x] 事件总线:Abp.vNext
|
||||||
|
|
||||||

|
#### 前端
|
||||||
|
js Vue3
|
||||||
|
- [x] 异步请求:axios
|
||||||
|
- [x] 图表:echarts
|
||||||
|
- [x] ui:element-plus
|
||||||
|
- [x] 存储:pinia
|
||||||
|
- [x] 路由:vue-router
|
||||||
|
- [x] 打包:vite
|
||||||
|
|
||||||
我们大致依照DDD领域驱动设计分层
|
#### 运维
|
||||||
|
- [x] 部署:nginx
|
||||||
|
- [x] CICD:gitlab+Jenkins
|
||||||
|
- [x] Docker:harbor
|
||||||
|
|
||||||
什么?感觉太复杂了?用户只需关注Api、Service其他都是轮子啊!
|
|
||||||
|
|
||||||
~~- BackGround:后台进程(目前可以无视,等待更新)~~
|
|
||||||
- Client:客户端(测试、客户端)
|
|
||||||
- Domain:领域层(Dto、服务接口层、模型层、仓储层、服务层)
|
|
||||||
- Infrastructure:基础实例层(通用工具层、核心层、定时任务Job、国际化、Web扩展层)
|
|
||||||
- MicroServiceInstance:服务层(微服务)
|
|
||||||
|
|
||||||
****
|
****
|
||||||
### 安装教程:
|
## 🍌 业务支持模块:
|
||||||
|
|
||||||
我们将在之后更新教程手册!
|
#### 🍒 RABC权限管理系统(持续更新)
|
||||||
|
(采用ruoyi前端)
|
||||||
|
- 用户管理
|
||||||
|
- 角色管理
|
||||||
|
- 菜单管理
|
||||||
|
- 部门管理
|
||||||
|
- 岗位管理
|
||||||
|
- 字典管理
|
||||||
|
- 参数管理
|
||||||
|
- 用户在线
|
||||||
|
- 操作日志
|
||||||
|
- 登录日志
|
||||||
|
- 定时任务
|
||||||
|
- 缓存列表
|
||||||
|
- 服务监控
|
||||||
|
|
||||||
1. 下载全部源码,默认使用sqlite数据库,已经生成
|
#### 🍐 BBS社区论坛系统(持续更新)
|
||||||
2. 直接点击sln文件运行即可,没有其他依赖
|
(采用vue3前端)
|
||||||
|
- 文章功能
|
||||||
|
- 板块功能
|
||||||
|
- 主题功能
|
||||||
|
- 个人中心
|
||||||
|
- 授权中心
|
||||||
|
- 权限管理
|
||||||
|
|
||||||
****
|
#### 🍉 演示截图:
|
||||||
### 使用说明:
|
<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>
|
||||||
|
|
||||||
1. 导入使用仓库中的WebFirst数据库
|
<table>
|
||||||
2. 使用WebFirst添加实体、同步实体、修改模板生成路径并生成方案
|
<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>
|
||||||
|
|
||||||
**爽点**:
|
## 🌶 感谢:
|
||||||
|
|
||||||
新人,看这里,项目下载之后直接可以启动,无任何依赖,之后你可以查看`Test控制器`,迫不及待的快来爽一爽!
|
|
||||||
|
|
||||||
我们将使用说明转移至我们的官方论坛中,正在制作中,尽情期待!
|
|
||||||
|
|
||||||
****
|
|
||||||
### 感谢:
|
|
||||||
|
|
||||||
**大力支持**: 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
|
||||||
|
|
||||||
[RuYiAdmin]https://gitee.com/pang-mingjun/RuYiAdmin
|
[车神]微信公众号搜索Dotnet技术进阶
|
||||||
|
|
||||||
[ZrAdminNetCore]https://gitee.com/izory/ZrAdminNetCore
|
[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/
|
||||||
|
|
||||||
****
|
****
|
||||||
### 联系我们:
|
## 🌽 联系我们:
|
||||||
|
|
||||||
作者QQ:454313500
|
作者QQ:`454313500`,2029年之前作者24小时在线,时刻保持活跃更新。
|
||||||
|
|
||||||
|
QQ交流群:官方一群(已满)、官方二群(已满)、官方三群:`786308927`(已满)、官方四群:`498310311`(已满)、官方五群:`981136525`
|
||||||
|
|
||||||
|
微信交流群:官方微信一群(已满)、官方微信二群(已满)、官方微信三群
|
||||||
|
|
||||||
|
微信交流群:加作者微信 chengzilaoge520 (橙子老哥520),备注拉群
|
||||||
|
|
||||||
联系作者,这里人人都是顾问
|
联系作者,这里人人都是顾问
|
||||||
|
|
||||||
官方网址:正在建设
|
官方网址留言区:[ccnetcore.com](https://ccnetcore.com)
|
||||||
|
|
||||||
****
|
****
|
||||||
### FQA:
|
## 🍄 FQA:
|
||||||
|
|
||||||
问1:为什么不采用EFcore?
|
前往官网查看留言区
|
||||||
|
|
||||||
答1:别问,问就是Sqlsugar,和本框架一样爽!
|
[留言区](https://ccnetcore.com/discuss/1641030787056930818)
|
||||||
|
|
||||||
问2:以后会持续更新下去吗?
|
|
||||||
|
|
||||||
答2:一定会的,我们的标题是 一个和Sqlsugar一样爽的.Net6开源框架 ,只要Sqlsugar在,我们将一直更新下去。
|
|
||||||
|
|
||||||
问3:这个框架的针对人群是哪些人?适合所有人吗?
|
|
||||||
|
|
||||||
答3:并不是适合所有人,应该算适合需要有一定基础的开发人员,当然,如果你是大神,你完全可以将这个框架二次开发!
|
|
||||||
|
|
||||||
问4:花如此多的精力制作这个框架,是为了什么?是为了赚钱吗?和目前主流的abp等框架比,又有什么意义呢?
|
|
||||||
|
|
||||||
答4:我们与Sqlsugar作者理念一致,我们是从用户角度出发,框架是为用户服务,与ABP复杂上手理念完全是相反的。
|
|
||||||
|
|
||||||
问5:为何不出版一个详细的说明书呢?
|
|
||||||
|
|
||||||
答5:暂时不会了,之后可能会,代码都是基于Asp.NetCore框架,适用于新手不用造轮子,整个框架较为简单,阅读源码后,基本能自定义改造使用了,过难也已经封装完毕,别忘了,其意义是为了开发更加简易!建议添加作者好友,这里人人都是顾问。
|
|
||||||
|
|
||||||
我大抵要厌倦了负重前行。
|
|
||||||
Binary file not shown.
10
Yi.Abp.Net8/.claude/settings.local.json
Normal file
10
Yi.Abp.Net8/.claude/settings.local.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"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/**)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,4 +22,12 @@
|
|||||||
**/secrets.dev.yaml
|
**/secrets.dev.yaml
|
||||||
**/values.dev.yaml
|
**/values.dev.yaml
|
||||||
LICENSE
|
LICENSE
|
||||||
README.md
|
README.md
|
||||||
|
!**/.gitignore
|
||||||
|
!.git/HEAD
|
||||||
|
!.git/config
|
||||||
|
!.git/packed-refs
|
||||||
|
!.git/refs/heads/**
|
||||||
|
appsettings.Development.json
|
||||||
|
appsettings.Production.json
|
||||||
|
appsettings.Staging.json
|
||||||
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,7 @@
|
|||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft": "Warning",
|
"Microsoft.AspNetCore": "Warning"
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"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");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
39
Yi.Abp.Net8/common.props
Normal file
39
Yi.Abp.Net8/common.props
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<Project>
|
||||||
|
<Import Project="usings.props" />
|
||||||
|
<Import Project="version.props" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<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,106 @@
|
|||||||
|
// 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 Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
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);
|
||||||
|
|
||||||
|
IUnifyResultProvider unifyResult = context.GetRequiredService<IUnifyResultProvider>();
|
||||||
|
// 执行规范化异常处理
|
||||||
|
context.Result = unifyResult.OnException(context, exceptionMetadata);
|
||||||
|
|
||||||
|
// 创建日志记录器
|
||||||
|
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<FriendlyExceptionFilter>>();
|
||||||
|
|
||||||
|
// 记录拦截日常
|
||||||
|
logger.LogError(context.Exception, context.Exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 UserFriendlyException friendlyException)
|
||||||
|
{
|
||||||
|
int statusCode2 = 500;
|
||||||
|
int.TryParse(friendlyException.Code, out statusCode2);
|
||||||
|
isFriendlyException = true;
|
||||||
|
errorCode = friendlyException.Code;
|
||||||
|
originErrorCode = friendlyException.Code;
|
||||||
|
statusCode = statusCode2==0?403:statusCode2;
|
||||||
|
isValidationException = false;
|
||||||
|
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,29 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
|
||||||
|
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.AddService<SucceededUnifyResultFilter>(99);
|
||||||
|
options.Filters.AddService<FriendlyExceptionFilter>(100);
|
||||||
|
options.Filters.RemoveAll(x => (x as ServiceFilterAttribute)?.ServiceType == typeof(AbpExceptionFilter));
|
||||||
|
});
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Helper
|
||||||
|
{
|
||||||
|
public static class AssemblyHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 此处统一获取程序集,排除微软内部相关
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Assembly[] GetAllLoadAssembly()
|
||||||
|
{
|
||||||
|
return AppDomain.CurrentDomain.GetAssemblies();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Assembly> GetReferanceAssemblies(this AppDomain domain)
|
||||||
|
{
|
||||||
|
var list = new List<Assembly>();
|
||||||
|
domain.GetAssemblies().ToList().ForEach(i =>
|
||||||
|
{
|
||||||
|
GetReferanceAssemblies(i, list);
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
private static void GetReferanceAssemblies(Assembly assembly, List<Assembly> list)
|
||||||
|
{
|
||||||
|
assembly.GetReferencedAssemblies().ToList().ForEach(i =>
|
||||||
|
{
|
||||||
|
var ass = Assembly.Load(i);
|
||||||
|
if (!list.Contains(ass))
|
||||||
|
{
|
||||||
|
list.Add(ass);
|
||||||
|
GetReferanceAssemblies(ass, list);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Type> GetClass(string assemblyFile, string? className = null, string? spaceName = null)
|
||||||
|
{
|
||||||
|
Assembly assembly = Assembly.Load(assemblyFile);
|
||||||
|
return assembly.GetTypes().Where(m => m.IsClass
|
||||||
|
&& className == null ? true : m.Name == className
|
||||||
|
&& spaceName == null ? true : m.Namespace == spaceName
|
||||||
|
&& !m.Name.StartsWith("<>")
|
||||||
|
).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Type> GetClassByParentClass(string assemblyFile, Type type)
|
||||||
|
{
|
||||||
|
Assembly assembly = Assembly.Load(assemblyFile);
|
||||||
|
|
||||||
|
List<Type> resList = new List<Type>();
|
||||||
|
|
||||||
|
List<Type> typeList = assembly.GetTypes().Where(m => m.IsClass).ToList();
|
||||||
|
foreach (var t in typeList)
|
||||||
|
{
|
||||||
|
var data = t.BaseType;
|
||||||
|
if (data == type)
|
||||||
|
{
|
||||||
|
resList.Add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return resList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static List<Type> GetClassByInterfaces(string assemblyFile, Type type)
|
||||||
|
{
|
||||||
|
Assembly assembly = Assembly.Load(assemblyFile);
|
||||||
|
|
||||||
|
List<Type> resList = new List<Type>();
|
||||||
|
|
||||||
|
List<Type> typeList = assembly.GetTypes().Where(m => m.IsClass).ToList();
|
||||||
|
foreach (var t in typeList)
|
||||||
|
{
|
||||||
|
var data = t.GetInterfaces();
|
||||||
|
if (data.Contains(type))
|
||||||
|
{
|
||||||
|
resList.Add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return resList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Yi.Framework.Common.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public sealed class Base32Helper
|
public sealed class Base32Helper
|
||||||
{
|
{
|
||||||
@@ -26,12 +26,12 @@ namespace Yi.Framework.Common.Helper
|
|||||||
{
|
{
|
||||||
// get the last piece from the current byte, shift it to the right
|
// get the last piece from the current byte, shift it to the right
|
||||||
// and increment the byte counter
|
// and increment the byte counter
|
||||||
index = (byte)(bytes[currentByte++] >> (hi - 5));
|
index = (byte)(bytes[currentByte++] >> hi - 5);
|
||||||
if (currentByte != bytes.Length)
|
if (currentByte != bytes.Length)
|
||||||
{
|
{
|
||||||
// if we are not at the end, get the first piece from
|
// if we are not at the end, get the first piece from
|
||||||
// the next byte, clear it and shift it to the left
|
// the next byte, clear it and shift it to the left
|
||||||
index = (byte)(((byte)(bytes[currentByte] << (16 - hi)) >> 3) | index);
|
index = (byte)((byte)(bytes[currentByte] << 16 - hi) >> 3 | index);
|
||||||
}
|
}
|
||||||
|
|
||||||
hi -= 3;
|
hi -= 3;
|
||||||
@@ -45,7 +45,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
{
|
{
|
||||||
|
|
||||||
// simply get the stuff from the current byte
|
// simply get the stuff from the current byte
|
||||||
index = (byte)((byte)(bytes[currentByte] << (8 - hi)) >> 3);
|
index = (byte)((byte)(bytes[currentByte] << 8 - hi) >> 3);
|
||||||
hi += 5;
|
hi += 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,13 +59,13 @@ namespace Yi.Framework.Common.Helper
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a Base32-k string into an array of bytes.
|
/// Converts a Base32-k string into an array of bytes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="System.ArgumentException">
|
/// <exception cref="ArgumentException">
|
||||||
/// Input string <paramref name="s">s</paramref> contains invalid Base32-k characters.
|
/// Input string <paramref name="s">s</paramref> contains invalid Base32-k characters.
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public static byte[] FromBase32String(string str)
|
public static byte[] FromBase32String(string str)
|
||||||
{
|
{
|
||||||
int numBytes = str.Length * 5 / 8;
|
int numBytes = str.Length * 5 / 8;
|
||||||
byte[] bytes = new Byte[numBytes];
|
byte[] bytes = new byte[numBytes];
|
||||||
|
|
||||||
// all UPPERCASE chars
|
// all UPPERCASE chars
|
||||||
str = str.ToUpper();
|
str = str.ToUpper();
|
||||||
@@ -80,7 +80,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_buffer = (ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5);
|
bit_buffer = ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5;
|
||||||
bits_in_buffer = 10;
|
bits_in_buffer = 10;
|
||||||
currentCharIndex = 2;
|
currentCharIndex = 2;
|
||||||
for (int i = 0; i < bytes.Length; i++)
|
for (int i = 0; i < bytes.Length; i++)
|
||||||
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.Common.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.Common.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class DateHelper
|
public class DateHelper
|
||||||
{
|
{
|
||||||
@@ -8,12 +8,12 @@ namespace Yi.Framework.Common.Helper
|
|||||||
{
|
{
|
||||||
time = time.Substring(0, 10);
|
time = time.Substring(0, 10);
|
||||||
double timestamp = Convert.ToInt64(time);
|
double timestamp = Convert.ToInt64(time);
|
||||||
System.DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
|
DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||||||
dateTime = dateTime.AddSeconds(timestamp).ToLocalTime();
|
dateTime = dateTime.AddSeconds(timestamp).ToLocalTime();
|
||||||
return dateTime;
|
return dateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string TimeSubTract(DateTime time1,DateTime time2)
|
public static string TimeSubTract(DateTime time1, DateTime time2)
|
||||||
{
|
{
|
||||||
TimeSpan subTract = time1.Subtract(time2);
|
TimeSpan subTract = time1.Subtract(time2);
|
||||||
return $"{subTract.Days} 天 {subTract.Hours} 时 {subTract.Minutes} 分 ";
|
return $"{subTract.Days} 天 {subTract.Hours} 时 {subTract.Minutes} 分 ";
|
||||||
139
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/DateTimeHelper.cs
Normal file
139
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/DateTimeHelper.cs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Helper
|
||||||
|
{
|
||||||
|
public class DateTimeHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateTime"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static DateTime GetBeginTime(DateTime? dateTime, int days = 0)
|
||||||
|
{
|
||||||
|
if (dateTime == DateTime.MinValue || dateTime == null)
|
||||||
|
{
|
||||||
|
return DateTime.Now.AddDays(days);
|
||||||
|
}
|
||||||
|
return dateTime ?? DateTime.Now;
|
||||||
|
}
|
||||||
|
#region 时间戳转换
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时间戳转本地时间-时间戳精确到秒
|
||||||
|
/// </summary>
|
||||||
|
public static DateTime ToLocalTimeDateBySeconds(long unix)
|
||||||
|
{
|
||||||
|
var dto = DateTimeOffset.FromUnixTimeSeconds(unix);
|
||||||
|
return dto.ToLocalTime().DateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时间转时间戳Unix-时间戳精确到秒
|
||||||
|
/// </summary>
|
||||||
|
public static long ToUnixTimestampBySeconds(DateTime dt)
|
||||||
|
{
|
||||||
|
DateTimeOffset dto = new DateTimeOffset(dt);
|
||||||
|
return dto.ToUnixTimeSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时间戳转本地时间-时间戳精确到毫秒
|
||||||
|
/// </summary>
|
||||||
|
public static DateTime ToLocalTimeDateByMilliseconds(long unix)
|
||||||
|
{
|
||||||
|
var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix);
|
||||||
|
return dto.ToLocalTime().DateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时间转时间戳Unix-时间戳精确到毫秒
|
||||||
|
/// </summary>
|
||||||
|
public static long ToUnixTimestampByMilliseconds(DateTime dt)
|
||||||
|
{
|
||||||
|
DateTimeOffset dto = new DateTimeOffset(dt);
|
||||||
|
return dto.ToUnixTimeMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 毫秒转天时分秒
|
||||||
|
/// <summary>
|
||||||
|
/// 毫秒转天时分秒
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ms"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string FormatTime(long ms)
|
||||||
|
{
|
||||||
|
int ss = 1000;
|
||||||
|
int mi = ss * 60;
|
||||||
|
int hh = mi * 60;
|
||||||
|
int dd = hh * 24;
|
||||||
|
|
||||||
|
long day = ms / dd;
|
||||||
|
long hour = (ms - day * dd) / hh;
|
||||||
|
long minute = (ms - day * dd - hour * hh) / mi;
|
||||||
|
long second = (ms - day * dd - hour * hh - minute * mi) / ss;
|
||||||
|
long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
|
||||||
|
|
||||||
|
string sDay = day < 10 ? "0" + day : "" + day; //天
|
||||||
|
string sHour = hour < 10 ? "0" + hour : "" + hour;//小时
|
||||||
|
string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟
|
||||||
|
string sSecond = second < 10 ? "0" + second : "" + second;//秒
|
||||||
|
string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒
|
||||||
|
sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond;
|
||||||
|
|
||||||
|
return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 获取unix时间戳
|
||||||
|
/// <summary>
|
||||||
|
/// 获取unix时间戳
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static long GetUnixTimeStamp(DateTime dt)
|
||||||
|
{
|
||||||
|
long unixTime = ((DateTimeOffset)dt).ToUnixTimeMilliseconds();
|
||||||
|
return unixTime;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 获取日期天的最小时间
|
||||||
|
public static DateTime GetDayMinDate(DateTime dt)
|
||||||
|
{
|
||||||
|
DateTime min = new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0);
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 获取日期天的最大时间
|
||||||
|
public static DateTime GetDayMaxDate(DateTime dt)
|
||||||
|
{
|
||||||
|
DateTime max = new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59);
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 获取日期天的最大时间
|
||||||
|
public static string FormatDateTime(DateTime? dt)
|
||||||
|
{
|
||||||
|
if (dt != null)
|
||||||
|
{
|
||||||
|
if (dt.Value.Year == DateTime.Now.Year)
|
||||||
|
{
|
||||||
|
return dt.Value.ToString("MM-dd HH:mm");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return dt.Value.ToString("yyyy-MM-dd HH:mm");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Helper
|
||||||
|
{
|
||||||
|
public class Compare<T, C> : IEqualityComparer<T>
|
||||||
|
{
|
||||||
|
private Func<T, C> _getField;
|
||||||
|
public Compare(Func<T, C> getfield)
|
||||||
|
{
|
||||||
|
_getField = getfield;
|
||||||
|
}
|
||||||
|
public bool Equals(T? x, T? y)
|
||||||
|
{
|
||||||
|
return EqualityComparer<C>.Default.Equals(_getField(x!), _getField(y!));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(T obj)
|
||||||
|
{
|
||||||
|
return EqualityComparer<C>.Default.GetHashCode(_getField(obj)!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class DistinctHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义Distinct扩展方法
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">要去重的对象类</typeparam>
|
||||||
|
/// <typeparam name="C">自定义去重的字段类型</typeparam>
|
||||||
|
/// <param name="source">要去重的对象</param>
|
||||||
|
/// <param name="getfield">获取自定义去重字段的委托</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEnumerable<T> DistinctNew<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
|
||||||
|
{
|
||||||
|
return source.Distinct(new Compare<T, C>(getfield));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/EnumHelper.cs
Normal file
25
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/EnumHelper.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Helper
|
||||||
|
{
|
||||||
|
public static class EnumHelper
|
||||||
|
{
|
||||||
|
public static New EnumToEnum<New>(this object oldEnum)
|
||||||
|
{
|
||||||
|
if (oldEnum is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(oldEnum));
|
||||||
|
}
|
||||||
|
return (New)Enum.ToObject(typeof(New), oldEnum.GetHashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TEnum StringToEnum<TEnum>(this string str)
|
||||||
|
{
|
||||||
|
return (TEnum)Enum.Parse(typeof(TEnum), str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Helper
|
||||||
|
{
|
||||||
|
public static class ExpressionHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expression表达式树lambda参数拼接组合
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="first"></param>
|
||||||
|
/// <param name="second"></param>
|
||||||
|
/// <param name="merge"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
|
||||||
|
{
|
||||||
|
var parameterMap = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
|
||||||
|
var secondBody = LambdaParameteRebinder.ReplaceParameter(parameterMap, second.Body);
|
||||||
|
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expression表达式树lambda参数拼接--false
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Expression<Func<T, bool>> False<T>() => f => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expression表达式树lambda参数拼接-true
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Expression<Func<T, bool>> True<T>() => f => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expression表达式树lambda参数拼接--and
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="first"></param>
|
||||||
|
/// <param name="second"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) => first.Compose(second, Expression.And);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expression表达式树lambda参数拼接--or
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="first"></param>
|
||||||
|
/// <param name="second"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) => first.Compose(second, Expression.Or);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LambdaParameteRebinder : ExpressionVisitor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 存放表达式树的参数的字典
|
||||||
|
/// </summary>
|
||||||
|
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
public LambdaParameteRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
|
||||||
|
{
|
||||||
|
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重载参数访问的方法,访问表达式树参数,如果字典中包含,则取出
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">表达式树参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected override Expression VisitParameter(ParameterExpression node)
|
||||||
|
{
|
||||||
|
if (map.TryGetValue(node, out ParameterExpression expression))
|
||||||
|
{
|
||||||
|
node = expression;
|
||||||
|
}
|
||||||
|
return base.VisitParameter(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression ReplaceParameter(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
|
||||||
|
{
|
||||||
|
return new LambdaParameteRebinder(map).Visit(exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Yi.Framework.Common.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class FileHelper : IDisposable
|
public class FileHelper : IDisposable
|
||||||
{
|
{
|
||||||
|
|
||||||
private bool _alreadyDispose = false;
|
private bool _alreadyDispose = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 构造函数
|
#region 构造函数
|
||||||
public FileHelper()
|
public FileHelper()
|
||||||
{
|
{
|
||||||
@@ -125,7 +128,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
FileStream f = File.Create(Path);
|
FileStream f = File.Create(Path);
|
||||||
f.Close();
|
f.Close();
|
||||||
}
|
}
|
||||||
StreamWriter f2 = new StreamWriter(Path, false, System.Text.Encoding.GetEncoding("gb2312"));
|
StreamWriter f2 = new StreamWriter(Path, false, Encoding.GetEncoding("gb2312"));
|
||||||
f2.Write(Strings);
|
f2.Write(Strings);
|
||||||
f2.Close();
|
f2.Close();
|
||||||
f2.Dispose();
|
f2.Dispose();
|
||||||
@@ -172,7 +175,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
s = "不存在相应的目录";
|
s = "不存在相应的目录";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
StreamReader f2 = new StreamReader(Path, System.Text.Encoding.GetEncoding("gb2312"));
|
StreamReader f2 = new StreamReader(Path, Encoding.GetEncoding("gb2312"));
|
||||||
s = f2.ReadToEnd();
|
s = f2.ReadToEnd();
|
||||||
f2.Close();
|
f2.Close();
|
||||||
f2.Dispose();
|
f2.Dispose();
|
||||||
@@ -391,5 +394,97 @@ namespace Yi.Framework.Common.Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取目录下全部文件名
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path"></param>
|
||||||
|
/// <param name="pattern"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static List<string> GetAllFileNames(string path, string pattern = "*")
|
||||||
|
{
|
||||||
|
List<FileInfo> folder = new DirectoryInfo(path).GetFiles(pattern).ToList();
|
||||||
|
|
||||||
|
return folder.Select(x => x.Name).ToList();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 文件内容替换
|
||||||
|
/// </summary>
|
||||||
|
public static string FileContentReplace(string path, string oldStr, string newStr)
|
||||||
|
{
|
||||||
|
var content = File.ReadAllText(path);
|
||||||
|
|
||||||
|
if (content.Contains(oldStr))
|
||||||
|
{
|
||||||
|
File.Delete(path);
|
||||||
|
File.WriteAllText(path, content.Replace(oldStr, newStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 文件名称
|
||||||
|
/// </summary>
|
||||||
|
public static string FileNameReplace(string path, string oldStr, string newStr)
|
||||||
|
{
|
||||||
|
string fileName = Path.GetFileName(path);
|
||||||
|
if (!fileName.Contains(oldStr))
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
string? directoryName = Path.GetDirectoryName(path);
|
||||||
|
string newFileName = fileName.Replace(oldStr, newStr);
|
||||||
|
string newPath = Path.Combine(directoryName ?? "", newFileName);
|
||||||
|
File.Move(path, newPath);
|
||||||
|
|
||||||
|
return newPath;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 目录名替换
|
||||||
|
/// </summary>
|
||||||
|
public static string DirectoryNameReplace(string path, string oldStr, string newStr)
|
||||||
|
{
|
||||||
|
string fileName = Path.GetFileName(path);
|
||||||
|
if (!fileName.Contains(oldStr))
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
string? directoryName = Path.GetDirectoryName(path);
|
||||||
|
string newFileName = fileName.Replace(oldStr, newStr);
|
||||||
|
string newPath = Path.Combine(directoryName ?? "", newFileName);
|
||||||
|
Directory.Move(path, newPath);
|
||||||
|
return newPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 全部信息递归替换
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dirPath"></param>
|
||||||
|
/// <param name="oldStr"></param>
|
||||||
|
/// <param name="newStr"></param>
|
||||||
|
public static void AllInfoReplace(string dirPath, string oldStr, string newStr)
|
||||||
|
{
|
||||||
|
var path = DirectoryNameReplace(dirPath, oldStr, newStr);
|
||||||
|
var dirInfo = new DirectoryInfo(path);
|
||||||
|
var files = dirInfo.GetFiles();
|
||||||
|
var dirs = dirInfo.GetDirectories();
|
||||||
|
if (files.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (var f in files)
|
||||||
|
{
|
||||||
|
FileContentReplace(f.FullName, oldStr, newStr);
|
||||||
|
FileNameReplace(f.FullName, oldStr, newStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dirs.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (var d in dirs)
|
||||||
|
{
|
||||||
|
AllInfoReplace(d.FullName, oldStr, newStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Yi.Framework.Common.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public static class HtmlHelper
|
public static class HtmlHelper
|
||||||
{
|
{
|
||||||
122
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/HttpHelper.cs
Normal file
122
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/HttpHelper.cs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Mime;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Helper
|
||||||
|
{
|
||||||
|
public static class HttpHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
public static HttpClient Client { get; set; } = new HttpClient();
|
||||||
|
|
||||||
|
public static async Task<string> Get(string url)
|
||||||
|
{
|
||||||
|
return await Client.GetStringAsync(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Stream> GetIO(string url)
|
||||||
|
{
|
||||||
|
return await Client.GetStreamAsync(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async Task<string> Post(string url, object? item = null, Dictionary<string, string>? head = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
using StringContent json = new(JsonSerializer.Serialize(item), Encoding.UTF8, MediaTypeNames.Application.Json);
|
||||||
|
|
||||||
|
|
||||||
|
if (head is not null)
|
||||||
|
{
|
||||||
|
foreach (var d in head)
|
||||||
|
{
|
||||||
|
json.Headers.Add(d.Key, d.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpResponse = await Client.PostAsync(url, json);
|
||||||
|
|
||||||
|
httpResponse.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var content = httpResponse.Content;
|
||||||
|
|
||||||
|
return await content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public static string HttpGet(string Url, string postDataStr="")
|
||||||
|
// {
|
||||||
|
//#pragma warning disable SYSLIB0014 // 类型或成员已过时
|
||||||
|
// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr);
|
||||||
|
//#pragma warning restore SYSLIB0014 // 类型或成员已过时
|
||||||
|
// request.Method = "GET";
|
||||||
|
// request.ContentType = "text/html;charset=UTF-8";
|
||||||
|
|
||||||
|
// HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||||
|
// Stream myResponseStream = response.GetResponseStream();
|
||||||
|
// StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
|
||||||
|
// string retString = myStreamReader.ReadToEnd();
|
||||||
|
// myStreamReader.Close();
|
||||||
|
// myResponseStream.Close();
|
||||||
|
|
||||||
|
// return retString;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public static bool HttpIOGet(string Url, string file, string postDataStr="")
|
||||||
|
// {
|
||||||
|
// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr);
|
||||||
|
// request.Method = "GET";
|
||||||
|
// request.ContentType = "text/html;charset=UTF-8";
|
||||||
|
|
||||||
|
// HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||||
|
// Stream myResponseStream = response.GetResponseStream();
|
||||||
|
// FileStream writer = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write);
|
||||||
|
// byte[] buffer = new byte[1024];
|
||||||
|
// int c;
|
||||||
|
// while ((c = myResponseStream.Read(buffer, 0, buffer.Length)) > 0)
|
||||||
|
// {
|
||||||
|
// writer.Write(buffer, 0, c);
|
||||||
|
// }
|
||||||
|
// writer.Close();
|
||||||
|
// myResponseStream.Close();
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public static string HttpPost(string Url, string postDataStr="")
|
||||||
|
// {
|
||||||
|
// CookieContainer cookie = new CookieContainer();
|
||||||
|
//#pragma warning disable SYSLIB0014 // 类型或成员已过时
|
||||||
|
// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
|
||||||
|
//#pragma warning restore SYSLIB0014 // 类型或成员已过时
|
||||||
|
// request.Method = "POST";
|
||||||
|
// request.ContentType = "application/x-www-form-urlencoded";
|
||||||
|
// request.ContentLength = Encoding.UTF8.GetByteCount(postDataStr);
|
||||||
|
// request.CookieContainer = cookie;
|
||||||
|
|
||||||
|
// Stream myRequestStream = request.GetRequestStream();
|
||||||
|
// StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312"));
|
||||||
|
// myStreamWriter.Write(postDataStr);
|
||||||
|
// myStreamWriter.Close();
|
||||||
|
|
||||||
|
// HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||||
|
|
||||||
|
// response.Cookies = cookie.GetCookies(response.ResponseUri);
|
||||||
|
// Stream myResponseStream = response.GetResponseStream();
|
||||||
|
// StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
|
||||||
|
// string retString = myStreamReader.ReadToEnd();
|
||||||
|
// myStreamReader.Close();
|
||||||
|
// myResponseStream.Close();
|
||||||
|
|
||||||
|
// return retString;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/IdHelper.cs
Normal file
16
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/IdHelper.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Core.Helper
|
||||||
|
{
|
||||||
|
public static class IdHelper
|
||||||
|
{
|
||||||
|
public static dynamic[] ToDynamicArray(this IEnumerable<long> ids)
|
||||||
|
{
|
||||||
|
return ids.Select(id => (dynamic)id).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
||||||
namespace Yi.Framework.Common.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class IpHelper
|
public class IpHelper
|
||||||
{
|
{
|
||||||
@@ -24,6 +24,11 @@ namespace Yi.Framework.Common.Helper
|
|||||||
// 获取所有可用网卡IP信息
|
// 获取所有可用网卡IP信息
|
||||||
var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses);
|
var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses);
|
||||||
|
|
||||||
|
if (ipCollection is null)
|
||||||
|
{
|
||||||
|
return instanceIp;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var ipadd in ipCollection)
|
foreach (var ipadd in ipCollection)
|
||||||
{
|
{
|
||||||
if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork)
|
if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
@@ -1,21 +1,27 @@
|
|||||||
using System;
|
using Newtonsoft.Json;
|
||||||
using System.Collections.Generic;
|
using Newtonsoft.Json.Converters;
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace Yi.Framework.Common.Helper
|
namespace Yi.Framework.Core.Helper
|
||||||
{
|
{
|
||||||
public class JsonHelper
|
public class JsonHelper
|
||||||
{
|
{
|
||||||
|
public static string ObjToStr<T>(T obj, string dateTimeFormat)
|
||||||
|
{
|
||||||
|
IsoDateTimeConverter timeConverter = new IsoDateTimeConverter()
|
||||||
|
{
|
||||||
|
DateTimeFormat = dateTimeFormat
|
||||||
|
};
|
||||||
|
return JsonConvert.SerializeObject(obj, Formatting.Indented, timeConverter);
|
||||||
|
}
|
||||||
|
|
||||||
public static string ObjToStr<T>(T obj)
|
public static string ObjToStr<T>(T obj)
|
||||||
{
|
{
|
||||||
return Newtonsoft.Json.JsonConvert.SerializeObject(obj);
|
return JsonConvert.SerializeObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T StrToObj<T>(string str)
|
public static T StrToObj<T>(string str)
|
||||||
{
|
{
|
||||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(str);
|
return JsonConvert.DeserializeObject<T>(str)!;
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转换对象为JSON格式数据
|
/// 转换对象为JSON格式数据
|
||||||
@@ -25,13 +31,12 @@ namespace Yi.Framework.Common.Helper
|
|||||||
/// <returns>字符格式的JSON数据</returns>
|
/// <returns>字符格式的JSON数据</returns>
|
||||||
public static string GetJSON<T>(object obj)
|
public static string GetJSON<T>(object obj)
|
||||||
{
|
{
|
||||||
string result = String.Empty;
|
string result = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
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 (System.IO.MemoryStream ms = new System.IO.MemoryStream())
|
using (MemoryStream ms = new MemoryStream())
|
||||||
{
|
{
|
||||||
serializer.WriteObject(ms, obj);
|
serializer.WriteObject(ms, obj);
|
||||||
result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
|
result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
|
||||||
@@ -58,7 +63,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
|
|
||||||
foreach (T city in vals)
|
foreach (T city in vals)
|
||||||
{
|
{
|
||||||
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
|
using (MemoryStream ms = new MemoryStream())
|
||||||
{
|
{
|
||||||
s.WriteObject(ms, city);
|
s.WriteObject(ms, city);
|
||||||
st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray()));
|
st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray()));
|
||||||
@@ -80,12 +85,12 @@ namespace Yi.Framework.Common.Helper
|
|||||||
public static T ParseFormByJson<T>(string jsonStr)
|
public static T ParseFormByJson<T>(string jsonStr)
|
||||||
{
|
{
|
||||||
T obj = Activator.CreateInstance<T>();
|
T obj = Activator.CreateInstance<T>();
|
||||||
using (System.IO.MemoryStream ms =
|
using (MemoryStream ms =
|
||||||
new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonStr)))
|
new MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonStr)))
|
||||||
{
|
{
|
||||||
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));
|
||||||
return (T)serializer.ReadObject(ms);
|
return (T)serializer.ReadObject(ms)!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +103,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
|
|
||||||
foreach (SendData city in vals)
|
foreach (SendData city in vals)
|
||||||
{
|
{
|
||||||
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
|
using (MemoryStream ms = new MemoryStream())
|
||||||
{
|
{
|
||||||
s.WriteObject(ms, city);
|
s.WriteObject(ms, city);
|
||||||
st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray()));
|
st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray()));
|
||||||
@@ -121,7 +126,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
{
|
{
|
||||||
char s = json[0];
|
char s = json[0];
|
||||||
char e = json[json.Length - 1];
|
char e = json[json.Length - 1];
|
||||||
return (s == '{' && e == '}') || (s == '[' && e == ']');
|
return s == '{' && e == '}' || s == '[' && e == ']';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -285,10 +290,10 @@ namespace Yi.Framework.Common.Helper
|
|||||||
{
|
{
|
||||||
if (cs.keyStart <= 0)
|
if (cs.keyStart <= 0)
|
||||||
{
|
{
|
||||||
cs.keyStart = (c == '"' ? 3 : 2);
|
cs.keyStart = c == '"' ? 3 : 2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if ((cs.keyStart == 2 && c == '\'') || (cs.keyStart == 3 && c == '"'))
|
else if (cs.keyStart == 2 && c == '\'' || cs.keyStart == 3 && c == '"')
|
||||||
{
|
{
|
||||||
if (!cs.escapeChar)
|
if (!cs.escapeChar)
|
||||||
{
|
{
|
||||||
@@ -305,10 +310,10 @@ namespace Yi.Framework.Common.Helper
|
|||||||
{
|
{
|
||||||
if (cs.valueStart <= 0)
|
if (cs.valueStart <= 0)
|
||||||
{
|
{
|
||||||
cs.valueStart = (c == '"' ? 3 : 2);
|
cs.valueStart = c == '"' ? 3 : 2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if ((cs.valueStart == 2 && c == '\'') || (cs.valueStart == 3 && c == '"'))
|
else if (cs.valueStart == 2 && c == '\'' || cs.valueStart == 3 && c == '"')
|
||||||
{
|
{
|
||||||
if (!cs.escapeChar)
|
if (!cs.escapeChar)
|
||||||
{
|
{
|
||||||
@@ -445,14 +450,14 @@ namespace Yi.Framework.Common.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"}]}]
|
||||||
isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。
|
isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。
|
||||||
break;
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
isError = !jsonStart || (keyStart != 0 && state == 0);//重复结束错误 或者 提前结束{"aa"}。正常的有{}
|
isError = !jsonStart || keyStart != 0 && state == 0;//重复结束错误 或者 提前结束{"aa"}。正常的有{}
|
||||||
break;
|
break;
|
||||||
case '[':
|
case '[':
|
||||||
isError = arrayStart && state == 0;//重复开始错误
|
isError = arrayStart && state == 0;//重复开始错误
|
||||||
@@ -466,7 +471,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
if (!isError)
|
if (!isError)
|
||||||
{
|
{
|
||||||
//重复开始 [""",{"" "}]
|
//重复开始 [""",{"" "}]
|
||||||
isError = (state == 0 && keyStart == -1) || (state == 1 && valueStart == -1);
|
isError = state == 0 && keyStart == -1 || state == 1 && valueStart == -1;
|
||||||
}
|
}
|
||||||
if (!isError && arrayStart && !jsonStart && c == '\'')//['aa',{}]
|
if (!isError && arrayStart && !jsonStart && c == '\'')//['aa',{}]
|
||||||
{
|
{
|
||||||
@@ -482,7 +487,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
{
|
{
|
||||||
if (jsonStart)
|
if (jsonStart)
|
||||||
{
|
{
|
||||||
isError = state == 0 || (state == 1 && valueStart > 1);//重复出现。
|
isError = state == 0 || state == 1 && valueStart > 1;//重复出现。
|
||||||
}
|
}
|
||||||
else if (arrayStart)//["aa,] [,] [{},{}]
|
else if (arrayStart)//["aa,] [,] [{},{}]
|
||||||
{
|
{
|
||||||
@@ -497,7 +502,7 @@ namespace Yi.Framework.Common.Helper
|
|||||||
case '\t':
|
case '\t':
|
||||||
break;
|
break;
|
||||||
default: //值开头。。
|
default: //值开头。。
|
||||||
isError = (!jsonStart && !arrayStart) || (state == 0 && keyStart == -1) || (valueStart == -1 && state == 1);//
|
isError = !jsonStart && !arrayStart || state == 0 && keyStart == -1 || valueStart == -1 && state == 1;//
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//if (isError)
|
//if (isError)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user