Commit 515fceeb92bacf78716f72ce5111d52846b7a1e8
0 parents
框架初始化
Showing
2204 changed files
with
159987 additions
and
0 deletions
Too many changes.
To preserve performance only 100 of 2204 files are displayed.
.DS_Store
0 → 100644
No preview for this file type
.gitignore
0 → 100644
| 1 | +++ a/.gitignore | |
| 1 | +## Ignore Visual Studio temporary files, build results, and | |
| 2 | +## files generated by popular Visual Studio add-ons. | |
| 3 | + | |
| 4 | +# User-specific files | |
| 5 | +*.suo | |
| 6 | +*.user | |
| 7 | +*.userosscache | |
| 8 | +*.sln.docstates | |
| 9 | + | |
| 10 | +# User-specific files (MonoDevelop/Xamarin Studio) | |
| 11 | +*.userprefs | |
| 12 | + | |
| 13 | +# Build results | |
| 14 | +[Dd]ebug/ | |
| 15 | +[Dd]ebugPublic/ | |
| 16 | +[Rr]elease/ | |
| 17 | +[Rr]eleases/ | |
| 18 | +x64/ | |
| 19 | +x86/ | |
| 20 | +bld/ | |
| 21 | +[Bb]in/ | |
| 22 | +[Oo]bj/ | |
| 23 | +[L]og/ | |
| 24 | + | |
| 25 | +# Visual Studio 2015 cache/options directory | |
| 26 | +.vs/ | |
| 27 | +# Uncomment if you have tasks that create the project's static files in wwwroot | |
| 28 | +#wwwroot/ | |
| 29 | + | |
| 30 | +# MSTest test Results | |
| 31 | +[Tt]est[Rr]esult*/ | |
| 32 | +[Bb]uild[Ll]og.* | |
| 33 | + | |
| 34 | +# NUNIT | |
| 35 | +*.VisualState.xml | |
| 36 | +TestResult.xml | |
| 37 | + | |
| 38 | +# Build Results of an ATL Project | |
| 39 | +[Dd]ebugPS/ | |
| 40 | +[Rr]eleasePS/ | |
| 41 | +dlldata.c | |
| 42 | + | |
| 43 | +# DNX | |
| 44 | +project.lock.json | |
| 45 | +artifacts/ | |
| 46 | + | |
| 47 | +*_i.c | |
| 48 | +*_p.c | |
| 49 | +*_i.h | |
| 50 | +*.ilk | |
| 51 | +*.meta | |
| 52 | +*.obj | |
| 53 | +*.pch | |
| 54 | +*.pdb | |
| 55 | +*.pgc | |
| 56 | +*.pgd | |
| 57 | +*.rsp | |
| 58 | +*.sbr | |
| 59 | +*.tlb | |
| 60 | +*.tli | |
| 61 | +*.tlh | |
| 62 | +*.tmp | |
| 63 | +*.tmp_proj | |
| 64 | +*.log | |
| 65 | +*.vspscc | |
| 66 | +*.vssscc | |
| 67 | +.builds | |
| 68 | +*.pidb | |
| 69 | +*.svclog | |
| 70 | +*.scc | |
| 71 | + | |
| 72 | +# Chutzpah Test files | |
| 73 | +_Chutzpah* | |
| 74 | + | |
| 75 | +# Visual C++ cache files | |
| 76 | +ipch/ | |
| 77 | +*.aps | |
| 78 | +*.ncb | |
| 79 | +*.opendb | |
| 80 | +*.opensdf | |
| 81 | +*.sdf | |
| 82 | +*.cachefile | |
| 83 | +*.VC.db | |
| 84 | +*.VC.VC.opendb | |
| 85 | + | |
| 86 | +# Visual Studio profiler | |
| 87 | +*.psess | |
| 88 | +*.vsp | |
| 89 | +*.vspx | |
| 90 | +*.sap | |
| 91 | + | |
| 92 | +# TFS 2012 Local Workspace | |
| 93 | +$tf/ | |
| 94 | + | |
| 95 | +# Guidance Automation Toolkit | |
| 96 | +*.gpState | |
| 97 | + | |
| 98 | +# ReSharper is a .NET coding add-in | |
| 99 | +_ReSharper*/ | |
| 100 | +*.[Rr]e[Ss]harper | |
| 101 | +*.DotSettings.user | |
| 102 | + | |
| 103 | +# JustCode is a .NET coding add-in | |
| 104 | +.JustCode | |
| 105 | + | |
| 106 | +# TeamCity is a build add-in | |
| 107 | +_TeamCity* | |
| 108 | + | |
| 109 | +# DotCover is a Code Coverage Tool | |
| 110 | +*.dotCover | |
| 111 | + | |
| 112 | +# NCrunch | |
| 113 | +_NCrunch_* | |
| 114 | +.*crunch*.local.xml | |
| 115 | +nCrunchTemp_* | |
| 116 | + | |
| 117 | +# MightyMoose | |
| 118 | +*.mm.* | |
| 119 | +AutoTest.Net/ | |
| 120 | + | |
| 121 | +# Web workbench (sass) | |
| 122 | +.sass-cache/ | |
| 123 | + | |
| 124 | +# Installshield output folder | |
| 125 | +[Ee]xpress/ | |
| 126 | + | |
| 127 | +# DocProject is a documentation generator add-in | |
| 128 | +DocProject/buildhelp/ | |
| 129 | +DocProject/Help/*.HxT | |
| 130 | +DocProject/Help/*.HxC | |
| 131 | +DocProject/Help/*.hhc | |
| 132 | +DocProject/Help/*.hhk | |
| 133 | +DocProject/Help/*.hhp | |
| 134 | +DocProject/Help/Html2 | |
| 135 | +DocProject/Help/html | |
| 136 | + | |
| 137 | +# Click-Once directory | |
| 138 | +publish/ | |
| 139 | + | |
| 140 | +# Publish Web Output | |
| 141 | +*.[Pp]ublish.xml | |
| 142 | +*.azurePubxml | |
| 143 | +# TODO: Comment the next line if you want to checkin your web deploy settings | |
| 144 | +# but database connection strings (with potential passwords) will be unencrypted | |
| 145 | +*.pubxml | |
| 146 | +*.publishproj | |
| 147 | + | |
| 148 | +# Microsoft Azure Web App publish settings. Comment the next line if you want to | |
| 149 | +# checkin your Azure Web App publish settings, but sensitive information contained | |
| 150 | +# in these scripts will be unencrypted | |
| 151 | +PublishScripts/ | |
| 152 | + | |
| 153 | +# NuGet Packages | |
| 154 | +*.nupkg | |
| 155 | +# The packages folder can be ignored because of Package Restore | |
| 156 | +**/packages/* | |
| 157 | + | |
| 158 | +# 把 Yi.Vben5.Vue3 下的 packages 目录重新放出来 | |
| 159 | +!**/Yi.Vben5.Vue3/packages/ | |
| 160 | +!**/Yi.Vben5.Vue3/packages/** | |
| 161 | +# except build/, which is used as an MSBuild target. | |
| 162 | +!**/packages/build/ | |
| 163 | +# Uncomment if necessary however generally it will be regenerated when needed | |
| 164 | +#!**/packages/repositories.config | |
| 165 | +# NuGet v3's project.json files produces more ignoreable files | |
| 166 | +*.nuget.props | |
| 167 | +*.nuget.targets | |
| 168 | + | |
| 169 | +# Microsoft Azure Build Output | |
| 170 | +csx/ | |
| 171 | +*.build.csdef | |
| 172 | + | |
| 173 | +# Microsoft Azure Emulator | |
| 174 | +ecf/ | |
| 175 | +rcf/ | |
| 176 | + | |
| 177 | +# Windows Store app package directories and files | |
| 178 | +AppPackages/ | |
| 179 | +BundleArtifacts/ | |
| 180 | +Package.StoreAssociation.xml | |
| 181 | +_pkginfo.txt | |
| 182 | + | |
| 183 | +# Visual Studio cache files | |
| 184 | +# files ending in .cache can be ignored | |
| 185 | +*.[Cc]ache | |
| 186 | +# but keep track of directories ending in .cache | |
| 187 | +!*.[Cc]ache/ | |
| 188 | + | |
| 189 | +# Others | |
| 190 | +ClientBin/ | |
| 191 | +~$* | |
| 192 | +*~ | |
| 193 | +*.dbmdl | |
| 194 | +*.dbproj.schemaview | |
| 195 | +*.pfx | |
| 196 | +*.publishsettings | |
| 197 | +node_modules/ | |
| 198 | +orleans.codegen.cs | |
| 199 | + | |
| 200 | +# Since there are multiple workflows, uncomment next line to ignore bower_components | |
| 201 | +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) | |
| 202 | +#bower_components/ | |
| 203 | + | |
| 204 | +# RIA/Silverlight projects | |
| 205 | +Generated_Code/ | |
| 206 | + | |
| 207 | +# Backup & report files from converting an old project file | |
| 208 | +# to a newer Visual Studio version. Backup files are not needed, | |
| 209 | +# because we have git ;-) | |
| 210 | +_UpgradeReport_Files/ | |
| 211 | +Backup*/ | |
| 212 | +UpgradeLog*.XML | |
| 213 | +UpgradeLog*.htm | |
| 214 | + | |
| 215 | +# SQL Server files | |
| 216 | +*.mdf | |
| 217 | +*.ldf | |
| 218 | + | |
| 219 | +# Business Intelligence projects | |
| 220 | +*.rdl.data | |
| 221 | +*.bim.layout | |
| 222 | +*.bim_*.settings | |
| 223 | + | |
| 224 | +# Microsoft Fakes | |
| 225 | +FakesAssemblies/ | |
| 226 | + | |
| 227 | +# GhostDoc plugin setting file | |
| 228 | +*.GhostDoc.xml | |
| 229 | + | |
| 230 | +# Node.js Tools for Visual Studio | |
| 231 | +.ntvs_analysis.dat | |
| 232 | + | |
| 233 | +# Visual Studio 6 build log | |
| 234 | +*.plg | |
| 235 | + | |
| 236 | +# Visual Studio 6 workspace options file | |
| 237 | +*.opt | |
| 238 | + | |
| 239 | +# Visual Studio LightSwitch build output | |
| 240 | +**/*.HTMLClient/GeneratedArtifacts | |
| 241 | +**/*.DesktopClient/GeneratedArtifacts | |
| 242 | +**/*.DesktopClient/ModelManifest.xml | |
| 243 | +**/*.Server/GeneratedArtifacts | |
| 244 | +**/*.Server/ModelManifest.xml | |
| 245 | +_Pvt_Extensions | |
| 246 | + | |
| 247 | +# Paket dependency manager | |
| 248 | +.paket/paket.exe | |
| 249 | +paket-files/ | |
| 250 | + | |
| 251 | +# FAKE - F# Make | |
| 252 | +.fake/ | |
| 253 | + | |
| 254 | +# JetBrains Rider | |
| 255 | +.idea/ | |
| 256 | +*.sln.iml | |
| 257 | + | |
| 258 | +# BookStore | |
| 259 | +src/Acme.BookStore.Web/Logs/* | |
| 260 | +src/Acme.BookStore.Web.Host/Logs/* | |
| 261 | +src/Acme.BookStore.AuthServer/Logs/* | |
| 262 | +src/Acme.BookStore.HttpApi.Host/Logs/* | |
| 263 | +src/Acme.BookStore.HttpApi.HostWithIds/Logs/* | |
| 264 | +src/Acme.BookStore.DbMigrator/Logs/* | |
| 265 | +src/Acme.BookStore.Blazor.Server/Logs/* | |
| 266 | +src/Acme.BookStore.Blazor.Server.Tiered/Logs/* | |
| 267 | + | |
| 268 | +# Use abp install-libs to restore. | |
| 269 | +**/wwwroot/libs/* | |
| 270 | +public | |
| 271 | +dist | |
| 272 | +.vscode | |
| 273 | +/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Development.json | |
| 274 | +/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Production.json | |
| 275 | +/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Development.json | |
| 276 | +/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Production.json | |
| 277 | +/Yi.Abp.Net8/tool/Yi.Abp.Tool.Web/appsettings.Development.json | |
| 278 | +database_backup | |
| 279 | +/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Staging.json | |
| 280 | +/Yi.Abp.Net8/src/Yi.Abp.Web/logs/ | |
| 281 | +/Yi.Abp.Net8/src/Yi.Abp.Web/yi-abp-dev.db | |
| 282 | + | |
| 283 | +package-lock.json | ... | ... |
LICENSE
0 → 100644
| 1 | +++ a/LICENSE | |
| 1 | +MIT License | |
| 2 | + | |
| 3 | +Copyright (c) 2023 橙子 | |
| 4 | + | |
| 5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 6 | +of this software and associated documentation files (the "Software"), to deal | |
| 7 | +in the Software without restriction, including without limitation the rights | |
| 8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 9 | +copies of the Software, and to permit persons to whom the Software is | |
| 10 | +furnished to do so, subject to the following conditions: | |
| 11 | + | |
| 12 | +The above copyright notice and this permission notice shall be included in all | |
| 13 | +copies or substantial portions of the Software. | |
| 14 | + | |
| 15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 21 | +SOFTWARE. | ... | ... |
README-Docker.md
0 → 100644
| 1 | +++ a/README-Docker.md | |
| 1 | +# 🍉Docker 构建说明 | |
| 2 | + | |
| 3 | +## 🍊后端 | |
| 4 | +执行目录:Yi\Yi.Abp.Net8 | |
| 5 | + | |
| 6 | +#### 🍊启动 | |
| 7 | +//不带配置文件 | |
| 8 | +docker run -d --name yi.admin -p 19001:19001 jiftcc/yi.admin:1.0.0 | |
| 9 | + | |
| 10 | +//带配置文件 | |
| 11 | +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 | |
| 12 | + | |
| 13 | + | |
| 14 | +#### 🍊完整代码编译 | |
| 15 | +docker build -t jiftcc/yi.admin:1.0.0 -f Dockerfile . | |
| 16 | + | |
| 17 | +#### 🍊快速产物编译 | |
| 18 | +docker build -t jiftcc/yi.admin:1.0.0 -f DockerfileFast . | |
| 19 | + | ... | ... |
README.md
0 → 100644
| 1 | +++ a/README.md | |
| 1 | +# Yi 框架 | |
| 2 | +--- | |
| 3 | + | |
| 4 | +## 📖 简介 | |
| 5 | + | |
| 6 | +**Yi Framework**(意框架)是一个基于 **.NET 8 + ABP.vNext + SqlSugar** 的 DDD 领域驱动设计后端开源框架。 | |
| 7 | + | |
| 8 | +### 核心理念 | |
| 9 | + | |
| 10 | +- **简单易用**:面向用户的快速开发框架,新人友好 | |
| 11 | +- **源码开放**:框架以源码形式提供,不打包,方便二开和学习 | |
| 12 | +- **模块化设计**:基于 ABP.vNext 模块化架构,按需引用 | |
| 13 | +- **开箱即用**:内置权限管理、多租户、CRUD 等常用功能 | |
| 14 | + | |
| 15 | +### 技术栈 | |
| 16 | + | |
| 17 | +**后端** | |
| 18 | +- .NET 8.0 | |
| 19 | +- ABP.vNext(动态 API、模块化、依赖注入) | |
| 20 | +- SqlSugar(ORM) | |
| 21 | +- JWT 鉴权 | |
| 22 | +- Serilog 日志 | |
| 23 | +- Mapster 对象映射 | |
| 24 | + | |
| 25 | +**前端** | |
| 26 | +- Vue 3.2 | |
| 27 | +- Vben Admin(企业级中后台前端解决方案) | |
| 28 | + | |
| 29 | +--- | |
| 30 | + | |
| 31 | +## 🚀 快速开始 | |
| 32 | + | |
| 33 | +### 环境要求 | |
| 34 | + | |
| 35 | +- **.NET SDK 8.0** 或更高版本 | |
| 36 | +- **Visual Studio 2022** 或 **VS Code** | |
| 37 | +- **Node.js 20.10+**(前端开发需要) | |
| 38 | +- **数据库**:SQLite(默认)/ MySQL / SQL Server / PostgreSQL / Oracle | |
| 39 | + | |
| 40 | +### 第一步:克隆项目 | |
| 41 | + | |
| 42 | +```bash | |
| 43 | +git clone https://gitee.com/ccnetcore/Yi.git | |
| 44 | +cd Yi | |
| 45 | +``` | |
| 46 | + | |
| 47 | +### 第二步:配置数据库 | |
| 48 | + | |
| 49 | +编辑 `Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json`: | |
| 50 | + | |
| 51 | +```json | |
| 52 | +{ | |
| 53 | + "DbConnOptions": { | |
| 54 | + "Url": "server=localhost;port=3306;database=yi_db;uid=root;pwd=123456;CharSet=utf8mb4;", | |
| 55 | + "DbType": "Mysql", | |
| 56 | + "EnabledCodeFirst": true, // 是否通过代码优先创建数据库表结构 | |
| 57 | + "EnabledDbSeed": true, // 是否启用数据库种子数据(初始化数据) | |
| 58 | + "EnabledSqlLog": true, // 是否启用SQL日志记录 | |
| 59 | + "EnabledSaasMultiTenancy": false, // 是否启用多租户 | |
| 60 | + "EnabledConcurrencyException": false // 是否启用并发异常处理 | |
| 61 | + } | |
| 62 | +} | |
| 63 | +``` | |
| 64 | + | |
| 65 | +**支持的数据库类型**: | |
| 66 | +- `Sqlite`(默认,无需配置) | |
| 67 | +- `Mysql` | |
| 68 | +- `Sqlserver` | |
| 69 | +- `PostgreSQL` | |
| 70 | +- `Oracle` | |
| 71 | + | |
| 72 | +### 第三步:启动后端 | |
| 73 | + | |
| 74 | +1. 使用 Visual Studio 打开 `Yi.Abp.Net8/Yi.Abp.sln` | |
| 75 | +2. 设置启动项目为 `Yi.Abp.Web` | |
| 76 | +3. 按 `F5` 启动项目 | |
| 77 | + | |
| 78 | +启动成功后,浏览器会自动打开 Swagger 文档:`http://localhost:19001/swagger` | |
| 79 | + | |
| 80 | +**默认管理员账号**:`cc` / `123456` | |
| 81 | + | |
| 82 | +> 💡 **提示**: | |
| 83 | +> - 首次启动会自动创建数据库表(CodeFirst) | |
| 84 | +> - 会自动初始化种子数据(用户、角色等) | |
| 85 | +> - 接口会自动分组,点击右上角的分组名称查看不同模块的接口 | |
| 86 | + | |
| 87 | +### 第四步:启动前端(可选) | |
| 88 | + | |
| 89 | +```bash | |
| 90 | +cd Yi.Vben5.Vue3 | |
| 91 | +pnpm install | |
| 92 | +pnpm dev:antd | |
| 93 | +``` | |
| 94 | + | |
| 95 | +前端地址:`http://localhost:18000` | |
| 96 | + | |
| 97 | +--- | |
| 98 | + | |
| 99 | +## 📁 项目结构 | |
| 100 | + | |
| 101 | +``` | |
| 102 | +Yi/ | |
| 103 | +├── Yi.Abp.Net8/ # 后端项目 | |
| 104 | +│ ├── framework/ # 框架核心代码(基础设施) | |
| 105 | +│ │ ├── Yi.Framework.SqlSugarCore/ # SqlSugar ORM 封装 | |
| 106 | +│ │ ├── Yi.Framework.Ddd.Application/ # DDD 应用层基类 | |
| 107 | +│ │ └── ... | |
| 108 | +│ ├── module/ # 业务模块目录(所有业务代码都在这里) | |
| 109 | +│ │ ├── rbac/ # 权限管理模块(内置) | |
| 110 | +│ │ ├── tenant-management/# 租户管理模块(内置) | |
| 111 | +│ │ ├── antis-erp/ # 示例业务模块 | |
| 112 | +│ │ └── your-module/ # 你的业务模块(在这里创建) | |
| 113 | +│ └── src/ # 框架启动项目 | |
| 114 | +│ └── Yi.Abp.Web/ # Web 层(启动项目,仅配置) | |
| 115 | +├── Yi.Vben5.Vue3/ # 前端项目 | |
| 116 | +└── Yi.Doc.Md/ # 框架文档 | |
| 117 | +``` | |
| 118 | + | |
| 119 | +### 模块结构(每个业务模块都包含以下分层) | |
| 120 | + | |
| 121 | +``` | |
| 122 | +your-module/ | |
| 123 | +├── YourModule.Domain.Shared/ # 领域共享层(枚举、常量) | |
| 124 | +├── YourModule.Domain/ # 领域层(实体、领域服务) | |
| 125 | +├── YourModule.Application.Contracts/ # 应用抽象层(接口、DTO) | |
| 126 | +├── YourModule.Application/ # 应用层(服务实现) | |
| 127 | +└── YourModule.SqlSugarCore/ # 基础设施层(数据库上下文) | |
| 128 | +``` | |
| 129 | + | |
| 130 | +### 分层架构(DDD) | |
| 131 | + | |
| 132 | +``` | |
| 133 | +┌─────────────────────────────────┐ | |
| 134 | +│ Web 层(Yi.Abp.Web) │ ← 启动项目、中间件配置 | |
| 135 | +├─────────────────────────────────┤ | |
| 136 | +│ 应用层(Application) │ ← 业务逻辑、服务实现 | |
| 137 | +├─────────────────────────────────┤ | |
| 138 | +│ 应用抽象层(Application.Contracts)│ ← 接口定义、DTO | |
| 139 | +├─────────────────────────────────┤ | |
| 140 | +│ 领域层(Domain) │ ← 实体、领域服务 | |
| 141 | +├─────────────────────────────────┤ | |
| 142 | +│ 领域共享层(Domain.Shared) │ ← 枚举、常量、共享 DTO | |
| 143 | +├─────────────────────────────────┤ | |
| 144 | +│ 基础设施层(SqlSugarCore) │ ← ORM、仓储实现 | |
| 145 | +└─────────────────────────────────┘ | |
| 146 | +``` | |
| 147 | + | |
| 148 | +> 💡 **重要**: | |
| 149 | +> - **所有业务代码都应该放在 `module` 目录下创建自己的模块** | |
| 150 | +> - `src` 目录只用于框架启动配置,不存放业务代码 | |
| 151 | +> - 每个模块都是独立的,可以按需引用 | |
| 152 | + | |
| 153 | +--- | |
| 154 | + | |
| 155 | +## 🎯 核心功能 | |
| 156 | + | |
| 157 | +### 1. 动态 API | |
| 158 | + | |
| 159 | +框架基于 ABP.vNext,自动将应用服务转换为 RESTful API,无需手写 Controller。 | |
| 160 | + | |
| 161 | +**示例**: | |
| 162 | +```csharp | |
| 163 | +// 在 Application 层创建服务 | |
| 164 | +public class NewsService : YiCrudAppService<...> { } | |
| 165 | + | |
| 166 | +// 自动生成 API: | |
| 167 | +// GET /api/app/news - 查询列表 | |
| 168 | +// GET /api/app/news/{id} - 查询详情 | |
| 169 | +// POST /api/app/news - 创建 | |
| 170 | +// PUT /api/app/news/{id} - 更新 | |
| 171 | +// DELETE /api/app/news/{id} - 删除 | |
| 172 | +``` | |
| 173 | + | |
| 174 | +### 2. CRUD 快速开发 | |
| 175 | + | |
| 176 | +继承 `YiCrudAppService` 即可自动获得完整的增删改查功能。 | |
| 177 | + | |
| 178 | +### 3. 权限管理(RBAC) | |
| 179 | + | |
| 180 | +内置完整的权限管理系统: | |
| 181 | +- 用户管理 | |
| 182 | +- 角色管理 | |
| 183 | +- 菜单管理 | |
| 184 | +- 部门管理 | |
| 185 | +- 岗位管理 | |
| 186 | +- 字典管理 | |
| 187 | +- 操作日志 | |
| 188 | +- 登录日志 | |
| 189 | + | |
| 190 | +### 4. 多租户支持 | |
| 191 | + | |
| 192 | +支持 SaaS 多租户架构,可配置是否启用。 | |
| 193 | + | |
| 194 | +### 5. 模块化架构 | |
| 195 | + | |
| 196 | +采用 ABP.vNext 模块化设计,功能模块化,按需引用。 | |
| 197 | + | |
| 198 | +--- | |
| 199 | + | |
| 200 | +## 💻 开发指南 | |
| 201 | + | |
| 202 | +### 创建自己的业务模块 | |
| 203 | + | |
| 204 | +**重要**:所有业务代码都应该在 `module` 目录下创建自己的模块,而不是放在 `src` 目录。 | |
| 205 | + | |
| 206 | +#### 步骤一:创建模块目录结构 | |
| 207 | + | |
| 208 | +在 `Yi.Abp.Net8/module/` 目录下创建你的模块文件夹,例如:`your-module/` | |
| 209 | + | |
| 210 | +模块应包含以下项目(参考 `antis-erp` 模块): | |
| 211 | +- `YourModule.Domain.Shared` - 领域共享层 | |
| 212 | +- `YourModule.Domain` - 领域层 | |
| 213 | +- `YourModule.Application.Contracts` - 应用抽象层 | |
| 214 | +- `YourModule.Application` - 应用层 | |
| 215 | +- `YourModule.SqlSugarCore` - 基础设施层 | |
| 216 | + | |
| 217 | +#### 步骤二:创建模块文件 | |
| 218 | + | |
| 219 | +每个项目都需要一个 `Module` 类,例如: | |
| 220 | +- `YourModuleDomainSharedModule.cs` | |
| 221 | +- `YourModuleDomainModule.cs` | |
| 222 | +- `YourModuleApplicationContractsModule.cs` | |
| 223 | +- `YourModuleApplicationModule.cs` | |
| 224 | +- `YourModuleSqlSugarCoreModule.cs` | |
| 225 | + | |
| 226 | +#### 步骤三:注册模块依赖 | |
| 227 | + | |
| 228 | +在 `Yi.Abp.Web/YiAbpWebModule.cs` 中注册你的模块: | |
| 229 | + | |
| 230 | +```csharp | |
| 231 | +[DependsOn( | |
| 232 | + typeof(YourModuleApplicationModule), // 添加你的应用模块 | |
| 233 | + // ... 其他依赖 | |
| 234 | +)] | |
| 235 | +public class YiAbpWebModule : AbpModule | |
| 236 | +{ | |
| 237 | + // 注册动态 API | |
| 238 | + PreConfigure<AbpAspNetCoreMvcOptions>(options => | |
| 239 | + { | |
| 240 | + options.ConventionalControllers.Create( | |
| 241 | + typeof(YourModuleApplicationModule).Assembly, | |
| 242 | + options => options.RemoteServiceName = "你的模块名称" | |
| 243 | + ); | |
| 244 | + }); | |
| 245 | +} | |
| 246 | +``` | |
| 247 | + | |
| 248 | +### 创建一个完整的 CRUD 功能 | |
| 249 | + | |
| 250 | +以创建"新闻管理"功能为例(在 `your-module` 模块中): | |
| 251 | + | |
| 252 | +#### 1. 创建实体(Domain 层) | |
| 253 | + | |
| 254 | +在 `YourModule.Domain/Entities/` 创建: | |
| 255 | + | |
| 256 | +```csharp | |
| 257 | +using SqlSugar; | |
| 258 | +using Volo.Abp.Auditing; | |
| 259 | +using Volo.Abp.Domain.Entities; | |
| 260 | +using Yi.Framework.Core.Data; | |
| 261 | + | |
| 262 | +namespace YourModule.Domain.Entities | |
| 263 | +{ | |
| 264 | + [SugarTable("News")] | |
| 265 | + public class NewsAggregateRoot : AggregateRoot<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IState | |
| 266 | + { | |
| 267 | + [SugarColumn(IsPrimaryKey = true)] | |
| 268 | + public override Guid Id { get; protected set; } | |
| 269 | + | |
| 270 | + public bool IsDeleted { get; set; } | |
| 271 | + public DateTime CreationTime { get; set; } = DateTime.Now; | |
| 272 | + public Guid? CreatorId { get; set; } | |
| 273 | + public Guid? LastModifierId { get; set; } | |
| 274 | + public DateTime? LastModificationTime { get; set; } | |
| 275 | + public int OrderNum { get; set; } = 0; | |
| 276 | + public bool State { get; set; } = true; | |
| 277 | + | |
| 278 | + [SugarColumn(ColumnName = "Title")] | |
| 279 | + public string Title { get; set; } = string.Empty; | |
| 280 | + | |
| 281 | + [SugarColumn(ColumnName = "Content", ColumnDataType = "text")] | |
| 282 | + public string Content { get; set; } = string.Empty; | |
| 283 | + } | |
| 284 | +} | |
| 285 | +``` | |
| 286 | + | |
| 287 | +#### 2. 创建 DTO(Application.Contracts 层) | |
| 288 | + | |
| 289 | +在 `YourModule.Application.Contracts/Dtos/News/` 创建: | |
| 290 | + | |
| 291 | +```csharp | |
| 292 | +// NewsGetOutputDto.cs - 详情输出 DTO | |
| 293 | +using Volo.Abp.Application.Dtos; | |
| 294 | + | |
| 295 | +namespace YourModule.Application.Contracts.Dtos.News | |
| 296 | +{ | |
| 297 | + public class NewsGetOutputDto : EntityDto<Guid> | |
| 298 | + { | |
| 299 | + public string Title { get; set; } | |
| 300 | + public string Content { get; set; } | |
| 301 | + public DateTime CreationTime { get; set; } | |
| 302 | + } | |
| 303 | +} | |
| 304 | + | |
| 305 | +// NewsGetListOutputDto.cs - 列表输出 DTO | |
| 306 | +public class NewsGetListOutputDto : EntityDto<Guid> | |
| 307 | +{ | |
| 308 | + public string Title { get; set; } | |
| 309 | + public DateTime CreationTime { get; set; } | |
| 310 | +} | |
| 311 | + | |
| 312 | +// NewsGetListInputVo.cs - 查询参数 | |
| 313 | +using Yi.Framework.Ddd.Application.Contracts; | |
| 314 | + | |
| 315 | +public class NewsGetListInputVo : PagedAllResultRequestDto | |
| 316 | +{ | |
| 317 | + public string? Title { get; set; } | |
| 318 | +} | |
| 319 | + | |
| 320 | +// NewsCreateInputVo.cs - 创建输入 | |
| 321 | +namespace YourModule.Application.Contracts.Dtos.News | |
| 322 | +{ | |
| 323 | + public class NewsCreateInputVo | |
| 324 | + { | |
| 325 | + public string Title { get; set; } | |
| 326 | + public string Content { get; set; } | |
| 327 | + } | |
| 328 | +} | |
| 329 | + | |
| 330 | +// NewsUpdateInputVo.cs - 更新输入 | |
| 331 | +public class NewsUpdateInputVo | |
| 332 | +{ | |
| 333 | + public string Title { get; set; } | |
| 334 | + public string Content { get; set; } | |
| 335 | +} | |
| 336 | +``` | |
| 337 | + | |
| 338 | +#### 3. 创建服务接口(Application.Contracts 层) | |
| 339 | + | |
| 340 | +在 `YourModule.Application.Contracts/IServices/` 创建: | |
| 341 | + | |
| 342 | +```csharp | |
| 343 | +using Yi.Framework.Ddd.Application.Contracts; | |
| 344 | +using YourModule.Application.Contracts.Dtos.News; | |
| 345 | + | |
| 346 | +namespace YourModule.Application.Contracts.IServices | |
| 347 | +{ | |
| 348 | + public interface INewsService : IYiCrudAppService< | |
| 349 | + NewsGetOutputDto, | |
| 350 | + NewsGetListOutputDto, | |
| 351 | + Guid, | |
| 352 | + NewsGetListInputVo, | |
| 353 | + NewsCreateInputVo, | |
| 354 | + NewsUpdateInputVo> | |
| 355 | + { | |
| 356 | + } | |
| 357 | +} | |
| 358 | +``` | |
| 359 | + | |
| 360 | +#### 4. 实现服务(Application 层) | |
| 361 | + | |
| 362 | +在 `YourModule.Application/Services/` 创建: | |
| 363 | + | |
| 364 | +```csharp | |
| 365 | +using SqlSugar; | |
| 366 | +using Volo.Abp.Application.Dtos; | |
| 367 | +using Yi.Framework.Ddd.Application; | |
| 368 | +using Yi.Framework.SqlSugarCore.Abstractions; | |
| 369 | +using YourModule.Application.Contracts.Dtos.News; | |
| 370 | +using YourModule.Application.Contracts.IServices; | |
| 371 | +using YourModule.Domain.Entities; | |
| 372 | + | |
| 373 | +namespace YourModule.Application.Services | |
| 374 | +{ | |
| 375 | + public class NewsService : YiCrudAppService< | |
| 376 | + NewsAggregateRoot, | |
| 377 | + NewsGetOutputDto, | |
| 378 | + NewsGetListOutputDto, | |
| 379 | + Guid, | |
| 380 | + NewsGetListInputVo, | |
| 381 | + NewsCreateInputVo, | |
| 382 | + NewsUpdateInputVo>, | |
| 383 | + INewsService | |
| 384 | + { | |
| 385 | + private ISqlSugarRepository<NewsAggregateRoot, Guid> _repository; | |
| 386 | + | |
| 387 | + public NewsService(ISqlSugarRepository<NewsAggregateRoot, Guid> repository) | |
| 388 | + : base(repository) | |
| 389 | + { | |
| 390 | + _repository = repository; | |
| 391 | + } | |
| 392 | + | |
| 393 | + // 自定义查询逻辑(可选) | |
| 394 | + public override async Task<PagedResultDto<NewsGetListOutputDto>> GetListAsync(NewsGetListInputVo input) | |
| 395 | + { | |
| 396 | + RefAsync<int> total = 0; | |
| 397 | + var entities = await _repository._DbQueryable | |
| 398 | + .WhereIF(!string.IsNullOrEmpty(input.Title), x => x.Title.Contains(input.Title!)) | |
| 399 | + .OrderByDescending(x => x.CreationTime) | |
| 400 | + .ToPageListAsync(input.SkipCount, input.MaxResultCount, total); | |
| 401 | + | |
| 402 | + return new PagedResultDto<NewsGetListOutputDto>( | |
| 403 | + total, | |
| 404 | + await MapToGetListOutputDtosAsync(entities) | |
| 405 | + ); | |
| 406 | + } | |
| 407 | + } | |
| 408 | +} | |
| 409 | +``` | |
| 410 | + | |
| 411 | +#### 5. 注册模块和动态 API | |
| 412 | + | |
| 413 | +在 `Yi.Abp.Web/YiAbpWebModule.cs` 中: | |
| 414 | + | |
| 415 | +```csharp | |
| 416 | +// 1. 添加模块依赖 | |
| 417 | +[DependsOn( | |
| 418 | + typeof(YourModuleApplicationModule), // 添加你的模块 | |
| 419 | + // ... 其他依赖 | |
| 420 | +)] | |
| 421 | + | |
| 422 | +// 2. 注册动态 API | |
| 423 | +PreConfigure<AbpAspNetCoreMvcOptions>(options => | |
| 424 | +{ | |
| 425 | + options.ConventionalControllers.Create( | |
| 426 | + typeof(YourModuleApplicationModule).Assembly, | |
| 427 | + options => options.RemoteServiceName = "你的模块名称" | |
| 428 | + ); | |
| 429 | +}); | |
| 430 | +``` | |
| 431 | + | |
| 432 | +#### 6. 完成! | |
| 433 | + | |
| 434 | +启动项目后,自动生成以下 API: | |
| 435 | +- `GET /api/app/news` - 分页查询 | |
| 436 | +- `GET /api/app/news/{id}` - 查询详情 | |
| 437 | +- `POST /api/app/news` - 创建 | |
| 438 | +- `PUT /api/app/news/{id}` - 更新 | |
| 439 | +- `DELETE /api/app/news/{id}` - 删除 | |
| 440 | + | |
| 441 | +数据库表会在首次启动时自动创建(CodeFirst)。 | |
| 442 | + | |
| 443 | +--- | |
| 444 | + | |
| 445 | +## ⚙️ 配置说明 | |
| 446 | + | |
| 447 | +### 数据库配置 | |
| 448 | + | |
| 449 | +```json | |
| 450 | +{ | |
| 451 | + "DbConnOptions": { | |
| 452 | + "Url": "数据库连接字符串", | |
| 453 | + "DbType": "Mysql", // 数据库类型 | |
| 454 | + "EnabledCodeFirst": true, // 是否自动创建表 | |
| 455 | + "EnabledDbSeed": true, // 是否初始化种子数据 | |
| 456 | + "EnabledSqlLog": true, // 是否记录SQL日志 | |
| 457 | + "EnabledSaasMultiTenancy": false, // 是否启用多租户 | |
| 458 | + "EnabledConcurrencyException": false // 是否启用乐观锁 | |
| 459 | + } | |
| 460 | +} | |
| 461 | +``` | |
| 462 | + | |
| 463 | +### JWT 配置 | |
| 464 | + | |
| 465 | +```json | |
| 466 | +{ | |
| 467 | + "JwtOptions": { | |
| 468 | + "Issuer": "https://ccnetcore.com", | |
| 469 | + "Audience": "https://ccnetcore.com", | |
| 470 | + "SecurityKey": "你的密钥", | |
| 471 | + "ExpiresMinuteTime": 86400 // Token 过期时间(分钟) | |
| 472 | + } | |
| 473 | +} | |
| 474 | +``` | |
| 475 | + | |
| 476 | +### Redis 配置(可选) | |
| 477 | + | |
| 478 | +```json | |
| 479 | +{ | |
| 480 | + "Redis": { | |
| 481 | + "IsEnabled": false, | |
| 482 | + "Configuration": "127.0.0.1:6379,password=123,defaultDatabase=13", | |
| 483 | + "JobDb": 13 | |
| 484 | + } | |
| 485 | +} | |
| 486 | +``` | |
| 487 | + | |
| 488 | +### 权限管理配置 | |
| 489 | + | |
| 490 | +```json | |
| 491 | +{ | |
| 492 | + "RbacOptions": { | |
| 493 | + "AdminPassword": "123456", // 默认管理员密码 | |
| 494 | + "EnableCaptcha": false, // 是否启用验证码 | |
| 495 | + "EnableRegister": false, // 是否允许注册 | |
| 496 | + "EnableDataBaseBackup": false // 是否启用数据库备份 | |
| 497 | + } | |
| 498 | +} | |
| 499 | +``` | |
| 500 | + | |
| 501 | +--- | |
| 502 | + | |
| 503 | +## 📚 更多文档 | |
| 504 | + | |
| 505 | +- [框架快速开始教程](https://ccnetcore.com/article/aaa00329-7f35-d3fe-d258-3a0f8380b742) | |
| 506 | +- [框架功能模块教程](https://ccnetcore.com/article/8c464ab3-8ba5-2761-a4b0-3a0f83a9f312) | |
| 507 | +- [实战演练开发教程](https://ccnetcore.com/article/e89c9593-f337-ada7-d108-3a0f83ae48e6) | |
| 508 | +- [社区导航大全](https://ccnetcore.com/article/aaa00329-7f35-d3fe-d258-3a0f8380b742/fb8c871b-41fc-21bc-474f-3a154498f42b) | |
| 509 | + | |
| 510 | +--- | |
| 511 | + | |
| 512 | +## 🎁 内置模块 | |
| 513 | + | |
| 514 | +- ✅ **RBAC 权限管理系统** - 完整的用户权限管理 | |
| 515 | +- ✅ **租户管理模块** - 多租户支持 | |
| 516 | +- ✅ **审计日志模块** - 操作日志记录 | |
| 517 | +- ✅ **设置管理模块** - 系统配置管理 | |
| 518 | + | |
| 519 | +--- | |
| 520 | + | |
| 521 | +## 🌟 特性 | |
| 522 | + | |
| 523 | +- ✅ **开箱即用**:默认 SQLite,无需配置即可运行 | |
| 524 | +- ✅ **CodeFirst**:自动创建数据库表结构 | |
| 525 | +- ✅ **种子数据**:自动初始化基础数据 | |
| 526 | +- ✅ **动态 API**:无需手写 Controller | |
| 527 | +- ✅ **CRUD 基类**:快速开发增删改查 | |
| 528 | +- ✅ **权限控制**:内置完整的权限管理 | |
| 529 | +- ✅ **多租户**:支持 SaaS 架构 | |
| 530 | +- ✅ **模块化**:功能模块化,按需引用 | |
| 531 | +- ✅ **源码开放**:框架源码直接提供,方便学习和二开 | |
| 532 | + | |
| 533 | +--- | |
| 534 | + | |
| 535 | +## 🔧 常见问题 | |
| 536 | + | |
| 537 | +### Q: 如何切换数据库? | |
| 538 | + | |
| 539 | +A: 修改 `appsettings.json` 中的 `DbConnOptions` 配置,设置 `DbType` 和 `Url`。 | |
| 540 | + | |
| 541 | +### Q: 如何禁用 CodeFirst 自动建表? | |
| 542 | + | |
| 543 | +A: 设置 `EnabledCodeFirst: false`,然后手动执行 SQL 脚本创建表。 | |
| 544 | + | |
| 545 | +### Q: 如何添加新的业务模块? | |
| 546 | + | |
| 547 | +A: **所有业务代码都应该在 `module` 目录下创建自己的模块**。参考 `antis-erp` 模块的结构,创建包含 Domain.Shared、Domain、Application.Contracts、Application、SqlSugarCore 五个项目的模块,然后在 `YiAbpWebModule.cs` 中注册模块依赖和动态 API。 | |
| 548 | + | |
| 549 | +### Q: 如何自定义 API 路由? | |
| 550 | + | |
| 551 | +A: 在服务方法上使用 `[Route("your-route")]` 特性。 | |
| 552 | + | |
| 553 | +### Q: 如何启用多租户? | |
| 554 | + | |
| 555 | +A: 设置 `EnabledSaasMultiTenancy: true`,并在 Swagger 中使用 `__tenant` 参数指定租户。 | |
| 556 | + | |
| 557 | +--- | |
| 558 | + | |
| 559 | +## 📞 联系我们 | |
| 560 | + | |
| 561 | +- **官网**:[ccnetcore.com](https://ccnetcore.com) | |
| 562 | +- **演示地址**:[data.ccnetcore.com:2000](https://data.ccnetcore.com:2000)(账号:cc / 密码:123456) | |
| 563 | +- **QQ 群**:981136525(官方五群) | |
| 564 | +- **微信**:添加 `chengzilaoge520`(备注:拉群) | |
| 565 | + | |
| 566 | +--- | |
| 567 | + | |
| 568 | +## 📄 许可证 | |
| 569 | + | |
| 570 | +本项目采用 [MIT](LICENSE) 许可证。 | |
| 571 | + | |
| 572 | +--- | |
| 573 | + | |
| 574 | +## 🙏 致谢 | |
| 575 | + | |
| 576 | +感谢以下开源项目: | |
| 577 | + | |
| 578 | +- [ABP Framework](https://github.com/abpframework/abp) | |
| 579 | +- [SqlSugar](https://www.donet5.com/) | |
| 580 | +- [Vben Admin](https://github.com/vbenjs/vben-admin-thin-next) | |
| 581 | + | |
| 582 | +--- | |
| 583 | + | |
| 584 | +<div align="center"> | |
| 585 | + | |
| 586 | +**⭐ 如果这个项目对你有帮助,请给个 Star ⭐** | |
| 587 | + | |
| 588 | +Made with ❤️ by [Yi Framework Team](https://ccnetcore.com) | |
| 589 | + | |
| 590 | +</div> | ... | ... |
Yi.Abp.Net8/.DS_Store
0 → 100644
No preview for this file type
Yi.Abp.Net8/.dockerignore
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/.dockerignore | |
| 1 | +**/.classpath | |
| 2 | +**/.dockerignore | |
| 3 | +**/.env | |
| 4 | +**/.git | |
| 5 | +**/.gitignore | |
| 6 | +**/.project | |
| 7 | +**/.settings | |
| 8 | +**/.toolstarget | |
| 9 | +**/.vs | |
| 10 | +**/.vscode | |
| 11 | +**/*.*proj.user | |
| 12 | +**/*.dbmdl | |
| 13 | +**/*.jfm | |
| 14 | +**/azds.yaml | |
| 15 | +**/bin | |
| 16 | +**/charts | |
| 17 | +**/docker-compose* | |
| 18 | +**/Dockerfile* | |
| 19 | +**/node_modules | |
| 20 | +**/npm-debug.log | |
| 21 | +**/obj | |
| 22 | +**/secrets.dev.yaml | |
| 23 | +**/values.dev.yaml | |
| 24 | +LICENSE | |
| 25 | +README.md | |
| 26 | +!**/.gitignore | |
| 27 | +!.git/HEAD | |
| 28 | +!.git/config | |
| 29 | +!.git/packed-refs | |
| 30 | +!.git/refs/heads/** | |
| 31 | +appsettings.Development.json | |
| 32 | +appsettings.Production.json | |
| 33 | +appsettings.Staging.json | |
| 0 | 34 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/Dockerfile
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/Dockerfile | |
| 1 | +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base | |
| 2 | +USER root | |
| 3 | +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime | |
| 4 | +RUN echo "Asia/Shanghai" > /etc/timezone | |
| 5 | +WORKDIR /app | |
| 6 | +EXPOSE 19001 | |
| 7 | + | |
| 8 | +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build | |
| 9 | +ARG BUILD_CONFIGURATION=Release | |
| 10 | +WORKDIR /main | |
| 11 | +COPY . . | |
| 12 | +WORKDIR "/main/src/Yi.Abp.Web" | |
| 13 | +RUN dotnet restore "Yi.Abp.Web.csproj" | |
| 14 | + | |
| 15 | +FROM build AS publish | |
| 16 | +WORKDIR "/main/src/Yi.Abp.Web" | |
| 17 | +RUN dotnet publish "Yi.Abp.Web.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false | |
| 18 | + | |
| 19 | +FROM base AS final | |
| 20 | +WORKDIR /app | |
| 21 | +COPY --from=publish /app/publish . | |
| 22 | +ENTRYPOINT ["dotnet", "Yi.Abp.Web.dll"] | |
| 0 | 23 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/DockerfileFast
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/DockerfileFast | |
| 1 | +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base | |
| 2 | +USER root | |
| 3 | +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime | |
| 4 | +RUN echo "Asia/Shanghai" > /etc/timezone | |
| 5 | +WORKDIR /app | |
| 6 | +EXPOSE 19001 | |
| 7 | + | |
| 8 | +FROM base AS final | |
| 9 | +WORKDIR /app | |
| 10 | +COPY ["./publish","."] | |
| 11 | +ENTRYPOINT ["dotnet", "Yi.Abp.Web.dll"] | |
| 0 | 12 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/Yi.Abp.sln
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/Yi.Abp.sln | |
| 1 | + | |
| 2 | +Microsoft Visual Studio Solution File, Format Version 12.00 | |
| 3 | +# Visual Studio Version 17 | |
| 4 | +VisualStudioVersion = 17.7.34202.233 | |
| 5 | +MinimumVisualStudioVersion = 10.0.40219.1 | |
| 6 | +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Web", "src\Yi.Abp.Web\Yi.Abp.Web.csproj", "{15913E44-DA92-44B9-9AC5-E9457EA34BF5}" | |
| 7 | +EndProject | |
| 8 | +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SqlSugarCore", "framework\Yi.Framework.SqlSugarCore\Yi.Framework.SqlSugarCore.csproj", "{DC431ECC-C75D-4B01-8B79-4861948179BB}" | |
| 9 | +EndProject | |
| 10 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B782C78B-6C17-49E6-A237-3383BA720766}" | |
| 11 | +EndProject | |
| 12 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "framework", "framework", "{77B949E9-530E-45A5-9657-20F7D5C6875C}" | |
| 13 | +EndProject | |
| 14 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "module", "module", "{2317227D-7796-4E7B-BEDB-7CD1CAE7B853}" | |
| 15 | +EndProject | |
| 16 | +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.SqlSugarCore", "src\Yi.Abp.SqlSugarCore\Yi.Abp.SqlSugarCore.csproj", "{9A7BBA40-28D6-4900-9E1D-D627A516EE72}" | |
| 17 | +EndProject | |
| 18 | +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Application", "src\Yi.Abp.Application\Yi.Abp.Application.csproj", "{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}" | |
| 19 | +EndProject | |
| 20 | +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}" | |
| 21 | +EndProject | |
| 22 | +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Domain", "src\Yi.Abp.Domain\Yi.Abp.Domain.csproj", "{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}" | |
| 23 | +EndProject | |
| 24 | +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}" | |
| 25 | +EndProject | |
| 26 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6A5375C6-1D55-4E93-9B19-736F1C68CBC3}" | |
| 27 | + ProjectSection(SolutionItems) = preProject | |
| 28 | + common.props = common.props | |
| 29 | + end.sh = end.sh | |
| 30 | + logo.png = logo.png | |
| 31 | + start.sh = start.sh | |
| 32 | + tool.bat = tool.bat | |
| 33 | + usings.props = usings.props | |
| 34 | + version.props = version.props | |
| 35 | + publish.bat = publish.bat | |
| 36 | + publish_Demo.bat = publish_Demo.bat | |
| 37 | + Dockerfile = Dockerfile | |
| 38 | + DockerfileFast = DockerfileFast | |
| 39 | + EndProjectSection | |
| 40 | +EndProject | |
| 41 | +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}" | |
| 42 | +EndProject | |
| 43 | +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core", "framework\Yi.Framework.Core\Yi.Framework.Core.csproj", "{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}" | |
| 44 | +EndProject | |
| 45 | +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Mapster", "framework\Yi.Framework.Mapster\Yi.Framework.Mapster.csproj", "{1995A019-C8AE-467E-B427-ED57D6CBF44F}" | |
| 46 | +EndProject | |
| 47 | +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore", "framework\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj", "{F5011C0D-209B-4A98-BBE3-68157503EEF8}" | |
| 48 | +EndProject | |
| 49 | +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}" | |
| 50 | +EndProject | |
| 51 | +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}" | |
| 52 | +EndProject | |
| 53 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rbac", "rbac", "{9CC7A457-1236-40BA-B47B-E7B710A3F061}" | |
| 54 | +EndProject | |
| 55 | +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}" | |
| 56 | +EndProject | |
| 57 | +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}" | |
| 58 | +EndProject | |
| 59 | +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}" | |
| 60 | +EndProject | |
| 61 | +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}" | |
| 62 | +EndProject | |
| 63 | +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}" | |
| 64 | +EndProject | |
| 65 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "audit-logging", "audit-logging", "{73CCF2C4-B9FD-44AB-8D4B-0A421805B094}" | |
| 66 | +EndProject | |
| 67 | +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}" | |
| 68 | +EndProject | |
| 69 | +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}" | |
| 70 | +EndProject | |
| 71 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant-management", "{499A8C71-7892-42D0-A77E-48756E1EFF16}" | |
| 72 | +EndProject | |
| 73 | +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}" | |
| 74 | +EndProject | |
| 75 | +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}" | |
| 76 | +EndProject | |
| 77 | +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}" | |
| 78 | +EndProject | |
| 79 | +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}" | |
| 80 | +EndProject | |
| 81 | +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}" | |
| 82 | +EndProject | |
| 83 | +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}" | |
| 84 | +EndProject | |
| 85 | +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}" | |
| 86 | +EndProject | |
| 87 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client", "client", "{8B27846A-043D-4F2F-8140-5CEC9D1863B5}" | |
| 88 | +EndProject | |
| 89 | +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}" | |
| 90 | +EndProject | |
| 91 | +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}" | |
| 92 | +EndProject | |
| 93 | +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}" | |
| 94 | +EndProject | |
| 95 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "setting-management", "setting-management", "{8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}" | |
| 96 | +EndProject | |
| 97 | +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}" | |
| 98 | +EndProject | |
| 99 | +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}" | |
| 100 | +EndProject | |
| 101 | +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}" | |
| 102 | +EndProject | |
| 103 | +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}" | |
| 104 | +EndProject | |
| 105 | +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}" | |
| 106 | +EndProject | |
| 107 | +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "antis-erp", "antis-erp", "{609660A4-AEE6-61D5-25B9-1FDCB688B986}" | |
| 108 | +EndProject | |
| 109 | +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Antis.Erp.Application", "module\antis-erp\Antis.Erp.Application\Antis.Erp.Application.csproj", "{151D2C44-2F56-4407-8FBF-B683B23617F1}" | |
| 110 | +EndProject | |
| 111 | +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Antis.Erp.Application.Contracts", "module\antis-erp\Antis.Erp.Application.Contracts\Antis.Erp.Application.Contracts.csproj", "{810FE198-77D9-4B2D-A83B-AA43D79B806A}" | |
| 112 | +EndProject | |
| 113 | +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Antis.Erp.Domain", "module\antis-erp\Antis.Erp.Domain\Antis.Erp.Domain.csproj", "{B7E56684-FF7B-40C0-9640-DC83CD59AD71}" | |
| 114 | +EndProject | |
| 115 | +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Antis.Erp.Domain.Shared", "module\antis-erp\Antis.Erp.Domain.Shared\Antis.Erp.Domain.Shared.csproj", "{867F0C31-9016-4903-ABAA-EB3A0A11953F}" | |
| 116 | +EndProject | |
| 117 | +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Antis.Erp.SqlSugarCore", "module\antis-erp\Antis.Erp.SqlSugarCore\Antis.Erp.SqlSugarCore.csproj", "{84973327-BF5A-4A7D-8D86-B9712559AD5A}" | |
| 118 | +EndProject | |
| 119 | +Global | |
| 120 | + GlobalSection(SolutionConfigurationPlatforms) = preSolution | |
| 121 | + Debug|Any CPU = Debug|Any CPU | |
| 122 | + Debug|x64 = Debug|x64 | |
| 123 | + Debug|x86 = Debug|x86 | |
| 124 | + Release|Any CPU = Release|Any CPU | |
| 125 | + Release|x64 = Release|x64 | |
| 126 | + Release|x86 = Release|x86 | |
| 127 | + EndGlobalSection | |
| 128 | + GlobalSection(ProjectConfigurationPlatforms) = postSolution | |
| 129 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 130 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 131 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 132 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|x64.Build.0 = Debug|Any CPU | |
| 133 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 134 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|x86.Build.0 = Debug|Any CPU | |
| 135 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 136 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 137 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|x64.ActiveCfg = Release|Any CPU | |
| 138 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|x64.Build.0 = Release|Any CPU | |
| 139 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|x86.ActiveCfg = Release|Any CPU | |
| 140 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|x86.Build.0 = Release|Any CPU | |
| 141 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 142 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 143 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 144 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|x64.Build.0 = Debug|Any CPU | |
| 145 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 146 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|x86.Build.0 = Debug|Any CPU | |
| 147 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 148 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 149 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|x64.ActiveCfg = Release|Any CPU | |
| 150 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|x64.Build.0 = Release|Any CPU | |
| 151 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|x86.ActiveCfg = Release|Any CPU | |
| 152 | + {DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|x86.Build.0 = Release|Any CPU | |
| 153 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 154 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 155 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 156 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|x64.Build.0 = Debug|Any CPU | |
| 157 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 158 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|x86.Build.0 = Debug|Any CPU | |
| 159 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 160 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 161 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|x64.ActiveCfg = Release|Any CPU | |
| 162 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|x64.Build.0 = Release|Any CPU | |
| 163 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|x86.ActiveCfg = Release|Any CPU | |
| 164 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|x86.Build.0 = Release|Any CPU | |
| 165 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 166 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 167 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 168 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|x64.Build.0 = Debug|Any CPU | |
| 169 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 170 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|x86.Build.0 = Debug|Any CPU | |
| 171 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 172 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 173 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|x64.ActiveCfg = Release|Any CPU | |
| 174 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|x64.Build.0 = Release|Any CPU | |
| 175 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|x86.ActiveCfg = Release|Any CPU | |
| 176 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|x86.Build.0 = Release|Any CPU | |
| 177 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 178 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 179 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 180 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|x64.Build.0 = Debug|Any CPU | |
| 181 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 182 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|x86.Build.0 = Debug|Any CPU | |
| 183 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 184 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 185 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|x64.ActiveCfg = Release|Any CPU | |
| 186 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|x64.Build.0 = Release|Any CPU | |
| 187 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|x86.ActiveCfg = Release|Any CPU | |
| 188 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|x86.Build.0 = Release|Any CPU | |
| 189 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 190 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 191 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 192 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|x64.Build.0 = Debug|Any CPU | |
| 193 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 194 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|x86.Build.0 = Debug|Any CPU | |
| 195 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 196 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 197 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|x64.ActiveCfg = Release|Any CPU | |
| 198 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|x64.Build.0 = Release|Any CPU | |
| 199 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|x86.ActiveCfg = Release|Any CPU | |
| 200 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|x86.Build.0 = Release|Any CPU | |
| 201 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 202 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 203 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 204 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|x64.Build.0 = Debug|Any CPU | |
| 205 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 206 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|x86.Build.0 = Debug|Any CPU | |
| 207 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 208 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 209 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|x64.ActiveCfg = Release|Any CPU | |
| 210 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|x64.Build.0 = Release|Any CPU | |
| 211 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|x86.ActiveCfg = Release|Any CPU | |
| 212 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|x86.Build.0 = Release|Any CPU | |
| 213 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 214 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 215 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 216 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|x64.Build.0 = Debug|Any CPU | |
| 217 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 218 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|x86.Build.0 = Debug|Any CPU | |
| 219 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 220 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 221 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|x64.ActiveCfg = Release|Any CPU | |
| 222 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|x64.Build.0 = Release|Any CPU | |
| 223 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|x86.ActiveCfg = Release|Any CPU | |
| 224 | + {FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|x86.Build.0 = Release|Any CPU | |
| 225 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 226 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 227 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 228 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|x64.Build.0 = Debug|Any CPU | |
| 229 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 230 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|x86.Build.0 = Debug|Any CPU | |
| 231 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 232 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 233 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|x64.ActiveCfg = Release|Any CPU | |
| 234 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|x64.Build.0 = Release|Any CPU | |
| 235 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|x86.ActiveCfg = Release|Any CPU | |
| 236 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|x86.Build.0 = Release|Any CPU | |
| 237 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 238 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 239 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 240 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|x64.Build.0 = Debug|Any CPU | |
| 241 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 242 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|x86.Build.0 = Debug|Any CPU | |
| 243 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 244 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 245 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|x64.ActiveCfg = Release|Any CPU | |
| 246 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|x64.Build.0 = Release|Any CPU | |
| 247 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|x86.ActiveCfg = Release|Any CPU | |
| 248 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|x86.Build.0 = Release|Any CPU | |
| 249 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 250 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 251 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 252 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|x64.Build.0 = Debug|Any CPU | |
| 253 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 254 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|x86.Build.0 = Debug|Any CPU | |
| 255 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 256 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 257 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|x64.ActiveCfg = Release|Any CPU | |
| 258 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|x64.Build.0 = Release|Any CPU | |
| 259 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|x86.ActiveCfg = Release|Any CPU | |
| 260 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|x86.Build.0 = Release|Any CPU | |
| 261 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 262 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 263 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 264 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|x64.Build.0 = Debug|Any CPU | |
| 265 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 266 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|x86.Build.0 = Debug|Any CPU | |
| 267 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 268 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 269 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|x64.ActiveCfg = Release|Any CPU | |
| 270 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|x64.Build.0 = Release|Any CPU | |
| 271 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|x86.ActiveCfg = Release|Any CPU | |
| 272 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|x86.Build.0 = Release|Any CPU | |
| 273 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 274 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 275 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 276 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|x64.Build.0 = Debug|Any CPU | |
| 277 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 278 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|x86.Build.0 = Debug|Any CPU | |
| 279 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 280 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 281 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|x64.ActiveCfg = Release|Any CPU | |
| 282 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|x64.Build.0 = Release|Any CPU | |
| 283 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|x86.ActiveCfg = Release|Any CPU | |
| 284 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|x86.Build.0 = Release|Any CPU | |
| 285 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 286 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 287 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 288 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|x64.Build.0 = Debug|Any CPU | |
| 289 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 290 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|x86.Build.0 = Debug|Any CPU | |
| 291 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 292 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 293 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|x64.ActiveCfg = Release|Any CPU | |
| 294 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|x64.Build.0 = Release|Any CPU | |
| 295 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|x86.ActiveCfg = Release|Any CPU | |
| 296 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|x86.Build.0 = Release|Any CPU | |
| 297 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 298 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 299 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 300 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|x64.Build.0 = Debug|Any CPU | |
| 301 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 302 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|x86.Build.0 = Debug|Any CPU | |
| 303 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 304 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 305 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|x64.ActiveCfg = Release|Any CPU | |
| 306 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|x64.Build.0 = Release|Any CPU | |
| 307 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|x86.ActiveCfg = Release|Any CPU | |
| 308 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|x86.Build.0 = Release|Any CPU | |
| 309 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 310 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 311 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 312 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|x64.Build.0 = Debug|Any CPU | |
| 313 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 314 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|x86.Build.0 = Debug|Any CPU | |
| 315 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 316 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 317 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|x64.ActiveCfg = Release|Any CPU | |
| 318 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|x64.Build.0 = Release|Any CPU | |
| 319 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|x86.ActiveCfg = Release|Any CPU | |
| 320 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|x86.Build.0 = Release|Any CPU | |
| 321 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 322 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 323 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 324 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|x64.Build.0 = Debug|Any CPU | |
| 325 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 326 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|x86.Build.0 = Debug|Any CPU | |
| 327 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 328 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 329 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|x64.ActiveCfg = Release|Any CPU | |
| 330 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|x64.Build.0 = Release|Any CPU | |
| 331 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|x86.ActiveCfg = Release|Any CPU | |
| 332 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|x86.Build.0 = Release|Any CPU | |
| 333 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 334 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 335 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 336 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|x64.Build.0 = Debug|Any CPU | |
| 337 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 338 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|x86.Build.0 = Debug|Any CPU | |
| 339 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 340 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 341 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|x64.ActiveCfg = Release|Any CPU | |
| 342 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|x64.Build.0 = Release|Any CPU | |
| 343 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|x86.ActiveCfg = Release|Any CPU | |
| 344 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|x86.Build.0 = Release|Any CPU | |
| 345 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 346 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 347 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 348 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|x64.Build.0 = Debug|Any CPU | |
| 349 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 350 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|x86.Build.0 = Debug|Any CPU | |
| 351 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 352 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 353 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|x64.ActiveCfg = Release|Any CPU | |
| 354 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|x64.Build.0 = Release|Any CPU | |
| 355 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|x86.ActiveCfg = Release|Any CPU | |
| 356 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|x86.Build.0 = Release|Any CPU | |
| 357 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 358 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 359 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 360 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|x64.Build.0 = Debug|Any CPU | |
| 361 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 362 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|x86.Build.0 = Debug|Any CPU | |
| 363 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 364 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 365 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|x64.ActiveCfg = Release|Any CPU | |
| 366 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|x64.Build.0 = Release|Any CPU | |
| 367 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|x86.ActiveCfg = Release|Any CPU | |
| 368 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|x86.Build.0 = Release|Any CPU | |
| 369 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 370 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 371 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 372 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|x64.Build.0 = Debug|Any CPU | |
| 373 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 374 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|x86.Build.0 = Debug|Any CPU | |
| 375 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 376 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 377 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|x64.ActiveCfg = Release|Any CPU | |
| 378 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|x64.Build.0 = Release|Any CPU | |
| 379 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|x86.ActiveCfg = Release|Any CPU | |
| 380 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|x86.Build.0 = Release|Any CPU | |
| 381 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 382 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 383 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 384 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|x64.Build.0 = Debug|Any CPU | |
| 385 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 386 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|x86.Build.0 = Debug|Any CPU | |
| 387 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 388 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 389 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|x64.ActiveCfg = Release|Any CPU | |
| 390 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|x64.Build.0 = Release|Any CPU | |
| 391 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|x86.ActiveCfg = Release|Any CPU | |
| 392 | + {54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|x86.Build.0 = Release|Any CPU | |
| 393 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 394 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 395 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 396 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|x64.Build.0 = Debug|Any CPU | |
| 397 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 398 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|x86.Build.0 = Debug|Any CPU | |
| 399 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 400 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 401 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|x64.ActiveCfg = Release|Any CPU | |
| 402 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|x64.Build.0 = Release|Any CPU | |
| 403 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|x86.ActiveCfg = Release|Any CPU | |
| 404 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|x86.Build.0 = Release|Any CPU | |
| 405 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 406 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 407 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 408 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|x64.Build.0 = Debug|Any CPU | |
| 409 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 410 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|x86.Build.0 = Debug|Any CPU | |
| 411 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 412 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 413 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|x64.ActiveCfg = Release|Any CPU | |
| 414 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|x64.Build.0 = Release|Any CPU | |
| 415 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|x86.ActiveCfg = Release|Any CPU | |
| 416 | + {9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|x86.Build.0 = Release|Any CPU | |
| 417 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 418 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 419 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 420 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Debug|x64.Build.0 = Debug|Any CPU | |
| 421 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 422 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Debug|x86.Build.0 = Debug|Any CPU | |
| 423 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 424 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 425 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Release|x64.ActiveCfg = Release|Any CPU | |
| 426 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Release|x64.Build.0 = Release|Any CPU | |
| 427 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Release|x86.ActiveCfg = Release|Any CPU | |
| 428 | + {17816837-E53B-486B-B796-53C601FE6CD9}.Release|x86.Build.0 = Release|Any CPU | |
| 429 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 430 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 431 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 432 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|x64.Build.0 = Debug|Any CPU | |
| 433 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 434 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|x86.Build.0 = Debug|Any CPU | |
| 435 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 436 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 437 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|x64.ActiveCfg = Release|Any CPU | |
| 438 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|x64.Build.0 = Release|Any CPU | |
| 439 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|x86.ActiveCfg = Release|Any CPU | |
| 440 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|x86.Build.0 = Release|Any CPU | |
| 441 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 442 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 443 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 444 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|x64.Build.0 = Debug|Any CPU | |
| 445 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 446 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|x86.Build.0 = Debug|Any CPU | |
| 447 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 448 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 449 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|x64.ActiveCfg = Release|Any CPU | |
| 450 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|x64.Build.0 = Release|Any CPU | |
| 451 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|x86.ActiveCfg = Release|Any CPU | |
| 452 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|x86.Build.0 = Release|Any CPU | |
| 453 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 454 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 455 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 456 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|x64.Build.0 = Debug|Any CPU | |
| 457 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 458 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|x86.Build.0 = Debug|Any CPU | |
| 459 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 460 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 461 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|x64.ActiveCfg = Release|Any CPU | |
| 462 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|x64.Build.0 = Release|Any CPU | |
| 463 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|x86.ActiveCfg = Release|Any CPU | |
| 464 | + {6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|x86.Build.0 = Release|Any CPU | |
| 465 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 466 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 467 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 468 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|x64.Build.0 = Debug|Any CPU | |
| 469 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 470 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|x86.Build.0 = Debug|Any CPU | |
| 471 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 472 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 473 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|x64.ActiveCfg = Release|Any CPU | |
| 474 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|x64.Build.0 = Release|Any CPU | |
| 475 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|x86.ActiveCfg = Release|Any CPU | |
| 476 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|x86.Build.0 = Release|Any CPU | |
| 477 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 478 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 479 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 480 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Debug|x64.Build.0 = Debug|Any CPU | |
| 481 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 482 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Debug|x86.Build.0 = Debug|Any CPU | |
| 483 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 484 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 485 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Release|x64.ActiveCfg = Release|Any CPU | |
| 486 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Release|x64.Build.0 = Release|Any CPU | |
| 487 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Release|x86.ActiveCfg = Release|Any CPU | |
| 488 | + {00E49781-C6A0-491C-86A1-46F685C90915}.Release|x86.Build.0 = Release|Any CPU | |
| 489 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 490 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 491 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 492 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|x64.Build.0 = Debug|Any CPU | |
| 493 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 494 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|x86.Build.0 = Debug|Any CPU | |
| 495 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 496 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 497 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|x64.ActiveCfg = Release|Any CPU | |
| 498 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|x64.Build.0 = Release|Any CPU | |
| 499 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|x86.ActiveCfg = Release|Any CPU | |
| 500 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|x86.Build.0 = Release|Any CPU | |
| 501 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 502 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 503 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 504 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|x64.Build.0 = Debug|Any CPU | |
| 505 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 506 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|x86.Build.0 = Debug|Any CPU | |
| 507 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 508 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 509 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Release|x64.ActiveCfg = Release|Any CPU | |
| 510 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Release|x64.Build.0 = Release|Any CPU | |
| 511 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Release|x86.ActiveCfg = Release|Any CPU | |
| 512 | + {495C4643-39D4-46E7-BDC8-237589627BE4}.Release|x86.Build.0 = Release|Any CPU | |
| 513 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 514 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 515 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 516 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|x64.Build.0 = Debug|Any CPU | |
| 517 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 518 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|x86.Build.0 = Debug|Any CPU | |
| 519 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 520 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 521 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|x64.ActiveCfg = Release|Any CPU | |
| 522 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|x64.Build.0 = Release|Any CPU | |
| 523 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|x86.ActiveCfg = Release|Any CPU | |
| 524 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|x86.Build.0 = Release|Any CPU | |
| 525 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 526 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 527 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 528 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|x64.Build.0 = Debug|Any CPU | |
| 529 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 530 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|x86.Build.0 = Debug|Any CPU | |
| 531 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 532 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 533 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|x64.ActiveCfg = Release|Any CPU | |
| 534 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|x64.Build.0 = Release|Any CPU | |
| 535 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|x86.ActiveCfg = Release|Any CPU | |
| 536 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|x86.Build.0 = Release|Any CPU | |
| 537 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 538 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 539 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 540 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|x64.Build.0 = Debug|Any CPU | |
| 541 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 542 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|x86.Build.0 = Debug|Any CPU | |
| 543 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 544 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 545 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|x64.ActiveCfg = Release|Any CPU | |
| 546 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|x64.Build.0 = Release|Any CPU | |
| 547 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|x86.ActiveCfg = Release|Any CPU | |
| 548 | + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|x86.Build.0 = Release|Any CPU | |
| 549 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 550 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 551 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 552 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Debug|x64.Build.0 = Debug|Any CPU | |
| 553 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 554 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Debug|x86.Build.0 = Debug|Any CPU | |
| 555 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 556 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 557 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Release|x64.ActiveCfg = Release|Any CPU | |
| 558 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Release|x64.Build.0 = Release|Any CPU | |
| 559 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Release|x86.ActiveCfg = Release|Any CPU | |
| 560 | + {151D2C44-2F56-4407-8FBF-B683B23617F1}.Release|x86.Build.0 = Release|Any CPU | |
| 561 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 562 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 563 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 564 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Debug|x64.Build.0 = Debug|Any CPU | |
| 565 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 566 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Debug|x86.Build.0 = Debug|Any CPU | |
| 567 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 568 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 569 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Release|x64.ActiveCfg = Release|Any CPU | |
| 570 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Release|x64.Build.0 = Release|Any CPU | |
| 571 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Release|x86.ActiveCfg = Release|Any CPU | |
| 572 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A}.Release|x86.Build.0 = Release|Any CPU | |
| 573 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 574 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 575 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 576 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Debug|x64.Build.0 = Debug|Any CPU | |
| 577 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 578 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Debug|x86.Build.0 = Debug|Any CPU | |
| 579 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 580 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 581 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Release|x64.ActiveCfg = Release|Any CPU | |
| 582 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Release|x64.Build.0 = Release|Any CPU | |
| 583 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Release|x86.ActiveCfg = Release|Any CPU | |
| 584 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71}.Release|x86.Build.0 = Release|Any CPU | |
| 585 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 586 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 587 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 588 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Debug|x64.Build.0 = Debug|Any CPU | |
| 589 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 590 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Debug|x86.Build.0 = Debug|Any CPU | |
| 591 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 592 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 593 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Release|x64.ActiveCfg = Release|Any CPU | |
| 594 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Release|x64.Build.0 = Release|Any CPU | |
| 595 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Release|x86.ActiveCfg = Release|Any CPU | |
| 596 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F}.Release|x86.Build.0 = Release|Any CPU | |
| 597 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |
| 598 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Debug|Any CPU.Build.0 = Debug|Any CPU | |
| 599 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Debug|x64.ActiveCfg = Debug|Any CPU | |
| 600 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Debug|x64.Build.0 = Debug|Any CPU | |
| 601 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Debug|x86.ActiveCfg = Debug|Any CPU | |
| 602 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Debug|x86.Build.0 = Debug|Any CPU | |
| 603 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Release|Any CPU.ActiveCfg = Release|Any CPU | |
| 604 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Release|Any CPU.Build.0 = Release|Any CPU | |
| 605 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Release|x64.ActiveCfg = Release|Any CPU | |
| 606 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Release|x64.Build.0 = Release|Any CPU | |
| 607 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Release|x86.ActiveCfg = Release|Any CPU | |
| 608 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A}.Release|x86.Build.0 = Release|Any CPU | |
| 609 | + EndGlobalSection | |
| 610 | + GlobalSection(SolutionProperties) = preSolution | |
| 611 | + HideSolutionNode = FALSE | |
| 612 | + EndGlobalSection | |
| 613 | + GlobalSection(NestedProjects) = preSolution | |
| 614 | + {15913E44-DA92-44B9-9AC5-E9457EA34BF5} = {B782C78B-6C17-49E6-A237-3383BA720766} | |
| 615 | + {DC431ECC-C75D-4B01-8B79-4861948179BB} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 616 | + {9A7BBA40-28D6-4900-9E1D-D627A516EE72} = {B782C78B-6C17-49E6-A237-3383BA720766} | |
| 617 | + {746DBBD6-23E8-4D5D-9D23-E2902BE338BD} = {B782C78B-6C17-49E6-A237-3383BA720766} | |
| 618 | + {51EEBF59-3D37-4681-981D-56F8D8F8968D} = {B782C78B-6C17-49E6-A237-3383BA720766} | |
| 619 | + {7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD} = {B782C78B-6C17-49E6-A237-3383BA720766} | |
| 620 | + {F4D5A496-BFBE-470B-A05B-CB5823B47E72} = {B782C78B-6C17-49E6-A237-3383BA720766} | |
| 621 | + {FD6D6860-3753-4747-8A26-977E4A3001F9} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 622 | + {ECE874D4-F882-4EF4-84A6-A842D9B8FBC5} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 623 | + {1995A019-C8AE-467E-B427-ED57D6CBF44F} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 624 | + {F5011C0D-209B-4A98-BBE3-68157503EEF8} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 625 | + {0A8296A3-C11F-4F13-8E49-6BC8188D4804} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 626 | + {F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 627 | + {9CC7A457-1236-40BA-B47B-E7B710A3F061} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853} | |
| 628 | + {1C360956-8CD8-407E-B87F-D0BD57068EB9} = {9CC7A457-1236-40BA-B47B-E7B710A3F061} | |
| 629 | + {4F02B08D-5FE2-460D-BCA5-DA565151AE30} = {9CC7A457-1236-40BA-B47B-E7B710A3F061} | |
| 630 | + {C04D3F71-1557-46D0-B810-97B1FBB6AB73} = {9CC7A457-1236-40BA-B47B-E7B710A3F061} | |
| 631 | + {A2BB899D-4F9A-4184-81BD-94B938E2AB03} = {9CC7A457-1236-40BA-B47B-E7B710A3F061} | |
| 632 | + {4503A2F9-139D-4CBC-AF11-689C34F0D77B} = {9CC7A457-1236-40BA-B47B-E7B710A3F061} | |
| 633 | + {73CCF2C4-B9FD-44AB-8D4B-0A421805B094} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853} | |
| 634 | + {48806510-8E18-4E1E-9BAF-5B97E88C5FC3} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094} | |
| 635 | + {791AC2FA-50D3-4408-8D68-31DA72F608BE} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 636 | + {499A8C71-7892-42D0-A77E-48756E1EFF16} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853} | |
| 637 | + {FA5BBAA1-08DC-472F-BB2C-5314E59D1556} = {499A8C71-7892-42D0-A77E-48756E1EFF16} | |
| 638 | + {54D8E2BC-591C-4344-A58E-874D49C00B41} = {499A8C71-7892-42D0-A77E-48756E1EFF16} | |
| 639 | + {EFD13211-17B5-400A-B99A-9F6F4E520C1E} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094} | |
| 640 | + {9C8C3C53-3DCE-4516-867E-228858E61B26} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094} | |
| 641 | + {17816837-E53B-486B-B796-53C601FE6CD9} = {499A8C71-7892-42D0-A77E-48756E1EFF16} | |
| 642 | + {FA735055-CBDD-4EFD-B84B-85810DA1425E} = {499A8C71-7892-42D0-A77E-48756E1EFF16} | |
| 643 | + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 644 | + {6B554DCC-3A81-4624-9141-4E39365ADA35} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5} | |
| 645 | + {2D23B44A-DFA3-4C36-8516-4F5AE442403C} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5} | |
| 646 | + {00E49781-C6A0-491C-86A1-46F685C90915} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5} | |
| 647 | + {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853} | |
| 648 | + {6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3} | |
| 649 | + {495C4643-39D4-46E7-BDC8-237589627BE4} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3} | |
| 650 | + {2A31D7CB-BDCC-4253-BA73-273B6B5E1956} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3} | |
| 651 | + {81CEA2ED-917B-41D8-BE0D-39A785B050C0} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 652 | + {862CA181-BEE6-4870-82D2-B662E527ED8C} = {77B949E9-530E-45A5-9657-20F7D5C6875C} | |
| 653 | + {609660A4-AEE6-61D5-25B9-1FDCB688B986} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853} | |
| 654 | + {151D2C44-2F56-4407-8FBF-B683B23617F1} = {609660A4-AEE6-61D5-25B9-1FDCB688B986} | |
| 655 | + {810FE198-77D9-4B2D-A83B-AA43D79B806A} = {609660A4-AEE6-61D5-25B9-1FDCB688B986} | |
| 656 | + {B7E56684-FF7B-40C0-9640-DC83CD59AD71} = {609660A4-AEE6-61D5-25B9-1FDCB688B986} | |
| 657 | + {867F0C31-9016-4903-ABAA-EB3A0A11953F} = {609660A4-AEE6-61D5-25B9-1FDCB688B986} | |
| 658 | + {84973327-BF5A-4A7D-8D86-B9712559AD5A} = {609660A4-AEE6-61D5-25B9-1FDCB688B986} | |
| 659 | + EndGlobalSection | |
| 660 | + GlobalSection(ExtensibilityGlobals) = postSolution | |
| 661 | + SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18} | |
| 662 | + EndGlobalSection | |
| 663 | +EndGlobal | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.Console/Program.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.Client.Console/Program.cs | |
| 1 | +using Microsoft.Extensions.DependencyInjection; | |
| 2 | +using Microsoft.Extensions.Hosting; | |
| 3 | +using Yi.Abp.Client.Console; | |
| 4 | +using Yi.Framework.Rbac.Application.Contracts.IServices; | |
| 5 | + | |
| 6 | +try | |
| 7 | +{ | |
| 8 | + IHost host = Host.CreateDefaultBuilder() | |
| 9 | + .ConfigureServices(async (host, service) => | |
| 10 | + { | |
| 11 | + await service.AddApplicationAsync<YiAbpClientConsoleModule>(); | |
| 12 | + }) | |
| 13 | + .UseAutofac() | |
| 14 | + .Build(); | |
| 15 | + | |
| 16 | + //控制台直接调用 | |
| 17 | + var account = host.Services.GetRequiredService<IAccountService>(); | |
| 18 | + | |
| 19 | + //获取验证码 | |
| 20 | + var data1 = await account.GetCaptchaImageAsync(); | |
| 21 | + | |
| 22 | + //登录 | |
| 23 | + var data2 = await account.PostLoginAsync(new Yi.Framework.Rbac.Application.Contracts.Dtos.Account.LoginInputVo { UserName = "cc", Password = "123456", Code = string.Empty, Uuid = string.Empty }); | |
| 24 | + | |
| 25 | + | |
| 26 | + host.Run(); | |
| 27 | + | |
| 28 | +} | |
| 29 | +catch (Exception ex) | |
| 30 | +{ | |
| 31 | + Console.WriteLine(ex.Message); | |
| 32 | + Console.WriteLine(ex.StackTrace); | |
| 33 | +} | |
| 0 | 34 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.Console/Yi.Abp.Client.Console.csproj
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.Client.Console/Yi.Abp.Client.Console.csproj | |
| 1 | +<Project Sdk="Microsoft.NET.Sdk"> | |
| 2 | + <Import Project="..\..\common.props" /> | |
| 3 | + <PropertyGroup> | |
| 4 | + <OutputType>Exe</OutputType> | |
| 5 | + <TargetFramework>net8.0</TargetFramework> | |
| 6 | + <ImplicitUsings>enable</ImplicitUsings> | |
| 7 | + <Nullable>enable</Nullable> | |
| 8 | + </PropertyGroup> | |
| 9 | + <ItemGroup> | |
| 10 | + <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> | |
| 11 | + <PackageReference Include="Volo.Abp.Autofac" Version="$(AbpVersion)" /> | |
| 12 | + </ItemGroup> | |
| 13 | + <ItemGroup> | |
| 14 | + <ProjectReference Include="..\Yi.Abp.HttpApi.Client\Yi.Abp.HttpApi.Client.csproj" /> | |
| 15 | + </ItemGroup> | |
| 16 | +</Project> | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.Console/YiAbpClientConsoleModule.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.Client.Console/YiAbpClientConsoleModule.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | +using Volo.Abp.Modularity; | |
| 7 | +using Yi.Abp.HttpApi.Client; | |
| 8 | + | |
| 9 | +namespace Yi.Abp.Client.Console | |
| 10 | +{ | |
| 11 | + [DependsOn(typeof(YiAbpHttpApiClientModule))] | |
| 12 | + public class YiAbpClientConsoleModule:AbpModule | |
| 13 | + { | |
| 14 | + } | |
| 15 | +} | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Controllers/AccountController.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Controllers/AccountController.cs | |
| 1 | +using Microsoft.AspNetCore.Mvc; | |
| 2 | +using Yi.Framework.Rbac.Application.Contracts.Dtos.Account; | |
| 3 | +using Yi.Framework.Rbac.Application.Contracts.IServices; | |
| 4 | + | |
| 5 | +namespace Yi.Abp.Client.WebApi.Controllers | |
| 6 | +{ | |
| 7 | + [ApiController] | |
| 8 | + [Route("[controller]")] | |
| 9 | + public class AccountController : ControllerBase | |
| 10 | + { | |
| 11 | + | |
| 12 | + | |
| 13 | + private readonly ILogger<AccountController> _logger; | |
| 14 | + private IAccountService _accountService; | |
| 15 | + public AccountController(ILogger<AccountController> logger, IAccountService accountService) | |
| 16 | + { | |
| 17 | + _logger = logger; | |
| 18 | + _accountService = accountService; | |
| 19 | + } | |
| 20 | + | |
| 21 | + [HttpPost("my-login")] | |
| 22 | + public async Task<IActionResult> Login(LoginInputVo input) | |
| 23 | + { | |
| 24 | + await _accountService.PostLoginAsync(input); | |
| 25 | + return Ok(); | |
| 26 | + } | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + [HttpGet("my-captcha-image")] | |
| 31 | + public async Task<IActionResult> CaptchaImageAsync() | |
| 32 | + { | |
| 33 | + var output = await _accountService.GetCaptchaImageAsync(); | |
| 34 | + return Ok(output); | |
| 35 | + } | |
| 36 | + } | |
| 37 | +} | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Program.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Program.cs | |
| 1 | +using Autofac.Core; | |
| 2 | +using Yi.Abp.Client.WebApi; | |
| 3 | + | |
| 4 | +var builder = WebApplication.CreateBuilder(args); | |
| 5 | + | |
| 6 | +// Add services to the container. | |
| 7 | +builder.Host.UseAutofac(); | |
| 8 | +builder.Services.AddControllers(); | |
| 9 | +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle | |
| 10 | +builder.Services.AddEndpointsApiExplorer(); | |
| 11 | +builder.Services.AddSwaggerGen(); | |
| 12 | +await builder.Services.AddApplicationAsync<YiAbpClientWebApiModule>(); | |
| 13 | +var app = builder.Build(); | |
| 14 | + | |
| 15 | +// Configure the HTTP request pipeline. | |
| 16 | +if (app.Environment.IsDevelopment()) | |
| 17 | +{ | |
| 18 | + app.UseSwagger(); | |
| 19 | + app.UseSwaggerUI(); | |
| 20 | +} | |
| 21 | + | |
| 22 | +app.UseHttpsRedirection(); | |
| 23 | + | |
| 24 | +app.UseAuthorization(); | |
| 25 | + | |
| 26 | +app.MapControllers(); | |
| 27 | + | |
| 28 | +app.Run(); | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Properties/launchSettings.json
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Properties/launchSettings.json | |
| 1 | +{ | |
| 2 | + "$schema": "http://json.schemastore.org/launchsettings.json", | |
| 3 | + "iisSettings": { | |
| 4 | + "windowsAuthentication": false, | |
| 5 | + "anonymousAuthentication": true, | |
| 6 | + "iisExpress": { | |
| 7 | + "applicationUrl": "http://localhost:35597", | |
| 8 | + "sslPort": 44322 | |
| 9 | + } | |
| 10 | + }, | |
| 11 | + "profiles": { | |
| 12 | + "http": { | |
| 13 | + "commandName": "Project", | |
| 14 | + "dotnetRunMessages": true, | |
| 15 | + "launchBrowser": true, | |
| 16 | + "launchUrl": "swagger", | |
| 17 | + "applicationUrl": "http://localhost:5002", | |
| 18 | + "environmentVariables": { | |
| 19 | + "ASPNETCORE_ENVIRONMENT": "Development" | |
| 20 | + } | |
| 21 | + }, | |
| 22 | + "https": { | |
| 23 | + "commandName": "Project", | |
| 24 | + "dotnetRunMessages": true, | |
| 25 | + "launchBrowser": true, | |
| 26 | + "launchUrl": "swagger", | |
| 27 | + "applicationUrl": "https://localhost:7108;http://localhost:5002", | |
| 28 | + "environmentVariables": { | |
| 29 | + "ASPNETCORE_ENVIRONMENT": "Development" | |
| 30 | + } | |
| 31 | + }, | |
| 32 | + "IIS Express": { | |
| 33 | + "commandName": "IISExpress", | |
| 34 | + "launchBrowser": true, | |
| 35 | + "launchUrl": "swagger", | |
| 36 | + "environmentVariables": { | |
| 37 | + "ASPNETCORE_ENVIRONMENT": "Development" | |
| 38 | + } | |
| 39 | + } | |
| 40 | + } | |
| 41 | +} | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Yi.Abp.Client.WebApi.csproj
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Yi.Abp.Client.WebApi.csproj | |
| 1 | +<Project Sdk="Microsoft.NET.Sdk.Web"> | |
| 2 | + <Import Project="..\..\common.props" /> | |
| 3 | + <PropertyGroup> | |
| 4 | + <TargetFramework>net8.0</TargetFramework> | |
| 5 | + <Nullable>enable</Nullable> | |
| 6 | + <ImplicitUsings>enable</ImplicitUsings> | |
| 7 | + </PropertyGroup> | |
| 8 | + | |
| 9 | + <ItemGroup> | |
| 10 | + <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> | |
| 11 | + </ItemGroup> | |
| 12 | + | |
| 13 | + <ItemGroup> | |
| 14 | + <ProjectReference Include="..\Yi.Abp.HttpApi.Client\Yi.Abp.HttpApi.Client.csproj" /> | |
| 15 | + </ItemGroup> | |
| 16 | + | |
| 17 | +</Project> | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/Yi.Abp.Client.WebApi.http
0 → 100644
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/YiAbpClientWebApiModule.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/YiAbpClientWebApiModule.cs | |
| 1 | +using Volo.Abp.Modularity; | |
| 2 | +using Yi.Abp.HttpApi.Client; | |
| 3 | + | |
| 4 | +namespace Yi.Abp.Client.WebApi | |
| 5 | +{ | |
| 6 | + [DependsOn(typeof(YiAbpHttpApiClientModule))] | |
| 7 | + public class YiAbpClientWebApiModule:AbpModule | |
| 8 | + { | |
| 9 | + } | |
| 10 | +} | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/appsettings.Development.json
0 → 100644
Yi.Abp.Net8/client/Yi.Abp.Client.WebApi/appsettings.json
0 → 100644
Yi.Abp.Net8/client/Yi.Abp.HttpApi.Client/Yi.Abp.HttpApi.Client.csproj
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.HttpApi.Client/Yi.Abp.HttpApi.Client.csproj | |
| 1 | +<Project Sdk="Microsoft.NET.Sdk"> | |
| 2 | + <Import Project="..\..\common.props" /> | |
| 3 | + <PropertyGroup> | |
| 4 | + <TargetFramework>net8.0</TargetFramework> | |
| 5 | + <ImplicitUsings>enable</ImplicitUsings> | |
| 6 | + <Nullable>enable</Nullable> | |
| 7 | + <OutputType>Library</OutputType> | |
| 8 | + </PropertyGroup> | |
| 9 | + | |
| 10 | + <ItemGroup> | |
| 11 | + <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> | |
| 12 | + <PackageReference Include="Volo.Abp.Http.Client" Version="$(AbpVersion)" /> | |
| 13 | + <PackageReference Include="Volo.Abp.Autofac" Version="$(AbpVersion)" /> | |
| 14 | + </ItemGroup> | |
| 15 | + | |
| 16 | + <ItemGroup> | |
| 17 | + <ProjectReference Include="..\..\src\Yi.Abp.Application.Contracts\Yi.Abp.Application.Contracts.csproj" /> | |
| 18 | + </ItemGroup> | |
| 19 | + | |
| 20 | +</Project> | ... | ... |
Yi.Abp.Net8/client/Yi.Abp.HttpApi.Client/YiAbpHttpApiClientModule.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/client/Yi.Abp.HttpApi.Client/YiAbpHttpApiClientModule.cs | |
| 1 | +using Microsoft.Extensions.DependencyInjection; | |
| 2 | +using Volo.Abp.Autofac; | |
| 3 | +using Volo.Abp.Http.Client; | |
| 4 | +using Volo.Abp.Modularity; | |
| 5 | +using Yi.Framework.Rbac.Application.Contracts; | |
| 6 | + | |
| 7 | +namespace Yi.Abp.HttpApi.Client | |
| 8 | +{ | |
| 9 | + [DependsOn(typeof(AbpHttpClientModule), | |
| 10 | + typeof(AbpAutofacModule), | |
| 11 | + | |
| 12 | + | |
| 13 | + typeof(YiFrameworkRbacApplicationContractsModule))] | |
| 14 | + public class YiAbpHttpApiClientModule : AbpModule | |
| 15 | + { | |
| 16 | + public override void ConfigureServices(ServiceConfigurationContext context) | |
| 17 | + { | |
| 18 | + //创建动态客户端代理 | |
| 19 | + context.Services.AddHttpClientProxies( | |
| 20 | + typeof(YiFrameworkRbacApplicationContractsModule).Assembly | |
| 21 | + | |
| 22 | + ); | |
| 23 | + Configure<AbpRemoteServiceOptions>(options => | |
| 24 | + { | |
| 25 | + options.RemoteServices.Default = | |
| 26 | + new RemoteServiceConfiguration("http://localhost:19001"); | |
| 27 | + }); | |
| 28 | + } | |
| 29 | + | |
| 30 | + | |
| 31 | + } | |
| 32 | +} | ... | ... |
Yi.Abp.Net8/common.props
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/common.props | |
| 1 | +<Project> | |
| 2 | + <Import Project="usings.props" /> | |
| 3 | + <Import Project="version.props" /> | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + <PropertyGroup> | |
| 9 | + <TargetFramework>net8.0</TargetFramework> | |
| 10 | + <Nullable>enable</Nullable> | |
| 11 | + <ImplicitUsings>enable</ImplicitUsings> | |
| 12 | + </PropertyGroup> | |
| 13 | + | |
| 14 | + <PropertyGroup> | |
| 15 | + <SatelliteResourceLanguages>en;zh-CN</SatelliteResourceLanguages> | |
| 16 | + <LangVersion>latest</LangVersion> | |
| 17 | + <Version>1.0.0</Version> | |
| 18 | + <NoWarn>$(NoWarn);CS1591;CS8618;CS1998;CS8604;CS8620;CS8600;CS8602</NoWarn> | |
| 19 | + <AbpProjectType>app</AbpProjectType> | |
| 20 | + | |
| 21 | + <PublishDocumentationFiles>true</PublishDocumentationFiles> | |
| 22 | + <GenerateDocumentationFile>true</GenerateDocumentationFile> | |
| 23 | + | |
| 24 | + </PropertyGroup> | |
| 25 | + | |
| 26 | + <Target Name="NoWarnOnRazorViewImportedTypeConflicts" BeforeTargets="RazorCoreCompile"> | |
| 27 | + <PropertyGroup> | |
| 28 | + <NoWarn>$(NoWarn);0436</NoWarn> | |
| 29 | + </PropertyGroup> | |
| 30 | + </Target> | |
| 31 | + | |
| 32 | + <ItemGroup> | |
| 33 | + <Content Remove="$(UserProfile)\.nuget\packages\*\*\contentFiles\any\*\*.abppkg*.json" /> | |
| 34 | + </ItemGroup> | |
| 35 | + | |
| 36 | + <ItemGroup> | |
| 37 | + <FrameworkReference Include="Microsoft.AspNetCore.App" /> | |
| 38 | + </ItemGroup> | |
| 39 | + | |
| 40 | +</Project> | |
| 0 | 41 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/end.sh
0 → 100644
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/AuthenticationConstants.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/AuthenticationConstants.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth | |
| 8 | +{ | |
| 9 | + public class AuthenticationConstants | |
| 10 | + { | |
| 11 | + public const string OpenId = "urn:openid"; | |
| 12 | + public const string AccessToken = "urn:access_token"; | |
| 13 | + public const string Name = "urn:name"; | |
| 14 | + | |
| 15 | + } | |
| 16 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/AuthenticationOAuthOptions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/AuthenticationOAuthOptions.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | +using Microsoft.AspNetCore.Authentication.OAuth; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth | |
| 9 | +{ | |
| 10 | + public class AuthenticationOAuthOptions:OAuthOptions | |
| 11 | + { | |
| 12 | + | |
| 13 | + public string RedirectUri { get; set; } | |
| 14 | + } | |
| 15 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/AuthticationErrCodeModel.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/AuthticationErrCodeModel.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | +using Yi.Framework.AspNetCore.Authentication.OAuth.Gitee; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth | |
| 9 | +{ | |
| 10 | + public class AuthticationErrCodeModel | |
| 11 | + { | |
| 12 | + public string error { get; set; } | |
| 13 | + | |
| 14 | + public string error_description { get; set; } | |
| 15 | + | |
| 16 | + public static void VerifyErrResponse(string content) | |
| 17 | + { | |
| 18 | + | |
| 19 | + var model = Newtonsoft.Json.JsonConvert.DeserializeObject<AuthticationErrCodeModel>(content); | |
| 20 | + if (model.error != null) | |
| 21 | + { | |
| 22 | + | |
| 23 | + throw new Exception($"第三方授权返回错误,错误码:【{model.error}】,错误详情:【{model.error_description}】"); | |
| 24 | + } | |
| 25 | + } | |
| 26 | + } | |
| 27 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationConstants.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationConstants.cs | |
| 1 | +/* | |
| 2 | + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | |
| 3 | + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers | |
| 4 | + * for more information concerning the license and the contributors participating to this project. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee; | |
| 8 | + | |
| 9 | +/// <summary> | |
| 10 | +/// Contains constants specific to the <see cref="GiteeAuthenticationHandler"/>. | |
| 11 | +/// </summary> | |
| 12 | +public static class GiteeAuthenticationConstants | |
| 13 | +{ | |
| 14 | + public static class Claims | |
| 15 | + { | |
| 16 | + public const string Url = "urn:gitee:url"; | |
| 17 | + public const string AvatarUrl = "urn:gitee:avatarUrl"; | |
| 18 | + } | |
| 19 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationDefaults.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationDefaults.cs | |
| 1 | +/* | |
| 2 | + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | |
| 3 | + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers | |
| 4 | + * for more information concerning the license and the contributors participating to this project. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee; | |
| 8 | + | |
| 9 | +/// <summary> | |
| 10 | +/// Default values used by the Gitee authentication middleware. | |
| 11 | +/// </summary> | |
| 12 | +public static class GiteeAuthenticationDefaults | |
| 13 | +{ | |
| 14 | + /// <summary> | |
| 15 | + /// Default value for <see cref="AuthenticationScheme.Name"/>. | |
| 16 | + /// </summary> | |
| 17 | + public const string AuthenticationScheme = "Gitee"; | |
| 18 | + | |
| 19 | + /// <summary> | |
| 20 | + /// Default value for <see cref="AuthenticationScheme.DisplayName"/>. | |
| 21 | + /// </summary> | |
| 22 | + public static readonly string DisplayName = "Gitee"; | |
| 23 | + | |
| 24 | + /// <summary> | |
| 25 | + /// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>. | |
| 26 | + /// </summary> | |
| 27 | + public static readonly string Issuer = "Gitee"; | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>. | |
| 31 | + /// </summary> | |
| 32 | + public static readonly string CallbackPath = "/signin-gitee"; | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>. | |
| 36 | + /// </summary> | |
| 37 | + public static readonly string AuthorizationEndpoint = "https://gitee.com/oauth/authorize"; | |
| 38 | + | |
| 39 | + /// <summary> | |
| 40 | + /// Default value for <see cref="OAuthOptions.TokenEndpoint"/>. | |
| 41 | + /// </summary> | |
| 42 | + public static readonly string TokenEndpoint = "https://gitee.com/oauth/token"; | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>. | |
| 46 | + /// </summary> | |
| 47 | + public static readonly string UserInformationEndpoint = "https://gitee.com/api/v5/user"; | |
| 48 | + | |
| 49 | + /// <summary> | |
| 50 | + /// Default value for <see cref="GiteeAuthenticationOptions.UserEmailsEndpoint"/>. | |
| 51 | + /// </summary> | |
| 52 | + public static readonly string UserEmailsEndpoint = "https://gitee.com/api/v5/emails"; | |
| 53 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationExtensions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationExtensions.cs | |
| 1 | +/* | |
| 2 | + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | |
| 3 | + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers | |
| 4 | + * for more information concerning the license and the contributors participating to this project. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +using JetBrains.Annotations; | |
| 8 | +using Microsoft.AspNetCore.Authentication; | |
| 9 | + | |
| 10 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee; | |
| 11 | + | |
| 12 | +/// <summary> | |
| 13 | +/// Extension methods to add Gitee authentication capabilities to an HTTP application pipeline. | |
| 14 | +/// </summary> | |
| 15 | +public static class GiteeAuthenticationExtensions | |
| 16 | +{ | |
| 17 | + /// <summary> | |
| 18 | + /// Adds <see cref="GiteeAuthenticationHandler"/> to the specified | |
| 19 | + /// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities. | |
| 20 | + /// </summary> | |
| 21 | + /// <param name="builder">The authentication builder.</param> | |
| 22 | + /// <returns>The <see cref="AuthenticationBuilder"/>.</returns> | |
| 23 | + public static AuthenticationBuilder AddGitee([NotNull] this AuthenticationBuilder builder) | |
| 24 | + { | |
| 25 | + return builder.AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, options => { }); | |
| 26 | + } | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// Adds <see cref="GiteeAuthenticationHandler"/> to the specified | |
| 30 | + /// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities. | |
| 31 | + /// </summary> | |
| 32 | + /// <param name="builder">The authentication builder.</param> | |
| 33 | + /// <param name="configuration">The delegate used to configure the OpenID 2.0 options.</param> | |
| 34 | + /// <returns>The <see cref="AuthenticationBuilder"/>.</returns> | |
| 35 | + public static AuthenticationBuilder AddGitee( | |
| 36 | + [NotNull] this AuthenticationBuilder builder, | |
| 37 | + [NotNull] Action<GiteeAuthenticationOptions> configuration) | |
| 38 | + { | |
| 39 | + return builder.AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, configuration); | |
| 40 | + } | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// Adds <see cref="GiteeAuthenticationHandler"/> to the specified | |
| 44 | + /// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities. | |
| 45 | + /// </summary> | |
| 46 | + /// <param name="builder">The authentication builder.</param> | |
| 47 | + /// <param name="scheme">The authentication scheme associated with this instance.</param> | |
| 48 | + /// <param name="configuration">The delegate used to configure the Gitee options.</param> | |
| 49 | + /// <returns>The <see cref="AuthenticationBuilder"/>.</returns> | |
| 50 | + public static AuthenticationBuilder AddGitee( | |
| 51 | + [NotNull] this AuthenticationBuilder builder, | |
| 52 | + [NotNull] string scheme, | |
| 53 | + [NotNull] Action<GiteeAuthenticationOptions> configuration) | |
| 54 | + { | |
| 55 | + return builder.AddGitee(scheme, GiteeAuthenticationDefaults.DisplayName, configuration); | |
| 56 | + } | |
| 57 | + | |
| 58 | + /// <summary> | |
| 59 | + /// Adds <see cref="GiteeAuthenticationHandler"/> to the specified | |
| 60 | + /// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities. | |
| 61 | + /// </summary> | |
| 62 | + /// <param name="builder">The authentication builder.</param> | |
| 63 | + /// <param name="scheme">The authentication scheme associated with this instance.</param> | |
| 64 | + /// <param name="caption">The optional display name associated with this instance.</param> | |
| 65 | + /// <param name="configuration">The delegate used to configure the Gitee options.</param> | |
| 66 | + /// <returns>The <see cref="AuthenticationBuilder"/>.</returns> | |
| 67 | + public static AuthenticationBuilder AddGitee( | |
| 68 | + [NotNull] this AuthenticationBuilder builder, | |
| 69 | + [NotNull] string scheme, | |
| 70 | + [CanBeNull] string caption, | |
| 71 | + [NotNull] Action<GiteeAuthenticationOptions> configuration) | |
| 72 | + { | |
| 73 | + return builder.AddScheme<GiteeAuthenticationOptions, GiteeAuthenticationHandler>(scheme, caption, configuration); | |
| 74 | + } | |
| 75 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationHandler.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationHandler.cs | |
| 1 | +using System.Security.Claims; | |
| 2 | +using System.Text.Encodings.Web; | |
| 3 | +using Microsoft.Extensions.Logging; | |
| 4 | +using Microsoft.Extensions.Options; | |
| 5 | +using static Yi.Framework.AspNetCore.Authentication.OAuth.Gitee.GiteeAuthenticationConstants; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee | |
| 8 | +{ | |
| 9 | + public class GiteeAuthenticationHandler : OauthAuthenticationHandler<GiteeAuthenticationOptions> | |
| 10 | + { | |
| 11 | + public GiteeAuthenticationHandler(IOptionsMonitor<GiteeAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder, httpClientFactory) | |
| 12 | + { | |
| 13 | + } | |
| 14 | + | |
| 15 | + public override string AuthenticationSchemeNmae => GiteeAuthenticationDefaults.AuthenticationScheme; | |
| 16 | + | |
| 17 | + protected override async Task<List<Claim>> GetAuthTicketAsync(string code) | |
| 18 | + { | |
| 19 | + //获取 accessToken | |
| 20 | + var tokenQueryKv = new List<KeyValuePair<string, string?>>() | |
| 21 | + { | |
| 22 | + new KeyValuePair<string, string?>("grant_type","authorization_code"), | |
| 23 | + new KeyValuePair<string, string?>("client_id",Options.ClientId), | |
| 24 | + new KeyValuePair<string, string?>("client_secret",Options.ClientSecret), | |
| 25 | + new KeyValuePair<string, string?>("redirect_uri",Options.RedirectUri), | |
| 26 | + new KeyValuePair<string, string?>("code",code) | |
| 27 | + }; | |
| 28 | + var tokenModel = await SendHttpRequestAsync<GiteeAuthticationcationTokenResponse>(GiteeAuthenticationDefaults.TokenEndpoint, tokenQueryKv,HttpMethod.Post); | |
| 29 | + | |
| 30 | + //获取 userInfo | |
| 31 | + var userInfoQueryKv = new List<KeyValuePair<string, string?>>() | |
| 32 | + { | |
| 33 | + new KeyValuePair<string, string?>("access_token",tokenModel.access_token), | |
| 34 | + }; | |
| 35 | + var userInfoMdoel = await SendHttpRequestAsync<GiteeAuthticationcationUserInfoResponse>(GiteeAuthenticationDefaults.UserInformationEndpoint, userInfoQueryKv); | |
| 36 | + | |
| 37 | + List<Claim> claims = new List<Claim>() | |
| 38 | + { | |
| 39 | + new Claim(Claims.AvatarUrl, userInfoMdoel.avatar_url), | |
| 40 | + new Claim(Claims.Url, userInfoMdoel.url), | |
| 41 | + | |
| 42 | + new Claim(AuthenticationConstants.OpenId,userInfoMdoel.id.ToString()), | |
| 43 | + new Claim(AuthenticationConstants.Name, userInfoMdoel.name), | |
| 44 | + new Claim(AuthenticationConstants.AccessToken, tokenModel.access_token) | |
| 45 | + }; | |
| 46 | + return claims; | |
| 47 | + } | |
| 48 | + } | |
| 49 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationOptions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthenticationOptions.cs | |
| 1 | +/* | |
| 2 | + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | |
| 3 | + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers | |
| 4 | + * for more information concerning the license and the contributors participating to this project. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +using System.Security.Claims; | |
| 8 | +using Microsoft.AspNetCore.Authentication; | |
| 9 | +using static Yi.Framework.AspNetCore.Authentication.OAuth.Gitee.GiteeAuthenticationConstants; | |
| 10 | + | |
| 11 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee; | |
| 12 | + | |
| 13 | +/// <summary> | |
| 14 | +/// Defines a set of options used by <see cref="GiteeAuthenticationHandler"/>. | |
| 15 | +/// </summary> | |
| 16 | +public class GiteeAuthenticationOptions : AuthenticationOAuthOptions | |
| 17 | +{ | |
| 18 | + public GiteeAuthenticationOptions() | |
| 19 | + { | |
| 20 | + ClaimsIssuer = GiteeAuthenticationDefaults.Issuer; | |
| 21 | + | |
| 22 | + CallbackPath = GiteeAuthenticationDefaults.CallbackPath; | |
| 23 | + | |
| 24 | + AuthorizationEndpoint = GiteeAuthenticationDefaults.AuthorizationEndpoint; | |
| 25 | + TokenEndpoint = GiteeAuthenticationDefaults.TokenEndpoint; | |
| 26 | + UserInformationEndpoint = GiteeAuthenticationDefaults.UserInformationEndpoint; | |
| 27 | + UserEmailsEndpoint = GiteeAuthenticationDefaults.UserEmailsEndpoint; | |
| 28 | + | |
| 29 | + Scope.Add("user_info"); | |
| 30 | + Scope.Add("emails"); | |
| 31 | + | |
| 32 | + ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); | |
| 33 | + ClaimActions.MapJsonKey(ClaimTypes.Name, "login"); | |
| 34 | + ClaimActions.MapJsonKey(ClaimTypes.Email, "email"); | |
| 35 | + ClaimActions.MapJsonKey(ClaimTypes.Name, "name"); | |
| 36 | + ClaimActions.MapJsonKey(Claims.Url, "url"); | |
| 37 | + } | |
| 38 | + | |
| 39 | + /// <summary> | |
| 40 | + /// Gets or sets the address of the endpoint exposing | |
| 41 | + /// the email addresses associated with the logged in user. | |
| 42 | + /// </summary> | |
| 43 | + public string UserEmailsEndpoint { get; set; } | |
| 44 | +} | |
| 0 | 45 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthticationcationHttpModel.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Gitee/GiteeAuthticationcationHttpModel.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee | |
| 8 | +{ | |
| 9 | + public class GiteeAuthticationcationTokenResponse | |
| 10 | + { | |
| 11 | + public string access_token { get; set; } | |
| 12 | + public string token_type { get; set; } | |
| 13 | + public int expires_in { get; set; } | |
| 14 | + public string refresh_token { get; set; } | |
| 15 | + public string scope { get; set; } | |
| 16 | + public long created_at { get; set; } | |
| 17 | + } | |
| 18 | + | |
| 19 | + | |
| 20 | + public class GiteeAuthticationcationOpenIdResponse | |
| 21 | + { | |
| 22 | + public string client_id { get; set; } | |
| 23 | + | |
| 24 | + public string openid { get; set; } | |
| 25 | + | |
| 26 | + } | |
| 27 | + | |
| 28 | + public class GiteeAuthticationcationUserInfoResponse | |
| 29 | + { | |
| 30 | + /// <summary> | |
| 31 | + /// 也可以等于openId | |
| 32 | + /// </summary> | |
| 33 | + public int id { get; set; } | |
| 34 | + public string login { get; set; } | |
| 35 | + public string name { get; set; } | |
| 36 | + public string avatar_url { get; set; } | |
| 37 | + public string url { get; set; } | |
| 38 | + public string html_url { get; set; } | |
| 39 | + public string remark { get; set; } | |
| 40 | + public string followers_url { get; set; } | |
| 41 | + public string following_url { get; set; } | |
| 42 | + public string gists_url { get; set; } | |
| 43 | + public string starred_url { get; set; } | |
| 44 | + public string subscriptions_url { get; set; } | |
| 45 | + public string organizations_url { get; set; } | |
| 46 | + public string repos_url { get; set; } | |
| 47 | + public string events_url { get; set; } | |
| 48 | + public string received_events_url { get; set; } | |
| 49 | + public string type { get; set; } | |
| 50 | + public string blog { get; set; } | |
| 51 | + public string weibo { get; set; } | |
| 52 | + public string bio { get; set; } | |
| 53 | + public int public_repos { get; set; } | |
| 54 | + public int public_gists { get; set; } | |
| 55 | + public int followers { get; set; } | |
| 56 | + public int following { get; set; } | |
| 57 | + public int stared { get; set; } | |
| 58 | + public int watched { get; set; } | |
| 59 | + public DateTime created_at { get; set; } | |
| 60 | + public DateTime updated_at { get; set; } | |
| 61 | + public string email { get; set; } | |
| 62 | + } | |
| 63 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/OAuthAuthenticationHandler.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/OAuthAuthenticationHandler.cs | |
| 1 | +using System.Security.Claims; | |
| 2 | +using System.Text.Encodings.Web; | |
| 3 | +using Microsoft.AspNetCore.Authentication; | |
| 4 | +using Microsoft.AspNetCore.WebUtilities; | |
| 5 | +using Microsoft.Extensions.Logging; | |
| 6 | +using Microsoft.Extensions.Options; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth | |
| 9 | +{ | |
| 10 | + public abstract class OauthAuthenticationHandler<TOptions> : AuthenticationHandler<TOptions> where TOptions : AuthenticationSchemeOptions, new() | |
| 11 | + { | |
| 12 | + public abstract string AuthenticationSchemeNmae { get; } | |
| 13 | + private AuthenticationScheme _scheme; | |
| 14 | + | |
| 15 | + public OauthAuthenticationHandler(IOptionsMonitor<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder) | |
| 16 | + { | |
| 17 | + HttpClientFactory = httpClientFactory; | |
| 18 | + HttpClient = HttpClientFactory.CreateClient(); | |
| 19 | + } | |
| 20 | + | |
| 21 | + | |
| 22 | + protected IHttpClientFactory HttpClientFactory { get; } | |
| 23 | + | |
| 24 | + protected HttpClient HttpClient { get; } | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 生成认证票据 | |
| 30 | + /// </summary> | |
| 31 | + /// <returns></returns> | |
| 32 | + private AuthenticationTicket TicketConver(List<Claim> claims) | |
| 33 | + { | |
| 34 | + var claimsIdentity = new ClaimsIdentity(claims.ToArray(), AuthenticationSchemeNmae); | |
| 35 | + var principal = new ClaimsPrincipal(claimsIdentity); | |
| 36 | + return new AuthenticationTicket(principal, AuthenticationSchemeNmae); | |
| 37 | + } | |
| 38 | + | |
| 39 | + protected async Task<HttpModel> SendHttpRequestAsync<HttpModel>(string url, IEnumerable<KeyValuePair<string, string?>> query, HttpMethod? httpMethod = null) | |
| 40 | + { | |
| 41 | + httpMethod = httpMethod ?? HttpMethod.Get; | |
| 42 | + | |
| 43 | + var queryUrl = QueryHelpers.AddQueryString(url, query); | |
| 44 | + HttpResponseMessage response = null; | |
| 45 | + if (httpMethod == HttpMethod.Get) | |
| 46 | + { | |
| 47 | + response = await HttpClient.GetAsync(queryUrl); | |
| 48 | + } | |
| 49 | + else if (httpMethod == HttpMethod.Post) | |
| 50 | + { | |
| 51 | + response = await HttpClient.PostAsync(queryUrl, null); | |
| 52 | + } | |
| 53 | + | |
| 54 | + var content = await response.Content.ReadAsStringAsync(); | |
| 55 | + if (!response.IsSuccessStatusCode) | |
| 56 | + { | |
| 57 | + throw new Exception($"授权服务器请求错误,请求地址:{queryUrl},错误信息:{content}"); | |
| 58 | + } | |
| 59 | + VerifyErrResponse(content); | |
| 60 | + var model = Newtonsoft.Json.JsonConvert.DeserializeObject<HttpModel>(content); | |
| 61 | + return model!; | |
| 62 | + } | |
| 63 | + | |
| 64 | + protected virtual void VerifyErrResponse(string content) | |
| 65 | + { | |
| 66 | + AuthticationErrCodeModel.VerifyErrResponse(content); | |
| 67 | + } | |
| 68 | + | |
| 69 | + protected abstract Task<List<Claim>> GetAuthTicketAsync(string code); | |
| 70 | + | |
| 71 | + | |
| 72 | + protected override async Task<AuthenticateResult> HandleAuthenticateAsync() | |
| 73 | + { | |
| 74 | + if (!Context.Request.Query.ContainsKey("code")) | |
| 75 | + { | |
| 76 | + return AuthenticateResult.Fail("回调未包含code参数"); | |
| 77 | + } | |
| 78 | + var code = Context.Request.Query["code"].ToString(); | |
| 79 | + | |
| 80 | + List<Claim> authTicket = null; | |
| 81 | + try | |
| 82 | + { | |
| 83 | + authTicket = await GetAuthTicketAsync(code); | |
| 84 | + } | |
| 85 | + catch (Exception ex) | |
| 86 | + { | |
| 87 | + return AuthenticateResult.Fail(ex.Message ?? "未知错误"); | |
| 88 | + } | |
| 89 | + //成功 | |
| 90 | + var result = AuthenticateResult.Success(TicketConver(authTicket)); | |
| 91 | + return result; | |
| 92 | + } | |
| 93 | + } | |
| 94 | +} | |
| 95 | + | |
| 96 | + | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationConstants.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationConstants.cs | |
| 1 | +/* | |
| 2 | + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | |
| 3 | + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers | |
| 4 | + * for more information concerning the license and the contributors participating to this project. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ; | |
| 8 | + | |
| 9 | +/// <summary> | |
| 10 | +/// Contains constants specific to the <see cref="QQAuthenticationHandler"/>. | |
| 11 | +/// </summary> | |
| 12 | +public static class QQAuthenticationConstants | |
| 13 | +{ | |
| 14 | + public static class Claims | |
| 15 | + { | |
| 16 | + public const string AvatarFullUrl = "urn:qq:avatar_full"; | |
| 17 | + public const string AvatarUrl = "urn:qq:avatar"; | |
| 18 | + public const string PictureFullUrl = "urn:qq:picture_full"; | |
| 19 | + public const string PictureMediumUrl = "urn:qq:picture_medium"; | |
| 20 | + public const string PictureUrl = "urn:qq:picture"; | |
| 21 | + public const string UnionId = "urn:qq:unionid"; | |
| 22 | + } | |
| 23 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationDefaults.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationDefaults.cs | |
| 1 | +/* | |
| 2 | + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | |
| 3 | + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers | |
| 4 | + * for more information concerning the license and the contributors participating to this project. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ; | |
| 8 | + | |
| 9 | +/// <summary> | |
| 10 | +/// Default values for QQ authentication. | |
| 11 | +/// </summary> | |
| 12 | +public static class QQAuthenticationDefaults | |
| 13 | +{ | |
| 14 | + /// <summary> | |
| 15 | + /// Default value for <see cref="AuthenticationScheme.Name"/>. | |
| 16 | + /// </summary> | |
| 17 | + public const string AuthenticationScheme = "QQ"; | |
| 18 | + | |
| 19 | + /// <summary> | |
| 20 | + /// Default value for <see cref="AuthenticationScheme.DisplayName"/>. | |
| 21 | + /// </summary> | |
| 22 | + public static readonly string DisplayName = "QQ"; | |
| 23 | + | |
| 24 | + /// <summary> | |
| 25 | + /// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>. | |
| 26 | + /// </summary> | |
| 27 | + public static readonly string Issuer = "QQ"; | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>. | |
| 31 | + /// </summary> | |
| 32 | + public static readonly string CallbackPath = "/signin-qq"; | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>. | |
| 36 | + /// </summary> | |
| 37 | + public static readonly string AuthorizationEndpoint = "https://graph.qq.com/oauth2.0/authorize"; | |
| 38 | + | |
| 39 | + /// <summary> | |
| 40 | + /// Default value for <see cref="OAuthOptions.TokenEndpoint"/>. | |
| 41 | + /// </summary> | |
| 42 | + public static readonly string TokenEndpoint = "https://graph.qq.com/oauth2.0/token"; | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// Default value for <see cref="QQAuthenticationOptions.UserIdentificationEndpoint"/>. | |
| 46 | + /// </summary> | |
| 47 | + public static readonly string UserIdentificationEndpoint = "https://graph.qq.com/oauth2.0/me"; | |
| 48 | + | |
| 49 | + /// <summary> | |
| 50 | + /// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>. | |
| 51 | + /// </summary> | |
| 52 | + public static readonly string UserInformationEndpoint = "https://graph.qq.com/user/get_user_info"; | |
| 53 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationExtensions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationExtensions.cs | |
| 1 | +/* | |
| 2 | + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | |
| 3 | + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers | |
| 4 | + * for more information concerning the license and the contributors participating to this project. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +using JetBrains.Annotations; | |
| 8 | +using Microsoft.AspNetCore.Authentication; | |
| 9 | +using Microsoft.Extensions.DependencyInjection; | |
| 10 | + | |
| 11 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ; | |
| 12 | + | |
| 13 | +/// <summary> | |
| 14 | +/// Extension methods to add QQ authentication capabilities to an HTTP application pipeline. | |
| 15 | +/// </summary> | |
| 16 | +public static class QQAuthenticationExtensions | |
| 17 | +{ | |
| 18 | + /// <summary> | |
| 19 | + /// Adds <see cref="QQAuthenticationHandler"/> to the specified | |
| 20 | + /// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities. | |
| 21 | + /// </summary> | |
| 22 | + /// <param name="builder">The authentication builder.</param> | |
| 23 | + /// <returns>The <see cref="AuthenticationBuilder"/>.</returns> | |
| 24 | + public static AuthenticationBuilder AddQQ([NotNull] this AuthenticationBuilder builder) | |
| 25 | + { | |
| 26 | + return builder.AddQQ(QQAuthenticationDefaults.AuthenticationScheme, options => { }); | |
| 27 | + } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// Adds <see cref="QQAuthenticationHandler"/> to the specified | |
| 31 | + /// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities. | |
| 32 | + /// </summary> | |
| 33 | + /// <param name="builder">The authentication builder.</param> | |
| 34 | + /// <param name="configuration">The delegate used to configure the OpenID 2.0 options.</param> | |
| 35 | + /// <returns>The <see cref="AuthenticationBuilder"/>.</returns> | |
| 36 | + public static AuthenticationBuilder AddQQ( | |
| 37 | + [NotNull] this AuthenticationBuilder builder, | |
| 38 | + [NotNull] Action<QQAuthenticationOptions> configuration) | |
| 39 | + { | |
| 40 | + return builder.AddQQ(QQAuthenticationDefaults.AuthenticationScheme, configuration); | |
| 41 | + } | |
| 42 | + | |
| 43 | + /// <summary> | |
| 44 | + /// Adds <see cref="QQAuthenticationHandler"/> to the specified | |
| 45 | + /// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities. | |
| 46 | + /// </summary> | |
| 47 | + /// <param name="builder">The authentication builder.</param> | |
| 48 | + /// <param name="scheme">The authentication scheme associated with this instance.</param> | |
| 49 | + /// <param name="configuration">The delegate used to configure the QQ options.</param> | |
| 50 | + /// <returns>The <see cref="AuthenticationBuilder"/>.</returns> | |
| 51 | + public static AuthenticationBuilder AddQQ( | |
| 52 | + [NotNull] this AuthenticationBuilder builder, | |
| 53 | + [NotNull] string scheme, | |
| 54 | + [NotNull] Action<QQAuthenticationOptions> configuration) | |
| 55 | + { | |
| 56 | + return builder.AddQQ(scheme, QQAuthenticationDefaults.DisplayName, configuration); | |
| 57 | + } | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// Adds <see cref="QQAuthenticationHandler"/> to the specified | |
| 61 | + /// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities. | |
| 62 | + /// </summary> | |
| 63 | + /// <param name="builder">The authentication builder.</param> | |
| 64 | + /// <param name="scheme">The authentication scheme associated with this instance.</param> | |
| 65 | + /// <param name="caption">The optional display name associated with this instance.</param> | |
| 66 | + /// <param name="configuration">The delegate used to configure the QQ options.</param> | |
| 67 | + /// <returns>The <see cref="AuthenticationBuilder"/>.</returns> | |
| 68 | + public static AuthenticationBuilder AddQQ( | |
| 69 | + [NotNull] this AuthenticationBuilder builder, | |
| 70 | + [NotNull] string scheme, | |
| 71 | + [CanBeNull] string caption, | |
| 72 | + [NotNull] Action<QQAuthenticationOptions> configuration) | |
| 73 | + { | |
| 74 | + return builder.AddScheme<QQAuthenticationOptions, QQAuthenticationHandler>(scheme, caption, configuration); | |
| 75 | + | |
| 76 | + } | |
| 77 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationHandler.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationHandler.cs | |
| 1 | +using System.Security.Claims; | |
| 2 | +using System.Text.Encodings.Web; | |
| 3 | +using Microsoft.Extensions.Logging; | |
| 4 | +using Microsoft.Extensions.Options; | |
| 5 | +using static Yi.Framework.AspNetCore.Authentication.OAuth.QQ.QQAuthenticationConstants; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ | |
| 8 | +{ | |
| 9 | + public class QQAuthenticationHandler : OauthAuthenticationHandler<QQAuthenticationOptions> | |
| 10 | + { | |
| 11 | + public QQAuthenticationHandler(IOptionsMonitor<QQAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder, httpClientFactory) | |
| 12 | + { | |
| 13 | + } | |
| 14 | + | |
| 15 | + public override string AuthenticationSchemeNmae => QQAuthenticationDefaults.AuthenticationScheme; | |
| 16 | + | |
| 17 | + protected override async Task<List<Claim>> GetAuthTicketAsync(string code) | |
| 18 | + { | |
| 19 | + | |
| 20 | + //获取 accessToken | |
| 21 | + var tokenQueryKv = new List<KeyValuePair<string, string?>>() | |
| 22 | + { | |
| 23 | + new KeyValuePair<string, string?>("grant_type","authorization_code"), | |
| 24 | + new KeyValuePair<string, string?>("client_id",Options.ClientId), | |
| 25 | + new KeyValuePair<string, string?>("client_secret",Options.ClientSecret), | |
| 26 | + new KeyValuePair<string, string?>("redirect_uri",Options.RedirectUri), | |
| 27 | + new KeyValuePair<string, string?>("fmt","json"), | |
| 28 | + new KeyValuePair<string, string?>("need_openid","1"), | |
| 29 | + new KeyValuePair<string, string?>("code",code) | |
| 30 | + }; | |
| 31 | + var tokenModel = await SendHttpRequestAsync<QQAuthticationcationTokenResponse>(QQAuthenticationDefaults.TokenEndpoint, tokenQueryKv); | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + //获取 userInfo | |
| 36 | + var userInfoQueryKv = new List<KeyValuePair<string, string?>>() | |
| 37 | + { | |
| 38 | + new KeyValuePair<string, string?>("access_token",tokenModel.access_token), | |
| 39 | + new KeyValuePair<string, string?>("oauth_consumer_key",Options.ClientId), | |
| 40 | + new KeyValuePair<string, string?>("openid",tokenModel.openid), | |
| 41 | + }; | |
| 42 | + | |
| 43 | + var userInfoMdoel = await SendHttpRequestAsync<QQAuthticationcationUserInfoResponse>(QQAuthenticationDefaults.UserInformationEndpoint, userInfoQueryKv); | |
| 44 | + | |
| 45 | + | |
| 46 | + List<Claim> claims = new List<Claim>() | |
| 47 | + { | |
| 48 | + | |
| 49 | + new Claim(Claims.AvatarFullUrl, userInfoMdoel.figureurl_qq_2), | |
| 50 | + new Claim(Claims.AvatarUrl, userInfoMdoel.figureurl_qq_1), | |
| 51 | + new Claim(Claims.PictureFullUrl, userInfoMdoel.figureurl_2), | |
| 52 | + new Claim(Claims.PictureMediumUrl, userInfoMdoel.figureurl_qq_1), | |
| 53 | + new Claim(Claims.PictureUrl, userInfoMdoel.figureurl), | |
| 54 | + | |
| 55 | + new Claim(AuthenticationConstants.OpenId, tokenModel.openid), | |
| 56 | + new Claim(AuthenticationConstants.Name, userInfoMdoel.nickname), | |
| 57 | + new Claim(AuthenticationConstants.AccessToken, tokenModel.access_token), | |
| 58 | + | |
| 59 | + }; | |
| 60 | + return claims; | |
| 61 | + | |
| 62 | + } | |
| 63 | + } | |
| 64 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationOptions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthenticationOptions.cs | |
| 1 | +/* | |
| 2 | + * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) | |
| 3 | + * See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers | |
| 4 | + * for more information concerning the license and the contributors participating to this project. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +using System.Security.Claims; | |
| 8 | +using Microsoft.AspNetCore.Authentication; | |
| 9 | +using static Yi.Framework.AspNetCore.Authentication.OAuth.QQ.QQAuthenticationConstants; | |
| 10 | + | |
| 11 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ; | |
| 12 | + | |
| 13 | +/// <summary> | |
| 14 | +/// Defines a set of options used by <see cref="QQAuthenticationHandler"/>. | |
| 15 | +/// </summary> | |
| 16 | +public class QQAuthenticationOptions : AuthenticationOAuthOptions | |
| 17 | +{ | |
| 18 | + public QQAuthenticationOptions() | |
| 19 | + { | |
| 20 | + ClaimsIssuer = QQAuthenticationDefaults.Issuer; | |
| 21 | + CallbackPath = QQAuthenticationDefaults.CallbackPath; | |
| 22 | + | |
| 23 | + AuthorizationEndpoint = QQAuthenticationDefaults.AuthorizationEndpoint; | |
| 24 | + TokenEndpoint = QQAuthenticationDefaults.TokenEndpoint; | |
| 25 | + UserIdentificationEndpoint = QQAuthenticationDefaults.UserIdentificationEndpoint; | |
| 26 | + UserInformationEndpoint = QQAuthenticationDefaults.UserInformationEndpoint; | |
| 27 | + | |
| 28 | + Scope.Add("get_user_info"); | |
| 29 | + | |
| 30 | + ClaimActions.MapJsonKey(ClaimTypes.Name, "nickname"); | |
| 31 | + ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender"); | |
| 32 | + ClaimActions.MapJsonKey(Claims.PictureUrl, "figureurl"); | |
| 33 | + ClaimActions.MapJsonKey(Claims.PictureMediumUrl, "figureurl_1"); | |
| 34 | + ClaimActions.MapJsonKey(Claims.PictureFullUrl, "figureurl_2"); | |
| 35 | + ClaimActions.MapJsonKey(Claims.AvatarUrl, "figureurl_qq_1"); | |
| 36 | + ClaimActions.MapJsonKey(Claims.AvatarFullUrl, "figureurl_qq_2"); | |
| 37 | + } | |
| 38 | + | |
| 39 | + /// <summary> | |
| 40 | + /// 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. | |
| 41 | + /// </summary> | |
| 42 | + public bool ApplyForUnionId { get; set; } | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// Gets or sets the URL of the user identification endpoint (a.k.a. the "OpenID endpoint"). | |
| 46 | + /// </summary> | |
| 47 | + public string UserIdentificationEndpoint { get; set; } | |
| 48 | + | |
| 49 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthticationcationHttpModel.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/QQ/QQAuthticationcationHttpModel.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ | |
| 8 | +{ | |
| 9 | + public class QQAuthticationcationTokenResponse | |
| 10 | + { | |
| 11 | + public string access_token { get; set; } | |
| 12 | + | |
| 13 | + public string expires_in { get; set; } | |
| 14 | + | |
| 15 | + public string refresh_token { get; set; } | |
| 16 | + | |
| 17 | + public string openid { get; set; } | |
| 18 | + } | |
| 19 | + | |
| 20 | + | |
| 21 | + public class QQAuthticationcationOpenIdResponse | |
| 22 | + { | |
| 23 | + public string client_id { get; set; } | |
| 24 | + | |
| 25 | + public string openid { get; set; } | |
| 26 | + | |
| 27 | + } | |
| 28 | + | |
| 29 | + public class QQAuthticationcationUserInfoResponse | |
| 30 | + { | |
| 31 | + // 返回码 | |
| 32 | + public int ret { get; set; } | |
| 33 | + | |
| 34 | + // 如果ret<0,会有相应的错误信息提示 | |
| 35 | + // 返回数据全部用UTF-8编码 | |
| 36 | + public string msg { get; set; } | |
| 37 | + | |
| 38 | + // 判断是否有数据丢失 | |
| 39 | + // 0或者不返回:没有数据丢失,可以缓存 | |
| 40 | + // 1:有部分数据丢失或错误,不要缓存 | |
| 41 | + public int is_lost { get; set; } | |
| 42 | + | |
| 43 | + // 用户在QQ空间的昵称 | |
| 44 | + public string nickname { get; set; } | |
| 45 | + | |
| 46 | + // 大小为30x30像素的QQ空间头像URL | |
| 47 | + public string figureurl { get; set; } | |
| 48 | + | |
| 49 | + // 大小为50x50像素的QQ空间头像URL | |
| 50 | + public string figureurl_1 { get; set; } | |
| 51 | + | |
| 52 | + // 大小为100x100像素的QQ空间头像URL | |
| 53 | + public string figureurl_2 { get; set; } | |
| 54 | + | |
| 55 | + // 大小为40x40像素的QQ头像URL | |
| 56 | + public string figureurl_qq_1 { get; set; } | |
| 57 | + | |
| 58 | + // 大小为100x100像素的QQ头像URL | |
| 59 | + // 需要注意,不是所有的用户都拥有QQ的100x100的头像,但40x40像素则是一定会有 | |
| 60 | + public string figureurl_qq_2 { get; set; } | |
| 61 | + | |
| 62 | + // 性别。如果获取不到则默认返回"男" | |
| 63 | + public string gender { get; set; } | |
| 64 | + | |
| 65 | + // 性别类型。默认返回2 | |
| 66 | + public int gender_type { get; set; } | |
| 67 | + | |
| 68 | + // 省 | |
| 69 | + public string province { get; set; } | |
| 70 | + | |
| 71 | + // 市 | |
| 72 | + public string city { get; set; } | |
| 73 | + | |
| 74 | + // 年 | |
| 75 | + public int year { get; set; } | |
| 76 | + | |
| 77 | + // 星座 | |
| 78 | + public string constellation { get; set; } | |
| 79 | + | |
| 80 | + // 标识用户是否为黄钻用户 | |
| 81 | + public int is_yellow_vip { get; set; } | |
| 82 | + | |
| 83 | + // 黄钻等级 | |
| 84 | + public int yellow_vip_level { get; set; } | |
| 85 | + | |
| 86 | + // 是否为年费黄钻用户 | |
| 87 | + public int is_yellow_year_vip { get; set; } | |
| 88 | + } | |
| 89 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Yi.Framework.AspNetCore.Authentication.OAuth.csproj
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/Yi.Framework.AspNetCore.Authentication.OAuth.csproj | |
| 1 | +<Project Sdk="Microsoft.NET.Sdk"> | |
| 2 | + <Import Project="..\..\common.props" /> | |
| 3 | + <PropertyGroup> | |
| 4 | + <TargetFramework>net8.0</TargetFramework> | |
| 5 | + <ImplicitUsings>enable</ImplicitUsings> | |
| 6 | + <Nullable>enable</Nullable> | |
| 7 | + </PropertyGroup> | |
| 8 | + <ItemGroup> | |
| 9 | + <ProjectReference Include="..\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj" /> | |
| 10 | + </ItemGroup> | |
| 11 | + | |
| 12 | +</Project> | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/YiFrameworkAspNetCoreAuthenticationOAuthModule.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore.Authentication.OAuth/YiFrameworkAspNetCoreAuthenticationOAuthModule.cs | |
| 1 | +using Microsoft.Extensions.DependencyInjection; | |
| 2 | +using Volo.Abp.Modularity; | |
| 3 | +using Yi.Framework.Core; | |
| 4 | + | |
| 5 | + | |
| 6 | +namespace Yi.Framework.AspNetCore.Authentication.OAuth | |
| 7 | +{ | |
| 8 | + /// <summary> | |
| 9 | + /// 本模块轮子来自 AspNet.Security.OAuth.QQ; | |
| 10 | + /// </summary> | |
| 11 | + [DependsOn(typeof(YiFrameworkAspNetCoreModule))] | |
| 12 | + public class YiFrameworkAspNetCoreAuthenticationOAuthModule:AbpModule | |
| 13 | + { | |
| 14 | + public override void ConfigureServices(ServiceConfigurationContext context) | |
| 15 | + { | |
| 16 | + var service = context.Services; | |
| 17 | + service.AddHttpClient(); | |
| 18 | + } | |
| 19 | + } | |
| 20 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ApiInfoBuilderExtensions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/ApiInfoBuilderExtensions.cs | |
| 1 | +using JetBrains.Annotations; | |
| 2 | +using Microsoft.AspNetCore.Builder; | |
| 3 | +using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares; | |
| 4 | + | |
| 5 | +namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// 提供API信息处理的应用程序构建器扩展方法 | |
| 9 | + /// </summary> | |
| 10 | + public static class ApiInfoBuilderExtensions | |
| 11 | + { | |
| 12 | + /// <summary> | |
| 13 | + /// 使用Yi框架的API信息处理中间件 | |
| 14 | + /// </summary> | |
| 15 | + /// <param name="builder">应用程序构建器实例</param> | |
| 16 | + /// <returns>配置后的应用程序构建器实例</returns> | |
| 17 | + /// <exception cref="ArgumentNullException">当builder参数为null时抛出</exception> | |
| 18 | + public static IApplicationBuilder UseApiInfoHandling([NotNull] this IApplicationBuilder builder) | |
| 19 | + { | |
| 20 | + // 添加API信息处理中间件到请求管道 | |
| 21 | + builder.UseMiddleware<ApiInfoMiddleware>(); | |
| 22 | + | |
| 23 | + return builder; | |
| 24 | + } | |
| 25 | + } | |
| 26 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerBuilderExtensons.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Builder/SwaggerBuilderExtensons.cs | |
| 1 | +using Microsoft.AspNetCore.Builder; | |
| 2 | +using Microsoft.Extensions.DependencyInjection; | |
| 3 | +using Microsoft.Extensions.Options; | |
| 4 | +using Volo.Abp.AspNetCore.Mvc; | |
| 5 | + | |
| 6 | +namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder | |
| 7 | +{ | |
| 8 | + /// <summary> | |
| 9 | + /// Swagger构建器扩展类 | |
| 10 | + /// </summary> | |
| 11 | + public static class SwaggerBuilderExtensions | |
| 12 | + { | |
| 13 | + /// <summary> | |
| 14 | + /// 配置并使用Yi框架的Swagger中间件 | |
| 15 | + /// </summary> | |
| 16 | + /// <param name="app">应用程序构建器</param> | |
| 17 | + /// <param name="swaggerConfigs">Swagger配置模型数组</param> | |
| 18 | + /// <returns>应用程序构建器</returns> | |
| 19 | + public static IApplicationBuilder UseYiSwagger( | |
| 20 | + this IApplicationBuilder app, | |
| 21 | + params SwaggerConfiguration[] swaggerConfigs) | |
| 22 | + { | |
| 23 | + if (app == null) | |
| 24 | + { | |
| 25 | + throw new ArgumentNullException(nameof(app)); | |
| 26 | + } | |
| 27 | + | |
| 28 | + var mvcOptions = app.ApplicationServices | |
| 29 | + .GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>() | |
| 30 | + .Value; | |
| 31 | + | |
| 32 | + // 启用Swagger中间件 | |
| 33 | + app.UseSwagger(); | |
| 34 | + | |
| 35 | + // 配置SwaggerUI | |
| 36 | + app.UseSwaggerUI(options => | |
| 37 | + { | |
| 38 | + // 添加约定控制器的Swagger终结点 | |
| 39 | + var conventionalSettings = mvcOptions.ConventionalControllers.ConventionalControllerSettings; | |
| 40 | + foreach (var setting in conventionalSettings) | |
| 41 | + { | |
| 42 | + options.SwaggerEndpoint( | |
| 43 | + $"/swagger/{setting.RemoteServiceName}/swagger.json", | |
| 44 | + setting.RemoteServiceName); | |
| 45 | + } | |
| 46 | + | |
| 47 | + // 如果没有配置任何终结点,使用默认配置 | |
| 48 | + if (!conventionalSettings.Any() && (swaggerConfigs == null || !swaggerConfigs.Any())) | |
| 49 | + { | |
| 50 | + options.SwaggerEndpoint("/swagger/v1/swagger.json", "Yi.Framework"); | |
| 51 | + return; | |
| 52 | + } | |
| 53 | + | |
| 54 | + // 添加自定义Swagger配置的终结点 | |
| 55 | + if (swaggerConfigs != null) | |
| 56 | + { | |
| 57 | + foreach (var config in swaggerConfigs) | |
| 58 | + { | |
| 59 | + options.SwaggerEndpoint(config.Url, config.Name); | |
| 60 | + } | |
| 61 | + } | |
| 62 | + }); | |
| 63 | + | |
| 64 | + return app; | |
| 65 | + } | |
| 66 | + } | |
| 67 | + | |
| 68 | + /// <summary> | |
| 69 | + /// Swagger配置模型 | |
| 70 | + /// </summary> | |
| 71 | + public class SwaggerConfiguration | |
| 72 | + { | |
| 73 | + private const string DefaultSwaggerUrl = "/swagger/v1/swagger.json"; | |
| 74 | + | |
| 75 | + /// <summary> | |
| 76 | + /// Swagger JSON文档的URL | |
| 77 | + /// </summary> | |
| 78 | + public string Url { get; } | |
| 79 | + | |
| 80 | + /// <summary> | |
| 81 | + /// Swagger文档的显示名称 | |
| 82 | + /// </summary> | |
| 83 | + public string Name { get; } | |
| 84 | + | |
| 85 | + /// <summary> | |
| 86 | + /// 使用默认URL创建Swagger配置 | |
| 87 | + /// </summary> | |
| 88 | + /// <param name="name">文档显示名称</param> | |
| 89 | + public SwaggerConfiguration(string name) | |
| 90 | + : this(DefaultSwaggerUrl, name) | |
| 91 | + { | |
| 92 | + } | |
| 93 | + | |
| 94 | + /// <summary> | |
| 95 | + /// 创建自定义Swagger配置 | |
| 96 | + /// </summary> | |
| 97 | + /// <param name="url">Swagger JSON文档URL</param> | |
| 98 | + /// <param name="name">文档显示名称</param> | |
| 99 | + public SwaggerConfiguration(string url, string name) | |
| 100 | + { | |
| 101 | + Url = url ?? throw new ArgumentNullException(nameof(url)); | |
| 102 | + Name = name ?? throw new ArgumentNullException(nameof(name)); | |
| 103 | + } | |
| 104 | + } | |
| 105 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/AspNetCore/Middlewares/ApiInfoMiddleware.cs | |
| 1 | +using System.Diagnostics; | |
| 2 | +using Microsoft.AspNetCore.Http; | |
| 3 | +using Volo.Abp.DependencyInjection; | |
| 4 | +using Yi.Framework.Core.Extensions; | |
| 5 | + | |
| 6 | +namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares | |
| 7 | +{ | |
| 8 | + /// <summary> | |
| 9 | + /// API响应信息处理中间件 | |
| 10 | + /// 主要用于处理特定文件类型的响应头信息 | |
| 11 | + /// </summary> | |
| 12 | + [DebuggerStepThrough] | |
| 13 | + public class ApiInfoMiddleware : IMiddleware, ITransientDependency | |
| 14 | + { | |
| 15 | + /// <summary> | |
| 16 | + /// 处理HTTP请求的中间件方法 | |
| 17 | + /// </summary> | |
| 18 | + /// <param name="context">HTTP上下文</param> | |
| 19 | + /// <param name="next">请求处理委托</param> | |
| 20 | + /// <returns>异步任务</returns> | |
| 21 | + public async Task InvokeAsync(HttpContext context, RequestDelegate next) | |
| 22 | + { | |
| 23 | + // // 在响应开始时处理文件下载相关的响应头 | |
| 24 | + // context.Response.OnStarting(() => | |
| 25 | + // { | |
| 26 | + // HandleFileDownloadResponse(context); | |
| 27 | + // return Task.CompletedTask; | |
| 28 | + // }); | |
| 29 | + | |
| 30 | + // 继续处理管道中的下一个中间件 | |
| 31 | + await next(context); | |
| 32 | + } | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 处理文件下载响应的响应头信息 | |
| 36 | + /// </summary> | |
| 37 | + /// <param name="context">HTTP上下文</param> | |
| 38 | + private static void HandleFileDownloadResponse(HttpContext context) | |
| 39 | + { | |
| 40 | + // 仅处理状态码为200的响应 | |
| 41 | + if (context.Response.StatusCode != StatusCodes.Status200OK) | |
| 42 | + { | |
| 43 | + return; | |
| 44 | + } | |
| 45 | + | |
| 46 | + var contentType = context.Response.Headers["Content-Type"].ToString(); | |
| 47 | + var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"); | |
| 48 | + | |
| 49 | + // 处理Excel文件下载 | |
| 50 | + if (contentType == "application/vnd.ms-excel") | |
| 51 | + { | |
| 52 | + context.FileAttachmentHandle($"{timestamp}.xlsx"); | |
| 53 | + } | |
| 54 | + // 处理ZIP文件下载 | |
| 55 | + else if (contentType == "application/x-zip-compressed") | |
| 56 | + { | |
| 57 | + context.FileAttachmentHandle($"{timestamp}.zip"); | |
| 58 | + } | |
| 59 | + } | |
| 60 | + } | |
| 61 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Microsoft/Extensions/DependencyInjection/SwaggerAddExtensions.cs | |
| 1 | +using System.ComponentModel; | |
| 2 | +using System.Diagnostics; | |
| 3 | +using System.Text; | |
| 4 | +using System.Xml.Linq; | |
| 5 | +using Microsoft.AspNetCore.Mvc.Controllers; | |
| 6 | +using Microsoft.Extensions.DependencyInjection; | |
| 7 | +using Microsoft.Extensions.Options; | |
| 8 | +using Microsoft.OpenApi.Any; | |
| 9 | +using Microsoft.OpenApi.Models; | |
| 10 | +using Swashbuckle.AspNetCore.SwaggerGen; | |
| 11 | +using Volo.Abp.AspNetCore.Mvc; | |
| 12 | +using Volo.Abp.AspNetCore.Mvc.Conventions; | |
| 13 | +using Volo.Abp.DependencyInjection; | |
| 14 | +using Volo.Abp.Options; | |
| 15 | + | |
| 16 | +namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection | |
| 17 | +{ | |
| 18 | + /// <summary> | |
| 19 | + /// Swagger生成器扩展类 | |
| 20 | + /// </summary> | |
| 21 | + public static class SwaggerAddExtensions | |
| 22 | + { | |
| 23 | + /// <summary> | |
| 24 | + /// 添加Yi框架的Swagger生成器服务 | |
| 25 | + /// </summary> | |
| 26 | + /// <typeparam name="TProgram">程序入口类型</typeparam> | |
| 27 | + /// <param name="services">服务集合</param> | |
| 28 | + /// <param name="setupAction">自定义配置动作</param> | |
| 29 | + /// <returns>服务集合</returns> | |
| 30 | + public static IServiceCollection AddYiSwaggerGen<TProgram>( | |
| 31 | + this IServiceCollection services, | |
| 32 | + Action<SwaggerGenOptions>? setupAction = null) | |
| 33 | + { | |
| 34 | + // 获取MVC配置选项 | |
| 35 | + var mvcOptions = services.GetPreConfigureActions<AbpAspNetCoreMvcOptions>().Configure(); | |
| 36 | + | |
| 37 | + // 获取并去重远程服务名称 | |
| 38 | + var remoteServiceSettings = mvcOptions.ConventionalControllers | |
| 39 | + .ConventionalControllerSettings | |
| 40 | + .DistinctBy(x => x.RemoteServiceName); | |
| 41 | + | |
| 42 | + services.AddAbpSwaggerGen( | |
| 43 | + options => | |
| 44 | + { | |
| 45 | + // 应用外部配置 | |
| 46 | + setupAction?.Invoke(options); | |
| 47 | + | |
| 48 | + // 配置API文档分组 | |
| 49 | + ConfigureApiGroups(options, remoteServiceSettings); | |
| 50 | + | |
| 51 | + // 配置API文档过滤器 | |
| 52 | + ConfigureApiFilter(options, remoteServiceSettings); | |
| 53 | + | |
| 54 | + // 配置Schema ID生成规则 | |
| 55 | + options.CustomSchemaIds(type => type.FullName); | |
| 56 | + | |
| 57 | + // 包含XML注释文档 | |
| 58 | + IncludeXmlComments<TProgram>(options); | |
| 59 | + | |
| 60 | + // 配置JWT认证 | |
| 61 | + ConfigureJwtAuthentication(options); | |
| 62 | + | |
| 63 | + // 添加自定义过滤器 | |
| 64 | + ConfigureCustomFilters(options); | |
| 65 | + } | |
| 66 | + ); | |
| 67 | + | |
| 68 | + return services; | |
| 69 | + } | |
| 70 | + | |
| 71 | + /// <summary> | |
| 72 | + /// 配置API分组 | |
| 73 | + /// </summary> | |
| 74 | + private static void ConfigureApiGroups( | |
| 75 | + SwaggerGenOptions options, | |
| 76 | + IEnumerable<ConventionalControllerSetting> settings) | |
| 77 | + { | |
| 78 | + foreach (var setting in settings.OrderBy(x => x.RemoteServiceName)) | |
| 79 | + { | |
| 80 | + if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName)) | |
| 81 | + { | |
| 82 | + options.SwaggerDoc(setting.RemoteServiceName, new OpenApiInfo | |
| 83 | + { | |
| 84 | + Title = setting.RemoteServiceName, | |
| 85 | + Version = "v1" | |
| 86 | + }); | |
| 87 | + } | |
| 88 | + } | |
| 89 | + } | |
| 90 | + | |
| 91 | + /// <summary> | |
| 92 | + /// 配置API文档过滤器 | |
| 93 | + /// </summary> | |
| 94 | + private static void ConfigureApiFilter( | |
| 95 | + SwaggerGenOptions options, | |
| 96 | + IEnumerable<ConventionalControllerSetting> settings) | |
| 97 | + { | |
| 98 | + options.DocInclusionPredicate((docName, apiDesc) => | |
| 99 | + { | |
| 100 | + if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerDesc) | |
| 101 | + { | |
| 102 | + var matchedSetting = settings | |
| 103 | + .FirstOrDefault(x => x.Assembly == controllerDesc.ControllerTypeInfo.Assembly); | |
| 104 | + return matchedSetting?.RemoteServiceName == docName; | |
| 105 | + } | |
| 106 | + return false; | |
| 107 | + }); | |
| 108 | + } | |
| 109 | + | |
| 110 | + /// <summary> | |
| 111 | + /// 包含XML注释文档 | |
| 112 | + /// </summary> | |
| 113 | + private static void IncludeXmlComments<TProgram>(SwaggerGenOptions options) | |
| 114 | + { | |
| 115 | + var basePath = Path.GetDirectoryName(typeof(TProgram).Assembly.Location); | |
| 116 | + if (basePath is not null) | |
| 117 | + { | |
| 118 | + foreach (var xmlFile in Directory.GetFiles(basePath, "*.xml")) | |
| 119 | + { | |
| 120 | + options.IncludeXmlComments(xmlFile, true); | |
| 121 | + } | |
| 122 | + } | |
| 123 | + } | |
| 124 | + | |
| 125 | + /// <summary> | |
| 126 | + /// 配置JWT认证 | |
| 127 | + /// </summary> | |
| 128 | + private static void ConfigureJwtAuthentication(SwaggerGenOptions options) | |
| 129 | + { | |
| 130 | + options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme | |
| 131 | + { | |
| 132 | + Description = "请在此输入JWT Token", | |
| 133 | + Name = "Authorization", | |
| 134 | + In = ParameterLocation.Header, | |
| 135 | + Type = SecuritySchemeType.Http, | |
| 136 | + Scheme = "bearer" | |
| 137 | + }); | |
| 138 | + | |
| 139 | + var scheme = new OpenApiSecurityScheme | |
| 140 | + { | |
| 141 | + Reference = new OpenApiReference | |
| 142 | + { | |
| 143 | + Type = ReferenceType.SecurityScheme, | |
| 144 | + Id = "JwtBearer" | |
| 145 | + } | |
| 146 | + }; | |
| 147 | + | |
| 148 | + options.AddSecurityRequirement(new OpenApiSecurityRequirement | |
| 149 | + { | |
| 150 | + [scheme] = Array.Empty<string>() | |
| 151 | + }); | |
| 152 | + } | |
| 153 | + | |
| 154 | + /// <summary> | |
| 155 | + /// 配置自定义过滤器 | |
| 156 | + /// </summary> | |
| 157 | + private static void ConfigureCustomFilters(SwaggerGenOptions options) | |
| 158 | + { | |
| 159 | + options.OperationFilter<TenantHeaderOperationFilter>(); | |
| 160 | + options.SchemaFilter<EnumSchemaFilter>(); | |
| 161 | + } | |
| 162 | + } | |
| 163 | + | |
| 164 | + /// <summary> | |
| 165 | + /// Swagger文档枚举字段显示过滤器 | |
| 166 | + /// </summary> | |
| 167 | + public class EnumSchemaFilter : ISchemaFilter | |
| 168 | + { | |
| 169 | + /// <summary> | |
| 170 | + /// 应用枚举架构过滤器 | |
| 171 | + /// </summary> | |
| 172 | + /// <param name="schema">OpenAPI架构</param> | |
| 173 | + /// <param name="context">架构过滤器上下文</param> | |
| 174 | + public void Apply(OpenApiSchema schema, SchemaFilterContext context) | |
| 175 | + { | |
| 176 | + if (!context.Type.IsEnum) return; | |
| 177 | + | |
| 178 | + schema.Enum.Clear(); | |
| 179 | + schema.Type = "string"; | |
| 180 | + schema.Format = null; | |
| 181 | + | |
| 182 | + var enumDescriptions = new StringBuilder(); | |
| 183 | + foreach (var enumName in Enum.GetNames(context.Type)) | |
| 184 | + { | |
| 185 | + var enumValue = (Enum)Enum.Parse(context.Type, enumName); | |
| 186 | + var description = GetEnumDescription(enumValue); | |
| 187 | + var enumIntValue = Convert.ToInt64(enumValue); | |
| 188 | + | |
| 189 | + schema.Enum.Add(new OpenApiString(enumName)); | |
| 190 | + enumDescriptions.AppendLine( | |
| 191 | + $"【枚举:{enumName}{(description is null ? string.Empty : $"({description})")}={enumIntValue}】"); | |
| 192 | + } | |
| 193 | + schema.Description = enumDescriptions.ToString(); | |
| 194 | + } | |
| 195 | + | |
| 196 | + /// <summary> | |
| 197 | + /// 获取枚举描述特性值 | |
| 198 | + /// </summary> | |
| 199 | + private static string? GetEnumDescription(Enum value) | |
| 200 | + { | |
| 201 | + var fieldInfo = value.GetType().GetField(value.ToString()); | |
| 202 | + var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); | |
| 203 | + return attributes.Length > 0 ? attributes[0].Description : null; | |
| 204 | + } | |
| 205 | + } | |
| 206 | + | |
| 207 | + /// <summary> | |
| 208 | + /// 租户头部参数过滤器 | |
| 209 | + /// </summary> | |
| 210 | + public class TenantHeaderOperationFilter : IOperationFilter | |
| 211 | + { | |
| 212 | + /// <summary> | |
| 213 | + /// 租户标识键名 | |
| 214 | + /// </summary> | |
| 215 | + private const string TenantHeaderKey = "__tenant"; | |
| 216 | + | |
| 217 | + /// <summary> | |
| 218 | + /// 应用租户头部参数过滤器 | |
| 219 | + /// </summary> | |
| 220 | + public void Apply(OpenApiOperation operation, OperationFilterContext context) | |
| 221 | + { | |
| 222 | + operation.Parameters ??= new List<OpenApiParameter>(); | |
| 223 | + | |
| 224 | + operation.Parameters.Add(new OpenApiParameter | |
| 225 | + { | |
| 226 | + Name = TenantHeaderKey, | |
| 227 | + In = ParameterLocation.Header, | |
| 228 | + Required = false, | |
| 229 | + AllowEmptyValue = true, | |
| 230 | + Description = "租户ID或租户名称(留空表示默认租户)" | |
| 231 | + }); | |
| 232 | + } | |
| 233 | + } | |
| 234 | +} | |
| 0 | 235 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiConventionalRouteBuilder.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiConventionalRouteBuilder.cs | |
| 1 | +using JetBrains.Annotations; | |
| 2 | +using Microsoft.AspNetCore.Mvc.ApplicationModels; | |
| 3 | +using System.Reflection; | |
| 4 | +using Microsoft.Extensions.DependencyInjection; | |
| 5 | +using Microsoft.Extensions.Options; | |
| 6 | +using Volo.Abp.AspNetCore.Mvc.Conventions; | |
| 7 | +using Volo.Abp.DependencyInjection; | |
| 8 | +using Volo.Abp.Reflection; | |
| 9 | + | |
| 10 | +namespace Yi.Framework.AspNetCore.Mvc | |
| 11 | +{ | |
| 12 | + /// <summary> | |
| 13 | + /// 自定义路由构建器,用于生成API路由规则 | |
| 14 | + /// </summary> | |
| 15 | + [Dependency(ServiceLifetime.Transient, ReplaceServices = true)] | |
| 16 | + [ExposeServices(typeof(IConventionalRouteBuilder))] | |
| 17 | + public class YiConventionalRouteBuilder : ConventionalRouteBuilder | |
| 18 | + { | |
| 19 | + /// <summary> | |
| 20 | + /// 构造函数 | |
| 21 | + /// </summary> | |
| 22 | + /// <param name="options">ABP约定控制器配置选项</param> | |
| 23 | + public YiConventionalRouteBuilder(IOptions<AbpConventionalControllerOptions> options) | |
| 24 | + : base(options) | |
| 25 | + { | |
| 26 | + } | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 构建API路由 | |
| 30 | + /// </summary> | |
| 31 | + /// <param name="rootPath">根路径</param> | |
| 32 | + /// <param name="controllerName">控制器名称</param> | |
| 33 | + /// <param name="action">Action模型</param> | |
| 34 | + /// <param name="httpMethod">HTTP方法</param> | |
| 35 | + /// <param name="configuration">控制器配置</param> | |
| 36 | + /// <returns>构建的路由URL</returns> | |
| 37 | + public override string Build( | |
| 38 | + string rootPath, | |
| 39 | + string controllerName, | |
| 40 | + ActionModel action, | |
| 41 | + string httpMethod, | |
| 42 | + [CanBeNull] ConventionalControllerSetting configuration) | |
| 43 | + { | |
| 44 | + // 获取API路由前缀 | |
| 45 | + var apiRoutePrefix = GetApiRoutePrefix(action, configuration); | |
| 46 | + | |
| 47 | + // 规范化控制器名称 | |
| 48 | + var normalizedControllerName = NormalizeUrlControllerName( | |
| 49 | + rootPath, | |
| 50 | + controllerName, | |
| 51 | + action, | |
| 52 | + httpMethod, | |
| 53 | + configuration); | |
| 54 | + | |
| 55 | + // 构建基础URL | |
| 56 | + var url = $"{rootPath}/{NormalizeControllerNameCase(normalizedControllerName, configuration)}"; | |
| 57 | + | |
| 58 | + // 处理ID参数路由 | |
| 59 | + url = BuildIdParameterRoute(url, action, configuration); | |
| 60 | + | |
| 61 | + // 处理Action名称路由 | |
| 62 | + url = BuildActionNameRoute(url, rootPath, controllerName, action, httpMethod, configuration); | |
| 63 | + | |
| 64 | + return url; | |
| 65 | + } | |
| 66 | + | |
| 67 | + /// <summary> | |
| 68 | + /// 构建ID参数路由部分 | |
| 69 | + /// </summary> | |
| 70 | + private string BuildIdParameterRoute( | |
| 71 | + string baseUrl, | |
| 72 | + ActionModel action, | |
| 73 | + ConventionalControllerSetting configuration) | |
| 74 | + { | |
| 75 | + var idParameter = action.Parameters.FirstOrDefault(p => p.ParameterName == "id"); | |
| 76 | + if (idParameter == null) | |
| 77 | + { | |
| 78 | + return baseUrl; | |
| 79 | + } | |
| 80 | + | |
| 81 | + // 处理原始类型ID | |
| 82 | + if (TypeHelper.IsPrimitiveExtended(idParameter.ParameterType, includeEnums: true)) | |
| 83 | + { | |
| 84 | + return $"{baseUrl}/{{id}}"; | |
| 85 | + } | |
| 86 | + | |
| 87 | + // 处理复杂类型ID | |
| 88 | + var properties = idParameter.ParameterType | |
| 89 | + .GetProperties(BindingFlags.Instance | BindingFlags.Public); | |
| 90 | + | |
| 91 | + foreach (var property in properties) | |
| 92 | + { | |
| 93 | + baseUrl += $"/{{{NormalizeIdPropertyNameCase(property, configuration)}}}"; | |
| 94 | + } | |
| 95 | + | |
| 96 | + return baseUrl; | |
| 97 | + } | |
| 98 | + | |
| 99 | + /// <summary> | |
| 100 | + /// 构建Action名称路由部分 | |
| 101 | + /// </summary> | |
| 102 | + private string BuildActionNameRoute( | |
| 103 | + string baseUrl, | |
| 104 | + string rootPath, | |
| 105 | + string controllerName, | |
| 106 | + ActionModel action, | |
| 107 | + string httpMethod, | |
| 108 | + ConventionalControllerSetting configuration) | |
| 109 | + { | |
| 110 | + var actionNameInUrl = NormalizeUrlActionName( | |
| 111 | + rootPath, | |
| 112 | + controllerName, | |
| 113 | + action, | |
| 114 | + httpMethod, | |
| 115 | + configuration); | |
| 116 | + | |
| 117 | + if (actionNameInUrl.IsNullOrEmpty()) | |
| 118 | + { | |
| 119 | + return baseUrl; | |
| 120 | + } | |
| 121 | + | |
| 122 | + baseUrl += $"/{NormalizeActionNameCase(actionNameInUrl, configuration)}"; | |
| 123 | + | |
| 124 | + // 处理次要ID参数 | |
| 125 | + var secondaryIds = action.Parameters | |
| 126 | + .Where(p => p.ParameterName.EndsWith("Id", StringComparison.Ordinal)) | |
| 127 | + .ToList(); | |
| 128 | + | |
| 129 | + if (secondaryIds.Count == 1) | |
| 130 | + { | |
| 131 | + baseUrl += $"/{{{NormalizeSecondaryIdNameCase(secondaryIds[0], configuration)}}}"; | |
| 132 | + } | |
| 133 | + | |
| 134 | + return baseUrl; | |
| 135 | + } | |
| 136 | + } | |
| 137 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiServiceConvention.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Mvc/YiServiceConvention.cs | |
| 1 | +using JetBrains.Annotations; | |
| 2 | +using Microsoft.AspNetCore.Mvc; | |
| 3 | +using Microsoft.AspNetCore.Mvc.ActionConstraints; | |
| 4 | +using Microsoft.AspNetCore.Mvc.ApplicationModels; | |
| 5 | +using Microsoft.Extensions.DependencyInjection; | |
| 6 | +using Microsoft.Extensions.Options; | |
| 7 | +using Volo.Abp; | |
| 8 | +using Volo.Abp.AspNetCore; | |
| 9 | +using Volo.Abp.AspNetCore.Mvc; | |
| 10 | +using Volo.Abp.AspNetCore.Mvc.Conventions; | |
| 11 | +using Volo.Abp.DependencyInjection; | |
| 12 | +using Volo.Abp.Reflection; | |
| 13 | + | |
| 14 | +namespace Yi.Framework.AspNetCore.Mvc | |
| 15 | +{ | |
| 16 | + /// <summary> | |
| 17 | + /// 自定义服务约定实现,用于处理API路由和HTTP方法约束 | |
| 18 | + /// </summary> | |
| 19 | + [Dependency(ServiceLifetime.Transient, ReplaceServices = true)] | |
| 20 | + [ExposeServices(typeof(IAbpServiceConvention))] | |
| 21 | + public class YiServiceConvention : AbpServiceConvention | |
| 22 | + { | |
| 23 | + /// <summary> | |
| 24 | + /// 初始化服务约定的新实例 | |
| 25 | + /// </summary> | |
| 26 | + /// <param name="options">ABP AspNetCore MVC 配置选项</param> | |
| 27 | + /// <param name="conventionalRouteBuilder">约定路由构建器</param> | |
| 28 | + public YiServiceConvention( | |
| 29 | + IOptions<AbpAspNetCoreMvcOptions> options, | |
| 30 | + IConventionalRouteBuilder conventionalRouteBuilder) | |
| 31 | + : base(options, conventionalRouteBuilder) | |
| 32 | + { | |
| 33 | + } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 配置选择器,处理路由和HTTP方法约束 | |
| 37 | + /// </summary> | |
| 38 | + protected override void ConfigureSelector( | |
| 39 | + string rootPath, | |
| 40 | + string controllerName, | |
| 41 | + ActionModel action, | |
| 42 | + ConventionalControllerSetting? configuration) | |
| 43 | + { | |
| 44 | + // 移除空选择器 | |
| 45 | + RemoveEmptySelectors(action.Selectors); | |
| 46 | + | |
| 47 | + // 检查远程服务特性 | |
| 48 | + var remoteServiceAttr = ReflectionHelper | |
| 49 | + .GetSingleAttributeOrDefault<RemoteServiceAttribute>(action.ActionMethod); | |
| 50 | + if (remoteServiceAttr != null && !remoteServiceAttr.IsEnabledFor(action.ActionMethod)) | |
| 51 | + { | |
| 52 | + return; | |
| 53 | + } | |
| 54 | + | |
| 55 | + // 根据选择器是否存在执行不同的配置 | |
| 56 | + if (!action.Selectors.Any()) | |
| 57 | + { | |
| 58 | + AddAbpServiceSelector(rootPath, controllerName, action, configuration); | |
| 59 | + } | |
| 60 | + else | |
| 61 | + { | |
| 62 | + NormalizeSelectorRoutes(rootPath, controllerName, action, configuration); | |
| 63 | + } | |
| 64 | + } | |
| 65 | + | |
| 66 | + /// <summary> | |
| 67 | + /// 规范化选择器路由 | |
| 68 | + /// </summary> | |
| 69 | + protected override void NormalizeSelectorRoutes( | |
| 70 | + string rootPath, | |
| 71 | + string controllerName, | |
| 72 | + ActionModel action, | |
| 73 | + ConventionalControllerSetting? configuration) | |
| 74 | + { | |
| 75 | + foreach (var selector in action.Selectors) | |
| 76 | + { | |
| 77 | + // 获取HTTP方法约束 | |
| 78 | + var httpMethod = GetOrCreateHttpMethod(selector, action, configuration); | |
| 79 | + | |
| 80 | + // 处理路由模板 | |
| 81 | + ConfigureRouteTemplate(selector, rootPath, controllerName, action, httpMethod, configuration); | |
| 82 | + | |
| 83 | + // 确保HTTP方法约束存在 | |
| 84 | + EnsureHttpMethodConstraint(selector, httpMethod); | |
| 85 | + } | |
| 86 | + } | |
| 87 | + | |
| 88 | + /// <summary> | |
| 89 | + /// 获取或创建HTTP方法 | |
| 90 | + /// </summary> | |
| 91 | + private string GetOrCreateHttpMethod( | |
| 92 | + SelectorModel selector, | |
| 93 | + ActionModel action, | |
| 94 | + ConventionalControllerSetting? configuration) | |
| 95 | + { | |
| 96 | + return selector.ActionConstraints | |
| 97 | + .OfType<HttpMethodActionConstraint>() | |
| 98 | + .FirstOrDefault()? | |
| 99 | + .HttpMethods? | |
| 100 | + .FirstOrDefault() | |
| 101 | + ?? SelectHttpMethod(action, configuration); | |
| 102 | + } | |
| 103 | + | |
| 104 | + /// <summary> | |
| 105 | + /// 配置路由模板 | |
| 106 | + /// </summary> | |
| 107 | + private void ConfigureRouteTemplate( | |
| 108 | + SelectorModel selector, | |
| 109 | + string rootPath, | |
| 110 | + string controllerName, | |
| 111 | + ActionModel action, | |
| 112 | + string httpMethod, | |
| 113 | + ConventionalControllerSetting? configuration) | |
| 114 | + { | |
| 115 | + if (selector.AttributeRouteModel == null) | |
| 116 | + { | |
| 117 | + selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel( | |
| 118 | + rootPath, | |
| 119 | + controllerName, | |
| 120 | + action, | |
| 121 | + httpMethod, | |
| 122 | + configuration); | |
| 123 | + } | |
| 124 | + else | |
| 125 | + { | |
| 126 | + NormalizeAttributeRouteTemplate(selector, rootPath); | |
| 127 | + } | |
| 128 | + } | |
| 129 | + | |
| 130 | + /// <summary> | |
| 131 | + /// 规范化特性路由模板 | |
| 132 | + /// </summary> | |
| 133 | + private void NormalizeAttributeRouteTemplate(SelectorModel selector, string rootPath) | |
| 134 | + { | |
| 135 | + var template = selector.AttributeRouteModel.Template; | |
| 136 | + if (!template.StartsWith("/")) | |
| 137 | + { | |
| 138 | + selector.AttributeRouteModel.Template = $"{rootPath}/{template}"; | |
| 139 | + } | |
| 140 | + } | |
| 141 | + | |
| 142 | + /// <summary> | |
| 143 | + /// 确保HTTP方法约束存在 | |
| 144 | + /// </summary> | |
| 145 | + private void EnsureHttpMethodConstraint(SelectorModel selector, string httpMethod) | |
| 146 | + { | |
| 147 | + if (!selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Any()) | |
| 148 | + { | |
| 149 | + selector.ActionConstraints.Add( | |
| 150 | + new HttpMethodActionConstraint(new[] { httpMethod })); | |
| 151 | + } | |
| 152 | + } | |
| 153 | + } | |
| 154 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RealIpHttpContextWebClientInfoProvider.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RealIpHttpContextWebClientInfoProvider.cs | |
| 1 | +using System.Net; | |
| 2 | +using Microsoft.AspNetCore.Http; | |
| 3 | +using Microsoft.Extensions.Logging; | |
| 4 | +using Volo.Abp.AspNetCore.WebClientInfo; | |
| 5 | + | |
| 6 | +namespace Yi.Framework.AspNetCore; | |
| 7 | + | |
| 8 | +/// <summary> | |
| 9 | +/// 真实IP地址提供程序,支持代理服务器场景 | |
| 10 | +/// </summary> | |
| 11 | +public class RealIpHttpContextWebClientInfoProvider : HttpContextWebClientInfoProvider | |
| 12 | +{ | |
| 13 | + private const string XForwardedForHeader = "X-Forwarded-For"; | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 初始化真实IP地址提供程序的新实例 | |
| 17 | + /// </summary> | |
| 18 | + public RealIpHttpContextWebClientInfoProvider( | |
| 19 | + ILogger<HttpContextWebClientInfoProvider> logger, | |
| 20 | + IHttpContextAccessor httpContextAccessor) | |
| 21 | + : base(logger, httpContextAccessor) | |
| 22 | + { | |
| 23 | + } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 获取客户端IP地址,优先从X-Forwarded-For头部获取 | |
| 27 | + /// </summary> | |
| 28 | + /// <returns>客户端IP地址</returns> | |
| 29 | + protected override string? GetClientIpAddress() | |
| 30 | + { | |
| 31 | + try | |
| 32 | + { | |
| 33 | + var httpContext = HttpContextAccessor.HttpContext; | |
| 34 | + if (httpContext == null) | |
| 35 | + { | |
| 36 | + return null; | |
| 37 | + } | |
| 38 | + | |
| 39 | + var headers = httpContext.Request?.Headers; | |
| 40 | + if (headers != null && headers.ContainsKey(XForwardedForHeader)) | |
| 41 | + { | |
| 42 | + // 从X-Forwarded-For获取真实客户端IP | |
| 43 | + var forwardedIp = headers[XForwardedForHeader].FirstOrDefault(); | |
| 44 | + if (!string.IsNullOrEmpty(forwardedIp)) | |
| 45 | + { | |
| 46 | + httpContext.Connection.RemoteIpAddress = IPAddress.Parse(forwardedIp); | |
| 47 | + } | |
| 48 | + } | |
| 49 | + | |
| 50 | + return httpContext.Connection?.RemoteIpAddress?.ToString(); | |
| 51 | + } | |
| 52 | + catch (Exception ex) | |
| 53 | + { | |
| 54 | + Logger.LogWarning(ex, "获取客户端IP地址时发生异常"); | |
| 55 | + return null; | |
| 56 | + } | |
| 57 | + } | |
| 58 | +} | |
| 0 | 59 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RemoteServiceSuccessInfo.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/RemoteServiceSuccessInfo.cs | |
| 1 | +namespace Yi.Framework.AspNetCore | |
| 2 | +{ | |
| 3 | + /// <summary> | |
| 4 | + /// 远程服务成功响应信息 | |
| 5 | + /// </summary> | |
| 6 | + [Serializable] | |
| 7 | + public class RemoteServiceSuccessInfo | |
| 8 | + { | |
| 9 | + /// <summary> | |
| 10 | + /// 获取或设置响应代码 | |
| 11 | + /// </summary> | |
| 12 | + public string? Code { get; private set; } | |
| 13 | + | |
| 14 | + /// <summary> | |
| 15 | + /// 获取或设置响应消息 | |
| 16 | + /// </summary> | |
| 17 | + public string? Message { get; private set; } | |
| 18 | + | |
| 19 | + /// <summary> | |
| 20 | + /// 获取或设置详细信息 | |
| 21 | + /// </summary> | |
| 22 | + public string? Details { get; private set; } | |
| 23 | + | |
| 24 | + /// <summary> | |
| 25 | + /// 获取或设置响应数据 | |
| 26 | + /// </summary> | |
| 27 | + public object? Data { get; private set; } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 初始化远程服务成功响应信息的新实例 | |
| 31 | + /// </summary> | |
| 32 | + public RemoteServiceSuccessInfo() | |
| 33 | + { | |
| 34 | + } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 使用指定参数初始化远程服务成功响应信息的新实例 | |
| 38 | + /// </summary> | |
| 39 | + /// <param name="message">响应消息</param> | |
| 40 | + /// <param name="details">详细信息</param> | |
| 41 | + /// <param name="code">响应代码</param> | |
| 42 | + /// <param name="data">响应数据</param> | |
| 43 | + public RemoteServiceSuccessInfo( | |
| 44 | + string message, | |
| 45 | + string? details = null, | |
| 46 | + string? code = null, | |
| 47 | + object? data = null) | |
| 48 | + { | |
| 49 | + Message = message; | |
| 50 | + Details = details; | |
| 51 | + Code = code; | |
| 52 | + Data = data; | |
| 53 | + } | |
| 54 | + } | |
| 55 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/ExceptionMetadata.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/ExceptionMetadata.cs | |
| 1 | +// MIT 许可证 | |
| 2 | +// | |
| 3 | +// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者 | |
| 4 | +// | |
| 5 | +// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利, | |
| 6 | +// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本, | |
| 7 | +// 以及再授权被配发了本软件的人如上的权利,须在下列条件下: | |
| 8 | +// | |
| 9 | +// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | |
| 10 | +// | |
| 11 | +// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。 | |
| 12 | +// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中, | |
| 13 | +// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | |
| 14 | + | |
| 15 | +namespace Yi.Framework.AspNetCore.UnifyResult; | |
| 16 | + | |
| 17 | +/// <summary> | |
| 18 | +/// 异常元数据 | |
| 19 | +/// </summary> | |
| 20 | +public sealed class ExceptionMetadata | |
| 21 | +{ | |
| 22 | + /// <summary> | |
| 23 | + /// 状态码 | |
| 24 | + /// </summary> | |
| 25 | + public int StatusCode { get; internal set; } | |
| 26 | + | |
| 27 | + /// <summary> | |
| 28 | + /// 错误码 | |
| 29 | + /// </summary> | |
| 30 | + public object ErrorCode { get; internal set; } | |
| 31 | + | |
| 32 | + /// <summary> | |
| 33 | + /// 错误码(没被复写过的 ErrorCode ) | |
| 34 | + /// </summary> | |
| 35 | + public object OriginErrorCode { get; internal set; } | |
| 36 | + | |
| 37 | + /// <summary> | |
| 38 | + /// 错误对象(信息) | |
| 39 | + /// </summary> | |
| 40 | + public object Errors { get; internal set; } | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// 额外数据 | |
| 44 | + /// </summary> | |
| 45 | + public object Data { get; internal set; } | |
| 46 | +} | |
| 0 | 47 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/Fiters/FriendlyExceptionFilter.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/Fiters/FriendlyExceptionFilter.cs | |
| 1 | +// MIT 许可证 | |
| 2 | +// | |
| 3 | +// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者 | |
| 4 | +// | |
| 5 | +// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利, | |
| 6 | +// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本, | |
| 7 | +// 以及再授权被配发了本软件的人如上的权利,须在下列条件下: | |
| 8 | +// | |
| 9 | +// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | |
| 10 | +// | |
| 11 | +// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。 | |
| 12 | +// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中, | |
| 13 | +// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | |
| 14 | + | |
| 15 | +using Microsoft.AspNetCore.Http; | |
| 16 | +using Microsoft.AspNetCore.Mvc; | |
| 17 | +using Microsoft.AspNetCore.Mvc.Filters; | |
| 18 | +using Microsoft.Extensions.DependencyInjection; | |
| 19 | +using Microsoft.Extensions.Logging; | |
| 20 | +using Newtonsoft.Json; | |
| 21 | +using Volo.Abp.AspNetCore.Mvc; | |
| 22 | +using Volo.Abp.Validation; | |
| 23 | +using Yi.Framework.Core.Extensions; | |
| 24 | + | |
| 25 | +namespace Yi.Framework.AspNetCore.UnifyResult.Fiters; | |
| 26 | + | |
| 27 | +/// <summary> | |
| 28 | +/// 友好异常拦截器 | |
| 29 | +/// </summary> | |
| 30 | +public sealed class FriendlyExceptionFilter : IAsyncExceptionFilter | |
| 31 | +{ | |
| 32 | + /// <summary> | |
| 33 | + /// 异常拦截 | |
| 34 | + /// </summary> | |
| 35 | + /// <param name="context"></param> | |
| 36 | + /// <returns></returns> | |
| 37 | + public async Task OnExceptionAsync(ExceptionContext context) | |
| 38 | + { | |
| 39 | + // 排除 WebSocket 请求处理 | |
| 40 | + if (context.HttpContext.IsWebSocketRequest()) return; | |
| 41 | + | |
| 42 | + // 如果异常在其他地方被标记了处理,那么这里不再处理 | |
| 43 | + if (context.ExceptionHandled) return; | |
| 44 | + | |
| 45 | + // 解析异常信息 | |
| 46 | + var exceptionMetadata = GetExceptionMetadata(context); | |
| 47 | + var unifyResult = context.GetRequiredService<IUnifyResultProvider>(); | |
| 48 | + // 执行规范化异常处理 | |
| 49 | + context.Result = unifyResult.OnException(context, exceptionMetadata); | |
| 50 | + | |
| 51 | + // 创建日志记录器 | |
| 52 | + var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<FriendlyExceptionFilter>>(); | |
| 53 | + | |
| 54 | + var errorMsg = ""; | |
| 55 | + if (exceptionMetadata.Errors != null) errorMsg = "\n" + JsonConvert.SerializeObject(exceptionMetadata.Errors); | |
| 56 | + | |
| 57 | + | |
| 58 | + // 记录拦截日常 | |
| 59 | + logger.LogError(context.Exception, context.Exception.Message + errorMsg); | |
| 60 | + } | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 获取异常元数据 | |
| 64 | + /// </summary> | |
| 65 | + /// <param name="context"></param> | |
| 66 | + /// <returns></returns> | |
| 67 | + public static ExceptionMetadata GetExceptionMetadata(ActionContext context) | |
| 68 | + { | |
| 69 | + object errorCode = default; | |
| 70 | + object originErrorCode = default; | |
| 71 | + object errors = default; | |
| 72 | + object data = default; | |
| 73 | + var statusCode = StatusCodes.Status500InternalServerError; | |
| 74 | + var isValidationException = false; // 判断是否是验证异常 | |
| 75 | + var isFriendlyException = false; | |
| 76 | + | |
| 77 | + // 判断是否是 ExceptionContext 或者 ActionExecutedContext | |
| 78 | + var exception = context is ExceptionContext exContext | |
| 79 | + ? exContext.Exception | |
| 80 | + : context is ActionExecutedContext edContext | |
| 81 | + ? edContext.Exception | |
| 82 | + : default; | |
| 83 | + | |
| 84 | + if (exception is AbpValidationException validationException) | |
| 85 | + { | |
| 86 | + errors = validationException.ValidationErrors; | |
| 87 | + isValidationException = true; | |
| 88 | + } | |
| 89 | + | |
| 90 | + // 判断是否是友好异常 | |
| 91 | + if (exception is UserFriendlyException friendlyException) | |
| 92 | + { | |
| 93 | + var statusCode2 = 500; | |
| 94 | + int.TryParse(friendlyException.Code, out statusCode2); | |
| 95 | + isFriendlyException = true; | |
| 96 | + errorCode = friendlyException.Code; | |
| 97 | + originErrorCode = friendlyException.Code; | |
| 98 | + statusCode = statusCode2 == 0 ? 403 : statusCode2; | |
| 99 | + errors = friendlyException.Message; | |
| 100 | + data = friendlyException.Data; | |
| 101 | + } | |
| 102 | + | |
| 103 | + return new ExceptionMetadata | |
| 104 | + { | |
| 105 | + StatusCode = statusCode, | |
| 106 | + ErrorCode = errorCode, | |
| 107 | + OriginErrorCode = originErrorCode, | |
| 108 | + Errors = errors, | |
| 109 | + Data = data | |
| 110 | + }; | |
| 111 | + } | |
| 112 | +} | |
| 0 | 113 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/Fiters/SucceededUnifyResultFilter.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/Fiters/SucceededUnifyResultFilter.cs | |
| 1 | +using System.Collections; | |
| 2 | +using System.Reflection; | |
| 3 | +using System.Text.Encodings.Web; | |
| 4 | +using System.Text.Json; | |
| 5 | +using Microsoft.AspNetCore.Http; | |
| 6 | +using Microsoft.AspNetCore.Http.Features; | |
| 7 | +using Microsoft.AspNetCore.Mvc; | |
| 8 | +using Microsoft.AspNetCore.Mvc.ApiExplorer; | |
| 9 | +using Microsoft.AspNetCore.Mvc.Controllers; | |
| 10 | +using Microsoft.AspNetCore.Mvc.Filters; | |
| 11 | +using Microsoft.AspNetCore.Mvc.Infrastructure; | |
| 12 | +using Microsoft.AspNetCore.Mvc.ModelBinding; | |
| 13 | +using Microsoft.AspNetCore.Mvc.RazorPages; | |
| 14 | +using Microsoft.Extensions.DependencyInjection; | |
| 15 | +using Microsoft.Extensions.Options; | |
| 16 | +using Volo.Abp.AspNetCore.Mvc; | |
| 17 | +using Volo.Abp.DependencyInjection; | |
| 18 | +using Yi.Framework.Core.Extensions; | |
| 19 | + | |
| 20 | +namespace Yi.Framework.AspNetCore.UnifyResult.Fiters; | |
| 21 | + | |
| 22 | +/// <summary> | |
| 23 | +/// 规范化结构(请求成功)过滤器 | |
| 24 | +/// </summary> | |
| 25 | +public class SucceededUnifyResultFilter : IAsyncActionFilter, IOrderedFilter | |
| 26 | +{ | |
| 27 | + /// <summary> | |
| 28 | + /// 过滤器排序 | |
| 29 | + /// </summary> | |
| 30 | + private const int FilterOrder = 8888; | |
| 31 | + | |
| 32 | + /// <summary> | |
| 33 | + /// 排序属性 | |
| 34 | + /// </summary> | |
| 35 | + public int Order => FilterOrder; | |
| 36 | + | |
| 37 | + /// <summary> | |
| 38 | + /// 处理规范化结果 | |
| 39 | + /// </summary> | |
| 40 | + /// <param name="context"></param> | |
| 41 | + /// <param name="next"></param> | |
| 42 | + /// <returns></returns> | |
| 43 | + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) | |
| 44 | + { | |
| 45 | + // 执行 Action 并获取结果 | |
| 46 | + var actionExecutedContext = await next(); | |
| 47 | + | |
| 48 | + // 排除 WebSocket 请求处理 | |
| 49 | + if (actionExecutedContext.HttpContext.IsWebSocketRequest()) return; | |
| 50 | + | |
| 51 | + // 处理已经含有状态码结果的 Result | |
| 52 | + if (actionExecutedContext.Result is IStatusCodeActionResult statusCodeResult && | |
| 53 | + statusCodeResult.StatusCode != null) | |
| 54 | + { | |
| 55 | + // 小于 200 或者 大于 299 都不是成功值,直接跳过 | |
| 56 | + if (statusCodeResult.StatusCode.Value < 200 || statusCodeResult.StatusCode.Value > 299) | |
| 57 | + { | |
| 58 | + // 处理规范化结果 | |
| 59 | + if (!CheckStatusCodeNonUnify(context.HttpContext, out var unifyRes)) | |
| 60 | + { | |
| 61 | + var httpContext = context.HttpContext; | |
| 62 | + var statusCode = statusCodeResult.StatusCode.Value; | |
| 63 | + | |
| 64 | + // 解决刷新 Token 时间和 Token 时间相近问题 | |
| 65 | + if (statusCodeResult.StatusCode.Value == StatusCodes.Status401Unauthorized | |
| 66 | + && httpContext.Response.Headers.ContainsKey("access-token") | |
| 67 | + && httpContext.Response.Headers.ContainsKey("x-access-token")) | |
| 68 | + { | |
| 69 | + httpContext.Response.StatusCode = statusCode = StatusCodes.Status403Forbidden; | |
| 70 | + } | |
| 71 | + | |
| 72 | + // 如果 Response 已经完成输出,则禁止写入 | |
| 73 | + if (httpContext.Response.HasStarted) return; | |
| 74 | + await unifyRes.OnResponseStatusCodes(httpContext, statusCode, | |
| 75 | + httpContext.RequestServices.GetService<IOptions<UnifyResultSettingsOptions>>()?.Value); | |
| 76 | + } | |
| 77 | + | |
| 78 | + return; | |
| 79 | + } | |
| 80 | + } | |
| 81 | + | |
| 82 | + // 如果出现异常,则不会进入该过滤器 | |
| 83 | + if (actionExecutedContext.Exception != null) return; | |
| 84 | + | |
| 85 | + // 获取控制器信息 | |
| 86 | + var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; | |
| 87 | + | |
| 88 | + // 判断是否支持 MVC 规范化处理,检测配置而已 | |
| 89 | + // if (!UnifyContext.CheckSupportMvcController(context.HttpContext, actionDescriptor, out _)) return; | |
| 90 | + | |
| 91 | + // 判断是否跳过规范化处理,检测NonUnifyAttribute而已 | |
| 92 | + if (CheckSucceededNonUnify(actionDescriptor.MethodInfo)) | |
| 93 | + { | |
| 94 | + return; | |
| 95 | + } | |
| 96 | + IUnifyResultProvider unifyResult = context.GetRequiredService<IUnifyResultProvider>(); | |
| 97 | + | |
| 98 | + // 处理 BadRequestObjectResult 类型规范化处理 | |
| 99 | + if (actionExecutedContext.Result is BadRequestObjectResult badRequestObjectResult) | |
| 100 | + { | |
| 101 | + // 解析验证消息 | |
| 102 | + var validationMetadata = GetValidationMetadata(badRequestObjectResult.Value); | |
| 103 | + | |
| 104 | + var result = unifyResult.OnValidateFailed(context, validationMetadata); | |
| 105 | + if (result != null) actionExecutedContext.Result = result; | |
| 106 | + } | |
| 107 | + else | |
| 108 | + { | |
| 109 | + IActionResult result = default; | |
| 110 | + | |
| 111 | + // 检查是否是有效的结果(可进行规范化的结果) | |
| 112 | + if (CheckVaildResult(actionExecutedContext.Result, out var data)) | |
| 113 | + { | |
| 114 | + result = unifyResult.OnSucceeded(actionExecutedContext, data); | |
| 115 | + } | |
| 116 | + | |
| 117 | + // 如果是不能规范化的结果类型,则跳过 | |
| 118 | + if (result == null) return; | |
| 119 | + | |
| 120 | + actionExecutedContext.Result = result; | |
| 121 | + } | |
| 122 | + } | |
| 123 | + | |
| 124 | + /// <summary> | |
| 125 | + /// 获取验证错误信息 | |
| 126 | + /// </summary> | |
| 127 | + /// <param name="errors"></param> | |
| 128 | + /// <returns></returns> | |
| 129 | + private static ValidationMetadata GetValidationMetadata(object errors) | |
| 130 | + { | |
| 131 | + ModelStateDictionary _modelState = null; | |
| 132 | + object validationResults = null; | |
| 133 | + (string message, string firstErrorMessage, string firstErrorProperty) = (default, default, default); | |
| 134 | + | |
| 135 | + // 判断是否是集合类型 | |
| 136 | + if (errors is IEnumerable && errors is not string) | |
| 137 | + { | |
| 138 | + // 如果是模型验证字典类型 | |
| 139 | + if (errors is ModelStateDictionary modelState) | |
| 140 | + { | |
| 141 | + _modelState = modelState; | |
| 142 | + // 将验证错误信息转换成字典并序列化成 Json | |
| 143 | + validationResults = modelState.Where(u => modelState[u.Key].ValidationState == ModelValidationState.Invalid) | |
| 144 | + .ToDictionary(u => u.Key, u => modelState[u.Key].Errors.Select(c => c.ErrorMessage).ToArray()); | |
| 145 | + } | |
| 146 | + // 如果是 ValidationProblemDetails 特殊类型 | |
| 147 | + else if (errors is ValidationProblemDetails validation) | |
| 148 | + { | |
| 149 | + validationResults = validation.Errors | |
| 150 | + .ToDictionary(u => u.Key, u => u.Value.ToArray()); | |
| 151 | + } | |
| 152 | + // 如果是字典类型 | |
| 153 | + else if (errors is Dictionary<string, string[]> dicResults) | |
| 154 | + { | |
| 155 | + validationResults = dicResults; | |
| 156 | + } | |
| 157 | + | |
| 158 | + message = JsonSerializer.Serialize(validationResults, new JsonSerializerOptions | |
| 159 | + { | |
| 160 | + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, | |
| 161 | + WriteIndented = true | |
| 162 | + }); | |
| 163 | + firstErrorMessage = (validationResults as Dictionary<string, string[]>).First().Value[0]; | |
| 164 | + firstErrorProperty = (validationResults as Dictionary<string, string[]>).First().Key; | |
| 165 | + } | |
| 166 | + // 其他类型 | |
| 167 | + else | |
| 168 | + { | |
| 169 | + validationResults = firstErrorMessage = message = errors?.ToString(); | |
| 170 | + } | |
| 171 | + | |
| 172 | + return new ValidationMetadata | |
| 173 | + { | |
| 174 | + ValidationResult = validationResults, | |
| 175 | + Message = message, | |
| 176 | + ModelState = _modelState, | |
| 177 | + FirstErrorProperty = firstErrorProperty, | |
| 178 | + FirstErrorMessage = firstErrorMessage | |
| 179 | + }; | |
| 180 | + } | |
| 181 | + | |
| 182 | + /// <summary> | |
| 183 | + /// 检查是否是有效的结果(可进行规范化的结果) | |
| 184 | + /// </summary> | |
| 185 | + /// <param name="result"></param> | |
| 186 | + /// <param name="data"></param> | |
| 187 | + /// <returns></returns> | |
| 188 | + private bool CheckVaildResult(IActionResult result, out object data) | |
| 189 | + { | |
| 190 | + data = default; | |
| 191 | + | |
| 192 | + // 排除以下结果,跳过规范化处理 | |
| 193 | + var isDataResult = result switch | |
| 194 | + { | |
| 195 | + ViewResult => false, | |
| 196 | + PartialViewResult => false, | |
| 197 | + FileResult => false, | |
| 198 | + ChallengeResult => false, | |
| 199 | + SignInResult => false, | |
| 200 | + SignOutResult => false, | |
| 201 | + RedirectToPageResult => false, | |
| 202 | + RedirectToRouteResult => false, | |
| 203 | + RedirectResult => false, | |
| 204 | + RedirectToActionResult => false, | |
| 205 | + LocalRedirectResult => false, | |
| 206 | + ForbidResult => false, | |
| 207 | + ViewComponentResult => false, | |
| 208 | + PageResult => false, | |
| 209 | + NotFoundResult => false, | |
| 210 | + NotFoundObjectResult => false, | |
| 211 | + _ => true, | |
| 212 | + }; | |
| 213 | + | |
| 214 | + // 目前支持返回值 ActionResult | |
| 215 | + if (isDataResult) data = result switch | |
| 216 | + { | |
| 217 | + // 处理内容结果 | |
| 218 | + ContentResult content => content.Content, | |
| 219 | + // 处理对象结果 | |
| 220 | + ObjectResult obj => obj.Value, | |
| 221 | + // 处理 JSON 对象 | |
| 222 | + JsonResult json => json.Value, | |
| 223 | + _ => null, | |
| 224 | + }; | |
| 225 | + | |
| 226 | + return isDataResult; | |
| 227 | + } | |
| 228 | + | |
| 229 | + | |
| 230 | + /// <summary> | |
| 231 | + /// 检查短路状态码(>=400)是否进行规范化处理 | |
| 232 | + /// </summary> | |
| 233 | + /// <param name="context"></param> | |
| 234 | + /// <param name="unifyResult"></param> | |
| 235 | + /// <returns>返回 true 跳过处理,否则进行规范化处理</returns> | |
| 236 | + internal static bool CheckStatusCodeNonUnify(HttpContext context, out IUnifyResultProvider unifyResult) | |
| 237 | + { | |
| 238 | + // 获取终点路由特性 | |
| 239 | + var endpointFeature = context.Features.Get<IEndpointFeature>(); | |
| 240 | + if (endpointFeature == null) return (unifyResult = null) == null; | |
| 241 | + | |
| 242 | + // 判断是否跳过规范化处理 | |
| 243 | + var isSkip = context.GetEndpoint()?.Metadata?.GetMetadata<NonUnifyAttribute>()!= null | |
| 244 | + || endpointFeature?.Endpoint?.Metadata?.GetMetadata<NonUnifyAttribute>() != null | |
| 245 | + || context.Request.Headers["accept"].ToString().Contains("odata.metadata=", StringComparison.OrdinalIgnoreCase) | |
| 246 | + || context.Request.Headers["accept"].ToString().Contains("odata.streaming=", StringComparison.OrdinalIgnoreCase); | |
| 247 | + | |
| 248 | + if (isSkip == true) unifyResult = null; | |
| 249 | + else | |
| 250 | + { | |
| 251 | + unifyResult = context.RequestServices.GetRequiredService<IUnifyResultProvider>(); | |
| 252 | + } | |
| 253 | + | |
| 254 | + return unifyResult == null || isSkip; | |
| 255 | + } | |
| 256 | + | |
| 257 | + /// <summary> | |
| 258 | + /// 检查请求成功是否进行规范化处理 | |
| 259 | + /// </summary> | |
| 260 | + /// <param name="method"></param> | |
| 261 | + /// <param name="isWebRequest"></param> | |
| 262 | + /// <returns>返回 true 跳过处理,否则进行规范化处理</returns> | |
| 263 | + private bool CheckSucceededNonUnify(MethodInfo method, bool isWebRequest = true) | |
| 264 | + { | |
| 265 | + // 判断是否跳过规范化处理 | |
| 266 | + var isSkip = method.CustomAttributes.Any(x => typeof(NonUnifyAttribute).IsAssignableFrom(x.AttributeType) || typeof(ProducesResponseTypeAttribute).IsAssignableFrom(x.AttributeType) || typeof(IApiResponseMetadataProvider).IsAssignableFrom(x.AttributeType)) | |
| 267 | + || method.ReflectedType.IsDefined(typeof(NonUnifyAttribute), true) | |
| 268 | + || method.DeclaringType.Assembly.GetName().Name.StartsWith("Microsoft.AspNetCore.OData"); | |
| 269 | + | |
| 270 | + if (!isWebRequest) | |
| 271 | + { | |
| 272 | + return isSkip; | |
| 273 | + } | |
| 274 | + return isSkip; | |
| 275 | + } | |
| 276 | +} | |
| 0 | 277 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/IUnifyResultProvider.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/IUnifyResultProvider.cs | |
| 1 | +// MIT 许可证 | |
| 2 | +// | |
| 3 | +// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者 | |
| 4 | +// | |
| 5 | +// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利, | |
| 6 | +// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本, | |
| 7 | +// 以及再授权被配发了本软件的人如上的权利,须在下列条件下: | |
| 8 | +// | |
| 9 | +// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | |
| 10 | +// | |
| 11 | +// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。 | |
| 12 | +// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中, | |
| 13 | +// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | |
| 14 | + | |
| 15 | +using Microsoft.AspNetCore.Http; | |
| 16 | +using Microsoft.AspNetCore.Mvc; | |
| 17 | +using Microsoft.AspNetCore.Mvc.Filters; | |
| 18 | + | |
| 19 | +namespace Yi.Framework.AspNetCore.UnifyResult; | |
| 20 | + | |
| 21 | +/// <summary> | |
| 22 | +/// 规范化结果提供器 | |
| 23 | +/// </summary> | |
| 24 | +public interface IUnifyResultProvider | |
| 25 | +{ | |
| 26 | + /// <summary> | |
| 27 | + /// 异常返回值 | |
| 28 | + /// </summary> | |
| 29 | + /// <param name="context"></param> | |
| 30 | + /// <param name="metadata"></param> | |
| 31 | + /// <returns></returns> | |
| 32 | + IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata); | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 成功返回值 | |
| 36 | + /// </summary> | |
| 37 | + /// <param name="context"></param> | |
| 38 | + /// <param name="data"></param> | |
| 39 | + /// <returns></returns> | |
| 40 | + IActionResult OnSucceeded(ActionExecutedContext context, object data); | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// 验证失败返回值 | |
| 44 | + /// </summary> | |
| 45 | + /// <param name="context"></param> | |
| 46 | + /// <param name="metadata"></param> | |
| 47 | + /// <returns></returns> | |
| 48 | + IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata); | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 拦截返回状态码 | |
| 52 | + /// </summary> | |
| 53 | + /// <param name="context"></param> | |
| 54 | + /// <param name="statusCode"></param> | |
| 55 | + /// <param name="unifyResultSettings"></param> | |
| 56 | + /// <returns></returns> | |
| 57 | + Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings = default); | |
| 58 | +} | |
| 0 | 59 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/NonUnifyAttribute.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/NonUnifyAttribute.cs | |
| 1 | +// MIT 许可证 | |
| 2 | +// | |
| 3 | +// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者 | |
| 4 | +// | |
| 5 | +// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利, | |
| 6 | +// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本, | |
| 7 | +// 以及再授权被配发了本软件的人如上的权利,须在下列条件下: | |
| 8 | +// | |
| 9 | +// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | |
| 10 | +// | |
| 11 | +// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。 | |
| 12 | +// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中, | |
| 13 | +// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | |
| 14 | + | |
| 15 | +namespace Yi.Framework.AspNetCore.UnifyResult; | |
| 16 | + | |
| 17 | +/// <summary> | |
| 18 | +/// 禁止规范化处理 | |
| 19 | +/// </summary> | |
| 20 | +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] | |
| 21 | +public sealed class NonUnifyAttribute : Attribute | |
| 22 | +{ | |
| 23 | +} | |
| 0 | 24 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/Providers/RESTfulResultProvider.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/Providers/RESTfulResultProvider.cs | |
| 1 | +// MIT 许可证 | |
| 2 | +// | |
| 3 | +// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者 | |
| 4 | +// | |
| 5 | +// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利, | |
| 6 | +// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本, | |
| 7 | +// 以及再授权被配发了本软件的人如上的权利,须在下列条件下: | |
| 8 | +// | |
| 9 | +// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | |
| 10 | +// | |
| 11 | +// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。 | |
| 12 | +// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中, | |
| 13 | +// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | |
| 14 | + | |
| 15 | +using Microsoft.AspNetCore.Http; | |
| 16 | +using Microsoft.AspNetCore.Mvc; | |
| 17 | +using Microsoft.AspNetCore.Mvc.Filters; | |
| 18 | +using Volo.Abp.DependencyInjection; | |
| 19 | + | |
| 20 | +namespace Yi.Framework.AspNetCore.UnifyResult.Providers; | |
| 21 | + | |
| 22 | +/// <summary> | |
| 23 | +/// RESTful 风格返回值 | |
| 24 | +/// </summary> | |
| 25 | +[Dependency(TryRegister = true)] | |
| 26 | +[ExposeServices(typeof(IUnifyResultProvider))] | |
| 27 | +public class RESTfulResultProvider : IUnifyResultProvider,ITransientDependency | |
| 28 | +{ | |
| 29 | + /// <summary> | |
| 30 | + /// 设置响应状态码 | |
| 31 | + /// </summary> | |
| 32 | + /// <param name="context"></param> | |
| 33 | + /// <param name="statusCode"></param> | |
| 34 | + /// <param name="unifyResultSettings"></param> | |
| 35 | + public static void SetResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings) | |
| 36 | + { | |
| 37 | + if (unifyResultSettings == null) return; | |
| 38 | + | |
| 39 | + // 篡改响应状态码 | |
| 40 | + if (unifyResultSettings.AdaptStatusCodes != null && unifyResultSettings.AdaptStatusCodes.Length > 0) | |
| 41 | + { | |
| 42 | + var adaptStatusCode = unifyResultSettings.AdaptStatusCodes.FirstOrDefault(u => u[0] == statusCode); | |
| 43 | + if (adaptStatusCode != null && adaptStatusCode.Length > 0 && adaptStatusCode[0] > 0) | |
| 44 | + { | |
| 45 | + context.Response.StatusCode = adaptStatusCode[1]; | |
| 46 | + return; | |
| 47 | + } | |
| 48 | + } | |
| 49 | + | |
| 50 | + // 如果为 null,则所有请求错误的状态码设置为 200 | |
| 51 | + if (unifyResultSettings.Return200StatusCodes == null) context.Response.StatusCode = 200; | |
| 52 | + // 否则只有里面的才设置为 200 | |
| 53 | + else if (unifyResultSettings.Return200StatusCodes.Contains(statusCode)) context.Response.StatusCode = 200; | |
| 54 | + else { } | |
| 55 | + } | |
| 56 | + | |
| 57 | + /// <summary> | |
| 58 | + /// 异常返回值 | |
| 59 | + /// </summary> | |
| 60 | + /// <param name="context"></param> | |
| 61 | + /// <param name="metadata"></param> | |
| 62 | + /// <returns></returns> | |
| 63 | + public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata) | |
| 64 | + { | |
| 65 | + return new JsonResult(RESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors)); | |
| 66 | + } | |
| 67 | + | |
| 68 | + /// <summary> | |
| 69 | + /// 成功返回值 | |
| 70 | + /// </summary> | |
| 71 | + /// <param name="context"></param> | |
| 72 | + /// <param name="data"></param> | |
| 73 | + /// <returns></returns> | |
| 74 | + public IActionResult OnSucceeded(ActionExecutedContext context, object data) | |
| 75 | + { | |
| 76 | + return new JsonResult(RESTfulResult(StatusCodes.Status200OK, true, data)); | |
| 77 | + } | |
| 78 | + | |
| 79 | + /// <summary> | |
| 80 | + /// 验证失败/业务异常返回值 | |
| 81 | + /// </summary> | |
| 82 | + /// <param name="context"></param> | |
| 83 | + /// <param name="metadata"></param> | |
| 84 | + /// <returns></returns> | |
| 85 | + public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata) | |
| 86 | + { | |
| 87 | + return new JsonResult(RESTfulResult(metadata.StatusCode ?? StatusCodes.Status400BadRequest, data: metadata.Data, errors: metadata.ValidationResult)); | |
| 88 | + } | |
| 89 | + | |
| 90 | + /// <summary> | |
| 91 | + /// 特定状态码返回值 | |
| 92 | + /// </summary> | |
| 93 | + /// <param name="context"></param> | |
| 94 | + /// <param name="statusCode"></param> | |
| 95 | + /// <param name="unifyResultSettings"></param> | |
| 96 | + /// <returns></returns> | |
| 97 | + public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings) | |
| 98 | + { | |
| 99 | + // 设置响应状态码 | |
| 100 | + SetResponseStatusCodes(context, statusCode, unifyResultSettings); | |
| 101 | + | |
| 102 | + switch (statusCode) | |
| 103 | + { | |
| 104 | + // 处理 401 状态码 | |
| 105 | + case StatusCodes.Status401Unauthorized: | |
| 106 | + await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "401 Unauthorized")); | |
| 107 | + break; | |
| 108 | + // 处理 403 状态码 | |
| 109 | + case StatusCodes.Status403Forbidden: | |
| 110 | + await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "403 Forbidden")); | |
| 111 | + break; | |
| 112 | + | |
| 113 | + default: break; | |
| 114 | + } | |
| 115 | + } | |
| 116 | + | |
| 117 | + /// <summary> | |
| 118 | + /// 返回 RESTful 风格结果集 | |
| 119 | + /// </summary> | |
| 120 | + /// <param name="statusCode"></param> | |
| 121 | + /// <param name="succeeded"></param> | |
| 122 | + /// <param name="data"></param> | |
| 123 | + /// <param name="errors"></param> | |
| 124 | + /// <returns></returns> | |
| 125 | + public static RESTfulResult<object> RESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default) | |
| 126 | + { | |
| 127 | + return new RESTfulResult<object> | |
| 128 | + { | |
| 129 | + StatusCode = statusCode, | |
| 130 | + Succeeded = succeeded, | |
| 131 | + Data = data, | |
| 132 | + Errors = errors, | |
| 133 | + Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() | |
| 134 | + }; | |
| 135 | + } | |
| 136 | +} | |
| 0 | 137 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/RESTfulResult.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/RESTfulResult.cs | |
| 1 | +// MIT 许可证 | |
| 2 | +// | |
| 3 | +// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者 | |
| 4 | +// | |
| 5 | +// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利, | |
| 6 | +// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本, | |
| 7 | +// 以及再授权被配发了本软件的人如上的权利,须在下列条件下: | |
| 8 | +// | |
| 9 | +// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | |
| 10 | +// | |
| 11 | +// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。 | |
| 12 | +// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中, | |
| 13 | +// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | |
| 14 | + | |
| 15 | +namespace Yi.Framework.AspNetCore.UnifyResult; | |
| 16 | + | |
| 17 | +/// <summary> | |
| 18 | +/// RESTful 风格结果集 | |
| 19 | +/// </summary> | |
| 20 | +/// <typeparam name="T"></typeparam> | |
| 21 | +public class RESTfulResult<T> | |
| 22 | +{ | |
| 23 | + /// <summary> | |
| 24 | + /// 状态码 | |
| 25 | + /// </summary> | |
| 26 | + public int? StatusCode { get; set; } | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 数据 | |
| 30 | + /// </summary> | |
| 31 | + public T Data { get; set; } | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 执行成功 | |
| 35 | + /// </summary> | |
| 36 | + public bool Succeeded { get; set; } | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 错误信息 | |
| 40 | + /// </summary> | |
| 41 | + public object Errors { get; set; } | |
| 42 | + | |
| 43 | + /// <summary> | |
| 44 | + /// 附加数据 | |
| 45 | + /// </summary> | |
| 46 | + public object Extras { get; set; } | |
| 47 | + | |
| 48 | + /// <summary> | |
| 49 | + /// 时间戳 | |
| 50 | + /// </summary> | |
| 51 | + public long Timestamp { get; set; } | |
| 52 | +} | |
| 0 | 53 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/UnifyResultExtensions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/UnifyResultExtensions.cs | |
| 1 | +using Microsoft.AspNetCore.Mvc; | |
| 2 | +using Microsoft.Extensions.DependencyInjection; | |
| 3 | +using Swashbuckle.AspNetCore.SwaggerGen; | |
| 4 | +using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; | |
| 5 | +using Volo.Abp.AspNetCore.Mvc.Response; | |
| 6 | +using Yi.Framework.AspNetCore.UnifyResult.Fiters; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.AspNetCore.UnifyResult; | |
| 9 | + | |
| 10 | +/// <summary> | |
| 11 | +/// 规范化接口 | |
| 12 | +/// 由于太多人反应,想兼容一套类似furion的返回情况,200状态码包一层更符合国内习惯,既然如此,不如直接搬过来 | |
| 13 | +/// </summary> | |
| 14 | +public static class UnifyResultExtensions | |
| 15 | +{ | |
| 16 | + public static IServiceCollection AddFurionUnifyResultApi(this IServiceCollection services) | |
| 17 | + { | |
| 18 | + //成功规范接口 | |
| 19 | + services.AddTransient<SucceededUnifyResultFilter>(); | |
| 20 | + //异常规范接口 | |
| 21 | + services.AddTransient<FriendlyExceptionFilter>(); | |
| 22 | + services.AddMvc(options => | |
| 23 | + { | |
| 24 | + options.Filters.RemoveAll(x => (x as ServiceFilterAttribute)?.ServiceType == typeof(AbpExceptionFilter)); | |
| 25 | + options.Filters.RemoveAll(x => (x as ServiceFilterAttribute)?.ServiceType == typeof(AbpNoContentActionFilter)); | |
| 26 | + options.Filters.AddService<SucceededUnifyResultFilter>(99); | |
| 27 | + options.Filters.AddService<FriendlyExceptionFilter>(100); | |
| 28 | + }); | |
| 29 | + return services; | |
| 30 | + } | |
| 31 | +} | |
| 0 | 32 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/UnifyResultSettingsOptions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/UnifyResultSettingsOptions.cs | |
| 1 | +// MIT 许可证 | |
| 2 | +// | |
| 3 | +// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者 | |
| 4 | +// | |
| 5 | +// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利, | |
| 6 | +// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本, | |
| 7 | +// 以及再授权被配发了本软件的人如上的权利,须在下列条件下: | |
| 8 | +// | |
| 9 | +// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | |
| 10 | +// | |
| 11 | +// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。 | |
| 12 | +// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中, | |
| 13 | +// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | |
| 14 | + | |
| 15 | +using Microsoft.Extensions.Configuration; | |
| 16 | + | |
| 17 | +namespace Yi.Framework.AspNetCore.UnifyResult; | |
| 18 | + | |
| 19 | +/// <summary> | |
| 20 | +/// 规范化配置选项 | |
| 21 | +/// </summary> | |
| 22 | +public sealed class UnifyResultSettingsOptions | |
| 23 | +{ | |
| 24 | + /// <summary> | |
| 25 | + /// 设置返回 200 状态码列表 | |
| 26 | + /// <para>默认:401,403,如果设置为 null,则标识所有状态码都返回 200 </para> | |
| 27 | + /// </summary> | |
| 28 | + public int[] Return200StatusCodes { get; set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 适配(篡改)Http 状态码(只支持短路状态码,比如 401,403,500 等) | |
| 32 | + /// </summary> | |
| 33 | + public int[][] AdaptStatusCodes { get; set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 是否支持 MVC 控制台规范化处理 | |
| 37 | + /// </summary> | |
| 38 | + public bool? SupportMvcController { get; set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 选项后期配置 | |
| 42 | + /// </summary> | |
| 43 | + /// <param name="options"></param> | |
| 44 | + /// <param name="configuration"></param> | |
| 45 | + public void PostConfigure(UnifyResultSettingsOptions options, IConfiguration configuration) | |
| 46 | + { | |
| 47 | + options.Return200StatusCodes ??= new[] { 401, 403 }; | |
| 48 | + options.SupportMvcController ??= false; | |
| 49 | + } | |
| 50 | +} | |
| 0 | 51 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/ValidationMetadata.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/UnifyResult/ValidationMetadata.cs | |
| 1 | +// MIT 许可证 | |
| 2 | +// | |
| 3 | +// 版权 © 2020-present 百小僧, 百签科技(广东)有限公司 和所有贡献者 | |
| 4 | +// | |
| 5 | +// 特此免费授予任何获得本软件副本和相关文档文件(下称“软件”)的人不受限制地处置该软件的权利, | |
| 6 | +// 包括不受限制地使用、复制、修改、合并、发布、分发、转授许可和/或出售该软件副本, | |
| 7 | +// 以及再授权被配发了本软件的人如上的权利,须在下列条件下: | |
| 8 | +// | |
| 9 | +// 上述版权声明和本许可声明应包含在该软件的所有副本或实质成分中。 | |
| 10 | +// | |
| 11 | +// 本软件是“如此”提供的,没有任何形式的明示或暗示的保证,包括但不限于对适销性、特定用途的适用性和不侵权的保证。 | |
| 12 | +// 在任何情况下,作者或版权持有人都不对任何索赔、损害或其他责任负责,无论这些追责来自合同、侵权或其它行为中, | |
| 13 | +// 还是产生于、源于或有关于本软件以及本软件的使用或其它处置。 | |
| 14 | + | |
| 15 | +using Microsoft.AspNetCore.Mvc.ModelBinding; | |
| 16 | + | |
| 17 | +namespace Yi.Framework.AspNetCore.UnifyResult; | |
| 18 | + | |
| 19 | +/// <summary> | |
| 20 | +/// 验证信息元数据 | |
| 21 | +/// </summary> | |
| 22 | +public sealed class ValidationMetadata | |
| 23 | +{ | |
| 24 | + /// <summary> | |
| 25 | + /// 验证结果 | |
| 26 | + /// </summary> | |
| 27 | + /// <remarks>返回字典或字符串类型</remarks> | |
| 28 | + public object ValidationResult { get; internal set; } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 异常消息 | |
| 32 | + /// </summary> | |
| 33 | + public string Message { get; internal set; } | |
| 34 | + | |
| 35 | + /// <summary> | |
| 36 | + /// 验证状态 | |
| 37 | + /// </summary> | |
| 38 | + public ModelStateDictionary ModelState { get; internal set; } | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 错误码 | |
| 42 | + /// </summary> | |
| 43 | + public object ErrorCode { get; internal set; } | |
| 44 | + | |
| 45 | + /// <summary> | |
| 46 | + /// 错误码(没被复写过的 ErrorCode ) | |
| 47 | + /// </summary> | |
| 48 | + public object OriginErrorCode { get; internal set; } | |
| 49 | + | |
| 50 | + /// <summary> | |
| 51 | + /// 状态码 | |
| 52 | + /// </summary> | |
| 53 | + public int? StatusCode { get; internal set; } | |
| 54 | + | |
| 55 | + /// <summary> | |
| 56 | + /// 首个错误属性 | |
| 57 | + /// </summary> | |
| 58 | + public string FirstErrorProperty { get; internal set; } | |
| 59 | + | |
| 60 | + /// <summary> | |
| 61 | + /// 首个错误消息 | |
| 62 | + /// </summary> | |
| 63 | + public string FirstErrorMessage { get; internal set; } | |
| 64 | + | |
| 65 | + /// <summary> | |
| 66 | + /// 额外数据 | |
| 67 | + /// </summary> | |
| 68 | + public object Data { get; internal set; } | |
| 69 | +} | |
| 0 | 70 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Yi.Framework.AspNetCore.csproj
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/Yi.Framework.AspNetCore.csproj | |
| 1 | +<Project Sdk="Microsoft.NET.Sdk"> | |
| 2 | + <Import Project="..\..\common.props" /> | |
| 3 | + | |
| 4 | + <ItemGroup> | |
| 5 | + <Compile Remove="Cors\**" /> | |
| 6 | + <EmbeddedResource Remove="Cors\**" /> | |
| 7 | + <None Remove="Cors\**" /> | |
| 8 | + </ItemGroup> | |
| 9 | + | |
| 10 | + <ItemGroup> | |
| 11 | + <PackageReference Include="Volo.Abp.Json" Version="$(AbpVersion)" /> | |
| 12 | + <PackageReference Include="Volo.Abp.Swashbuckle" Version="$(AbpVersion)" /> | |
| 13 | + </ItemGroup> | |
| 14 | + | |
| 15 | + <ItemGroup> | |
| 16 | + <ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" /> | |
| 17 | + </ItemGroup> | |
| 18 | + | |
| 19 | +</Project> | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.AspNetCore/YiFrameworkAspNetCoreModule.cs | |
| 1 | +using System.Reflection; | |
| 2 | +using Microsoft.AspNetCore.Builder; | |
| 3 | +using Microsoft.AspNetCore.Mvc; | |
| 4 | +using Microsoft.AspNetCore.Mvc.ApiExplorer; | |
| 5 | +using Microsoft.AspNetCore.Mvc.Controllers; | |
| 6 | +using Microsoft.Extensions.DependencyInjection; | |
| 7 | +using Microsoft.Extensions.DependencyInjection.Extensions; | |
| 8 | +using Microsoft.Extensions.Options; | |
| 9 | +using Microsoft.OpenApi.Models; | |
| 10 | +using Newtonsoft.Json.Linq; | |
| 11 | +using Swashbuckle.AspNetCore.SwaggerGen; | |
| 12 | +using Volo.Abp; | |
| 13 | +using Volo.Abp.AspNetCore.Mvc; | |
| 14 | +using Volo.Abp.AspNetCore.WebClientInfo; | |
| 15 | +using Volo.Abp.DependencyInjection; | |
| 16 | +using Volo.Abp.Modularity; | |
| 17 | +using Yi.Framework.AspNetCore.Mvc; | |
| 18 | +using Yi.Framework.Core; | |
| 19 | + | |
| 20 | +namespace Yi.Framework.AspNetCore | |
| 21 | +{ | |
| 22 | + /// <summary> | |
| 23 | + /// Yi框架ASP.NET Core模块 | |
| 24 | + /// </summary> | |
| 25 | + [DependsOn(typeof(YiFrameworkCoreModule))] | |
| 26 | + public class YiFrameworkAspNetCoreModule : AbpModule | |
| 27 | + { | |
| 28 | + /// <summary> | |
| 29 | + /// 配置服务后的处理 | |
| 30 | + /// </summary> | |
| 31 | + public override void PostConfigureServices(ServiceConfigurationContext context) | |
| 32 | + { | |
| 33 | + var services = context.Services; | |
| 34 | + | |
| 35 | + // 替换默认的WebClientInfoProvider为支持代理的实现 | |
| 36 | + services.Replace(new ServiceDescriptor( | |
| 37 | + typeof(IWebClientInfoProvider), | |
| 38 | + typeof(RealIpHttpContextWebClientInfoProvider), | |
| 39 | + ServiceLifetime.Transient)); | |
| 40 | + } | |
| 41 | + } | |
| 42 | +} | |
| 0 | 43 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/UnitOfWorkHangfireFilter.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/UnitOfWorkHangfireFilter.cs | |
| 1 | +using Hangfire.Server; | |
| 2 | +using Volo.Abp.DependencyInjection; | |
| 3 | +using Volo.Abp.Threading; | |
| 4 | +using Volo.Abp.Uow; | |
| 5 | + | |
| 6 | +namespace Yi.Framework.BackgroundWorkers.Hangfire; | |
| 7 | + | |
| 8 | +/// <summary> | |
| 9 | +/// Hangfire 工作单元过滤器 | |
| 10 | +/// 用于管理后台任务的事务处理 | |
| 11 | +/// </summary> | |
| 12 | +public sealed class UnitOfWorkHangfireFilter : IServerFilter, ISingletonDependency | |
| 13 | +{ | |
| 14 | + private const string UnitOfWorkItemKey = "HangfireUnitOfWork"; | |
| 15 | + private readonly IUnitOfWorkManager _unitOfWorkManager; | |
| 16 | + | |
| 17 | + /// <summary> | |
| 18 | + /// 初始化工作单元过滤器 | |
| 19 | + /// </summary> | |
| 20 | + /// <param name="unitOfWorkManager">工作单元管理器</param> | |
| 21 | + public UnitOfWorkHangfireFilter(IUnitOfWorkManager unitOfWorkManager) | |
| 22 | + { | |
| 23 | + _unitOfWorkManager = unitOfWorkManager; | |
| 24 | + } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 任务执行前的处理 | |
| 28 | + /// </summary> | |
| 29 | + /// <param name="context">执行上下文</param> | |
| 30 | + public void OnPerforming(PerformingContext context) | |
| 31 | + { | |
| 32 | + // 开启一个工作单元并存储到上下文中 | |
| 33 | + var uow = _unitOfWorkManager.Begin(); | |
| 34 | + context.Items.Add(UnitOfWorkItemKey, uow); | |
| 35 | + } | |
| 36 | + | |
| 37 | + /// <summary> | |
| 38 | + /// 任务执行后的处理 | |
| 39 | + /// </summary> | |
| 40 | + /// <param name="context">执行上下文</param> | |
| 41 | + public void OnPerformed(PerformedContext context) | |
| 42 | + { | |
| 43 | + AsyncHelper.RunSync(() => OnPerformedAsync(context)); | |
| 44 | + } | |
| 45 | + | |
| 46 | + /// <summary> | |
| 47 | + /// 任务执行后的异步处理 | |
| 48 | + /// </summary> | |
| 49 | + /// <param name="context">执行上下文</param> | |
| 50 | + private async Task OnPerformedAsync(PerformedContext context) | |
| 51 | + { | |
| 52 | + if (!context.Items.TryGetValue(UnitOfWorkItemKey, out var obj) || | |
| 53 | + obj is not IUnitOfWork uow) | |
| 54 | + { | |
| 55 | + return; | |
| 56 | + } | |
| 57 | + | |
| 58 | + try | |
| 59 | + { | |
| 60 | + // 如果没有异常且工作单元未完成,则提交事务 | |
| 61 | + if (context.Exception == null && !uow.IsCompleted) | |
| 62 | + { | |
| 63 | + await uow.CompleteAsync(); | |
| 64 | + } | |
| 65 | + else | |
| 66 | + { | |
| 67 | + // 否则回滚事务 | |
| 68 | + await uow.RollbackAsync(); | |
| 69 | + } | |
| 70 | + } | |
| 71 | + finally | |
| 72 | + { | |
| 73 | + // 确保工作单元被释放 | |
| 74 | + uow.Dispose(); | |
| 75 | + } | |
| 76 | + } | |
| 77 | +} | |
| 0 | 78 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj | |
| 1 | +<Project Sdk="Microsoft.NET.Sdk"> | |
| 2 | + | |
| 3 | + <Import Project="..\..\common.props" /> | |
| 4 | + | |
| 5 | + <PropertyGroup> | |
| 6 | + <TargetFramework>net8.0</TargetFramework> | |
| 7 | + <ImplicitUsings>enable</ImplicitUsings> | |
| 8 | + <Nullable>enable</Nullable> | |
| 9 | + </PropertyGroup> | |
| 10 | + | |
| 11 | + | |
| 12 | + <ItemGroup> | |
| 13 | + <PackageReference Include="Volo.Abp.BackgroundJobs.Hangfire" Version="$(AbpVersion)" /> | |
| 14 | + <PackageReference Include="Volo.Abp.BackgroundWorkers.Hangfire" Version="$(AbpVersion)" /> | |
| 15 | + </ItemGroup> | |
| 16 | + | |
| 17 | + | |
| 18 | +</Project> | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs | |
| 1 | +using System.Linq.Expressions; | |
| 2 | +using Hangfire; | |
| 3 | +using Microsoft.Extensions.Configuration; | |
| 4 | +using Microsoft.Extensions.DependencyInjection; | |
| 5 | +using Volo.Abp.BackgroundJobs.Hangfire; | |
| 6 | +using Volo.Abp.BackgroundWorkers; | |
| 7 | +using Volo.Abp.BackgroundWorkers.Hangfire; | |
| 8 | +using Volo.Abp.DynamicProxy; | |
| 9 | + | |
| 10 | +namespace Yi.Framework.BackgroundWorkers.Hangfire; | |
| 11 | + | |
| 12 | +/// <summary> | |
| 13 | +/// Hangfire 后台任务模块 | |
| 14 | +/// </summary> | |
| 15 | +[DependsOn(typeof(AbpBackgroundWorkersHangfireModule), | |
| 16 | + typeof(AbpBackgroundJobsHangfireModule))] | |
| 17 | +public sealed class YiFrameworkBackgroundWorkersHangfireModule : AbpModule | |
| 18 | +{ | |
| 19 | + /// <summary> | |
| 20 | + /// 配置服务前的预处理 | |
| 21 | + /// </summary> | |
| 22 | + /// <param name="context">服务配置上下文</param> | |
| 23 | + public override void PreConfigureServices(ServiceConfigurationContext context) | |
| 24 | + { | |
| 25 | + // 添加 Hangfire 后台任务约定注册器 | |
| 26 | + context.Services.AddConventionalRegistrar(new YiHangfireConventionalRegistrar()); | |
| 27 | + } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// 应用程序初始化 | |
| 31 | + /// </summary> | |
| 32 | + /// <param name="context">应用程序初始化上下文</param> | |
| 33 | + public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) | |
| 34 | + { | |
| 35 | + // 获取后台任务管理器和所有 Hangfire 后台任务 | |
| 36 | + var backgroundWorkerManager = context.ServiceProvider.GetRequiredService<IBackgroundWorkerManager>(); | |
| 37 | + var workers = context.ServiceProvider.GetServices<IHangfireBackgroundWorker>(); | |
| 38 | + | |
| 39 | + // 获取配置 | |
| 40 | + var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>(); | |
| 41 | + | |
| 42 | + // 检查是否启用 Redis | |
| 43 | + var isRedisEnabled = configuration.GetValue<bool>("Redis:IsEnabled"); | |
| 44 | + | |
| 45 | + foreach (var worker in workers) | |
| 46 | + { | |
| 47 | + // 设置时区为本地时区(上海) | |
| 48 | + worker.TimeZone = TimeZoneInfo.Local; | |
| 49 | + | |
| 50 | + if (isRedisEnabled) | |
| 51 | + { | |
| 52 | + // Redis 模式:使用 ABP 后台任务管理器 | |
| 53 | + await backgroundWorkerManager.AddAsync(worker); | |
| 54 | + } | |
| 55 | + else | |
| 56 | + { | |
| 57 | + // 内存模式:直接使用 Hangfire | |
| 58 | + var unProxyWorker = ProxyHelper.UnProxy(worker); | |
| 59 | + | |
| 60 | + // 添加或更新循环任务 | |
| 61 | + RecurringJob.AddOrUpdate( | |
| 62 | + worker.RecurringJobId, | |
| 63 | + (Expression<Func<Task>>)(() => | |
| 64 | + ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(default)), | |
| 65 | + worker.CronExpression, | |
| 66 | + new RecurringJobOptions | |
| 67 | + { | |
| 68 | + TimeZone = worker.TimeZone | |
| 69 | + }); | |
| 70 | + } | |
| 71 | + } | |
| 72 | + } | |
| 73 | + | |
| 74 | + /// <summary> | |
| 75 | + /// 应用程序初始化前的预处理 | |
| 76 | + /// </summary> | |
| 77 | + /// <param name="context">应用程序初始化上下文</param> | |
| 78 | + public override void OnPreApplicationInitialization(ApplicationInitializationContext context) | |
| 79 | + { | |
| 80 | + // 添加工作单元过滤器 | |
| 81 | + var services = context.ServiceProvider; | |
| 82 | + GlobalJobFilters.Filters.Add(services.GetRequiredService<UnitOfWorkHangfireFilter>()); | |
| 83 | + } | |
| 84 | +} | |
| 0 | 85 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs | |
| 1 | +using Volo.Abp.BackgroundWorkers.Hangfire; | |
| 2 | +using Volo.Abp.DependencyInjection; | |
| 3 | + | |
| 4 | +namespace Yi.Framework.BackgroundWorkers.Hangfire; | |
| 5 | + | |
| 6 | +/// <summary> | |
| 7 | +/// Hangfire 后台任务约定注册器 | |
| 8 | +/// </summary> | |
| 9 | +public sealed class YiHangfireConventionalRegistrar : DefaultConventionalRegistrar | |
| 10 | +{ | |
| 11 | + /// <summary> | |
| 12 | + /// 检查类型是否禁用约定注册 | |
| 13 | + /// </summary> | |
| 14 | + /// <param name="type">要检查的类型</param> | |
| 15 | + /// <returns>如果类型不是 IHangfireBackgroundWorker 或已被禁用则返回 true</returns> | |
| 16 | + protected override bool IsConventionalRegistrationDisabled(Type type) | |
| 17 | + { | |
| 18 | + return !typeof(IHangfireBackgroundWorker).IsAssignableFrom(type) || | |
| 19 | + base.IsConventionalRegistrationDisabled(type); | |
| 20 | + } | |
| 21 | + | |
| 22 | + /// <summary> | |
| 23 | + /// 获取要暴露的服务类型列表 | |
| 24 | + /// </summary> | |
| 25 | + /// <param name="type">实现类型</param> | |
| 26 | + /// <returns>服务类型列表</returns> | |
| 27 | + protected override List<Type> GetExposedServiceTypes(Type type) | |
| 28 | + { | |
| 29 | + return new List<Type> | |
| 30 | + { | |
| 31 | + typeof(IHangfireBackgroundWorker) | |
| 32 | + }; | |
| 33 | + } | |
| 34 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs | |
| 1 | +using Hangfire.Dashboard; | |
| 2 | +using Microsoft.AspNetCore.Http; | |
| 3 | +using Microsoft.Extensions.DependencyInjection; | |
| 4 | +using Volo.Abp.DependencyInjection; | |
| 5 | +using Volo.Abp.Users; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.BackgroundWorkers.Hangfire; | |
| 8 | + | |
| 9 | +/// <summary> | |
| 10 | +/// Hangfire 仪表盘的令牌认证过滤器 | |
| 11 | +/// </summary> | |
| 12 | +public sealed class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, ITransientDependency | |
| 13 | +{ | |
| 14 | + private const string BearerPrefix = "Bearer "; | |
| 15 | + private const string TokenCookieKey = "Token"; | |
| 16 | + private const string HtmlContentType = "text/html"; | |
| 17 | + | |
| 18 | + private readonly IServiceProvider _serviceProvider; | |
| 19 | + private string _requiredUsername = "cc"; | |
| 20 | + private TimeSpan _tokenExpiration = TimeSpan.FromMinutes(10); | |
| 21 | + | |
| 22 | + /// <summary> | |
| 23 | + /// 初始化令牌认证过滤器 | |
| 24 | + /// </summary> | |
| 25 | + /// <param name="serviceProvider">服务提供者</param> | |
| 26 | + public YiTokenAuthorizationFilter(IServiceProvider serviceProvider) | |
| 27 | + { | |
| 28 | + _serviceProvider = serviceProvider; | |
| 29 | + } | |
| 30 | + | |
| 31 | + /// <summary> | |
| 32 | + /// 设置需要的用户名 | |
| 33 | + /// </summary> | |
| 34 | + /// <param name="username">允许访问的用户名</param> | |
| 35 | + /// <returns>当前实例,支持链式调用</returns> | |
| 36 | + public YiTokenAuthorizationFilter SetRequiredUsername(string username) | |
| 37 | + { | |
| 38 | + _requiredUsername = username ?? throw new ArgumentNullException(nameof(username)); | |
| 39 | + return this; | |
| 40 | + } | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// 设置令牌过期时间 | |
| 44 | + /// </summary> | |
| 45 | + /// <param name="expiration">过期时间间隔</param> | |
| 46 | + /// <returns>当前实例,支持链式调用</returns> | |
| 47 | + public YiTokenAuthorizationFilter SetTokenExpiration(TimeSpan expiration) | |
| 48 | + { | |
| 49 | + _tokenExpiration = expiration; | |
| 50 | + return this; | |
| 51 | + } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 授权验证 | |
| 55 | + /// </summary> | |
| 56 | + /// <param name="context">仪表盘上下文</param> | |
| 57 | + /// <returns>是否通过授权</returns> | |
| 58 | + public bool Authorize(DashboardContext context) | |
| 59 | + { | |
| 60 | + var httpContext = context.GetHttpContext(); | |
| 61 | + var currentUser = _serviceProvider.GetRequiredService<ICurrentUser>(); | |
| 62 | + | |
| 63 | + if (!currentUser.IsAuthenticated) | |
| 64 | + { | |
| 65 | + SetChallengeResponse(httpContext); | |
| 66 | + return false; | |
| 67 | + } | |
| 68 | + | |
| 69 | + // 如果验证通过,设置 cookie | |
| 70 | + var authorization = httpContext.Request.Headers.Authorization.ToString(); | |
| 71 | + if (!string.IsNullOrWhiteSpace(authorization) && authorization.StartsWith(BearerPrefix)) | |
| 72 | + { | |
| 73 | + var token = authorization[BearerPrefix.Length..]; | |
| 74 | + SetTokenCookie(httpContext, token); | |
| 75 | + } | |
| 76 | + | |
| 77 | + return currentUser.UserName == _requiredUsername; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /// <summary> | |
| 81 | + /// 设置认证挑战响应 | |
| 82 | + /// 当用户未认证时,返回一个包含令牌输入表单的HTML页面 | |
| 83 | + /// </summary> | |
| 84 | + /// <param name="httpContext">HTTP 上下文</param> | |
| 85 | + private void SetChallengeResponse(HttpContext httpContext) | |
| 86 | + { | |
| 87 | + httpContext.Response.StatusCode = 401; | |
| 88 | + httpContext.Response.ContentType = HtmlContentType; | |
| 89 | + | |
| 90 | + var html = @" | |
| 91 | + <html> | |
| 92 | + <head> | |
| 93 | + <title>Hangfire Dashboard Authorization</title> | |
| 94 | + <style> | |
| 95 | + body { font-family: Arial, sans-serif; margin: 40px; } | |
| 96 | + .container { max-width: 400px; margin: 0 auto; } | |
| 97 | + .form-group { margin-bottom: 15px; } | |
| 98 | + input[type='text'] { width: 100%; padding: 8px; } | |
| 99 | + button { background: #337ab7; color: white; border: none; padding: 10px 15px; cursor: pointer; } | |
| 100 | + button:hover { background: #286090; } | |
| 101 | + </style> | |
| 102 | + </head> | |
| 103 | + <body> | |
| 104 | + <div class='container'> | |
| 105 | + <h2>Authorization Required</h2> | |
| 106 | + <div class='form-group'> | |
| 107 | + <input type='text' id='token' placeholder='Enter your Bearer token...' /> | |
| 108 | + </div> | |
| 109 | + <button onclick='authorize()'>Authorize</button> | |
| 110 | + </div> | |
| 111 | + <script> | |
| 112 | + function authorize() { | |
| 113 | + var token = document.getElementById('token').value; | |
| 114 | + if (token) { | |
| 115 | + document.cookie = 'Token=' + token + '; path=/'; | |
| 116 | + window.location.reload(); | |
| 117 | + } | |
| 118 | + } | |
| 119 | + </script> | |
| 120 | + </body> | |
| 121 | + </html>"; | |
| 122 | + | |
| 123 | + httpContext.Response.WriteAsync(html); | |
| 124 | + } | |
| 125 | + | |
| 126 | + /// <summary> | |
| 127 | + /// 设置令牌 Cookie | |
| 128 | + /// </summary> | |
| 129 | + /// <param name="httpContext">HTTP 上下文</param> | |
| 130 | + /// <param name="token">令牌值</param> | |
| 131 | + private void SetTokenCookie(HttpContext httpContext, string token) | |
| 132 | + { | |
| 133 | + var cookieOptions = new CookieOptions | |
| 134 | + { | |
| 135 | + Expires = DateTimeOffset.Now.Add(_tokenExpiration), | |
| 136 | + HttpOnly = true, | |
| 137 | + Secure = httpContext.Request.IsHttps, | |
| 138 | + SameSite = SameSiteMode.Lax | |
| 139 | + }; | |
| 140 | + | |
| 141 | + httpContext.Response.Cookies.Append(TokenCookieKey, token, cookieOptions); | |
| 142 | + } | |
| 143 | + | |
| 144 | + public Task<bool> AuthorizeAsync(DashboardContext context) | |
| 145 | + { | |
| 146 | + return Task.FromResult(Authorize(context)); | |
| 147 | + } | |
| 148 | +} | |
| 0 | 149 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/FreeSqlOptions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/FreeSqlOptions.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | +using FreeRedis; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.Caching.FreeRedis | |
| 9 | +{ | |
| 10 | + /// <summary> | |
| 11 | + /// 便于转到定义 | |
| 12 | + /// </summary> | |
| 13 | + public class FreeSqlOptions: ConnectionStringBuilder | |
| 14 | + { | |
| 15 | + | |
| 16 | + } | |
| 17 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/Yi.Framework.Caching.FreeRedis.csproj
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/Yi.Framework.Caching.FreeRedis.csproj | |
| 1 | +<Project Sdk="Microsoft.NET.Sdk"> | |
| 2 | + <Import Project="..\..\common.props" /> | |
| 3 | + | |
| 4 | + <PropertyGroup> | |
| 5 | + <TargetFramework>net8.0</TargetFramework> | |
| 6 | + <ImplicitUsings>enable</ImplicitUsings> | |
| 7 | + <Nullable>enable</Nullable> | |
| 8 | + </PropertyGroup> | |
| 9 | + | |
| 10 | + <ItemGroup> | |
| 11 | + <PackageReference Include="FreeRedis" Version="1.2.14" /> | |
| 12 | + <PackageReference Include="FreeRedis.DistributedCache" Version="1.2.5" /> | |
| 13 | + <PackageReference Include="Volo.Abp.Caching" Version="$(AbpVersion)" /> | |
| 14 | + </ItemGroup> | |
| 15 | + | |
| 16 | +</Project> | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | +using Microsoft.Extensions.Options; | |
| 7 | +using Volo.Abp.Caching; | |
| 8 | +using Volo.Abp.DependencyInjection; | |
| 9 | +using Volo.Abp.MultiTenancy; | |
| 10 | + | |
| 11 | +namespace Yi.Framework.Caching.FreeRedis | |
| 12 | +{ | |
| 13 | + /// <summary> | |
| 14 | + /// 缓存键标准化处理器 | |
| 15 | + /// 用于处理缓存键的格式化和多租户支持 | |
| 16 | + /// </summary> | |
| 17 | + [Dependency(ReplaceServices = true)] | |
| 18 | + public class YiDistributedCacheKeyNormalizer : IDistributedCacheKeyNormalizer, ITransientDependency | |
| 19 | + { | |
| 20 | + private readonly ICurrentTenant _currentTenant; | |
| 21 | + private readonly AbpDistributedCacheOptions _distributedCacheOptions; | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 构造函数 | |
| 25 | + /// </summary> | |
| 26 | + /// <param name="currentTenant">当前租户服务</param> | |
| 27 | + /// <param name="distributedCacheOptions">分布式缓存配置选项</param> | |
| 28 | + public YiDistributedCacheKeyNormalizer( | |
| 29 | + ICurrentTenant currentTenant, | |
| 30 | + IOptions<AbpDistributedCacheOptions> distributedCacheOptions) | |
| 31 | + { | |
| 32 | + _currentTenant = currentTenant; | |
| 33 | + _distributedCacheOptions = distributedCacheOptions.Value; | |
| 34 | + } | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// 标准化缓存键 | |
| 38 | + /// </summary> | |
| 39 | + /// <param name="args">缓存键标准化参数</param> | |
| 40 | + /// <returns>标准化后的缓存键</returns> | |
| 41 | + public virtual string NormalizeKey(DistributedCacheKeyNormalizeArgs args) | |
| 42 | + { | |
| 43 | + // 添加全局缓存前缀 | |
| 44 | + var normalizedKey = $"{_distributedCacheOptions.KeyPrefix}{args.Key}"; | |
| 45 | + | |
| 46 | + //todo 多租户支持已注释,如需启用取消注释即可 | |
| 47 | + //if (!args.IgnoreMultiTenancy && _currentTenant.Id.HasValue) | |
| 48 | + //{ | |
| 49 | + // normalizedKey = $"t:{_currentTenant.Id.Value},{normalizedKey}"; | |
| 50 | + //} | |
| 51 | + | |
| 52 | + return normalizedKey; | |
| 53 | + } | |
| 54 | + } | |
| 55 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs | |
| 1 | +using FreeRedis; | |
| 2 | +using Microsoft.Extensions.Caching.Distributed; | |
| 3 | +using Microsoft.Extensions.Configuration; | |
| 4 | +using Microsoft.Extensions.DependencyInjection; | |
| 5 | +using Microsoft.Extensions.DependencyInjection.Extensions; | |
| 6 | +using Volo.Abp.Caching; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.Caching.FreeRedis | |
| 9 | +{ | |
| 10 | + /// <summary> | |
| 11 | + /// FreeRedis缓存模块 | |
| 12 | + /// 提供基于FreeRedis的分布式缓存实现 | |
| 13 | + /// </summary> | |
| 14 | + [DependsOn(typeof(AbpCachingModule))] | |
| 15 | + public class YiFrameworkCachingFreeRedisModule : AbpModule | |
| 16 | + { | |
| 17 | + private const string RedisEnabledKey = "Redis:IsEnabled"; | |
| 18 | + private const string RedisConfigurationKey = "Redis:Configuration"; | |
| 19 | + | |
| 20 | + /// <summary> | |
| 21 | + /// 配置服务 | |
| 22 | + /// </summary> | |
| 23 | + /// <param name="context">服务配置上下文</param> | |
| 24 | + public override void ConfigureServices(ServiceConfigurationContext context) | |
| 25 | + { | |
| 26 | + var configuration = context.Services.GetConfiguration(); | |
| 27 | + | |
| 28 | + // 检查Redis是否启用 | |
| 29 | + if (!IsRedisEnabled(configuration)) | |
| 30 | + { | |
| 31 | + return; | |
| 32 | + } | |
| 33 | + | |
| 34 | + // 注册Redis服务 | |
| 35 | + RegisterRedisServices(context, configuration); | |
| 36 | + } | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 检查Redis是否启用 | |
| 40 | + /// </summary> | |
| 41 | + /// <param name="configuration">配置</param> | |
| 42 | + /// <returns>是否启用Redis</returns> | |
| 43 | + private static bool IsRedisEnabled(IConfiguration configuration) | |
| 44 | + { | |
| 45 | + var redisEnabled = configuration[RedisEnabledKey]; | |
| 46 | + return redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled); | |
| 47 | + } | |
| 48 | + | |
| 49 | + /// <summary> | |
| 50 | + /// 注册Redis相关服务 | |
| 51 | + /// </summary> | |
| 52 | + /// <param name="context">服务配置上下文</param> | |
| 53 | + /// <param name="configuration">配置</param> | |
| 54 | + private static void RegisterRedisServices(ServiceConfigurationContext context, IConfiguration configuration) | |
| 55 | + { | |
| 56 | + var redisConfiguration = configuration[RedisConfigurationKey]; | |
| 57 | + var redisClient = new RedisClient(redisConfiguration); | |
| 58 | + | |
| 59 | + context.Services.AddSingleton<IRedisClient>(redisClient); | |
| 60 | + context.Services.Replace(ServiceDescriptor.Singleton<IDistributedCache>( | |
| 61 | + new DistributedCache(redisClient))); | |
| 62 | + } | |
| 63 | + } | |
| 64 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IOrderNum.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IOrderNum.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Data | |
| 8 | +{ | |
| 9 | + /// <summary> | |
| 10 | + /// 排序接口 | |
| 11 | + /// </summary> | |
| 12 | + /// <remarks> | |
| 13 | + /// 实现此接口的实体类将支持排序功能 | |
| 14 | + /// 通常用于列表数据的展示顺序控制 | |
| 15 | + /// </remarks> | |
| 16 | + public interface IOrderNum | |
| 17 | + { | |
| 18 | + /// <summary> | |
| 19 | + /// 排序号 | |
| 20 | + /// </summary> | |
| 21 | + /// <remarks> | |
| 22 | + /// 数字越小越靠前,默认为0 | |
| 23 | + /// </remarks> | |
| 24 | + int OrderNum { get; set; } | |
| 25 | + } | |
| 26 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IState.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Data/IState.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Data | |
| 8 | +{ | |
| 9 | + /// <summary> | |
| 10 | + /// 状态接口 | |
| 11 | + /// </summary> | |
| 12 | + /// <remarks> | |
| 13 | + /// 实现此接口的实体类将支持启用/禁用状态管理 | |
| 14 | + /// 用于控制数据记录的可用状态 | |
| 15 | + /// </remarks> | |
| 16 | + public interface IState | |
| 17 | + { | |
| 18 | + /// <summary> | |
| 19 | + /// 状态标识 | |
| 20 | + /// </summary> | |
| 21 | + /// <remarks> | |
| 22 | + /// true表示启用,false表示禁用 | |
| 23 | + /// </remarks> | |
| 24 | + bool State { get; set; } | |
| 25 | + } | |
| 26 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/FileTypeEnum.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Enums | |
| 8 | +{ | |
| 9 | + /// <summary> | |
| 10 | + /// 文件类型枚举 | |
| 11 | + /// </summary> | |
| 12 | + /// <remarks> | |
| 13 | + /// 用于定义系统支持的文件类型分类 | |
| 14 | + /// 主要用于文件上传和存储时的类型区分 | |
| 15 | + /// </remarks> | |
| 16 | + public enum FileTypeEnum | |
| 17 | + { | |
| 18 | + /// <summary> | |
| 19 | + /// 普通文件 | |
| 20 | + /// </summary> | |
| 21 | + file = 0, | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 图片文件 | |
| 25 | + /// </summary> | |
| 26 | + image = 1, | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 缩略图文件 | |
| 30 | + /// </summary> | |
| 31 | + thumbnail = 2, | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// Excel文件 | |
| 35 | + /// </summary> | |
| 36 | + excel = 3, | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 临时文件 | |
| 40 | + /// </summary> | |
| 41 | + temp = 4 | |
| 42 | + } | |
| 43 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/OrderByEnum.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/OrderByEnum.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Enums | |
| 8 | +{ | |
| 9 | + /// <summary> | |
| 10 | + /// 排序方向枚举 | |
| 11 | + /// </summary> | |
| 12 | + /// <remarks> | |
| 13 | + /// 用于定义数据查询时的排序方向 | |
| 14 | + /// 常用于列表数据排序 | |
| 15 | + /// </remarks> | |
| 16 | + public enum OrderByEnum | |
| 17 | + { | |
| 18 | + /// <summary> | |
| 19 | + /// 升序排列 | |
| 20 | + /// </summary> | |
| 21 | + Asc = 0, | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 降序排列 | |
| 25 | + /// </summary> | |
| 26 | + Desc = 1 | |
| 27 | + } | |
| 28 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/QueryOperatorEnum.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Enums | |
| 8 | +{ | |
| 9 | + /// <summary> | |
| 10 | + /// 查询操作符枚举 | |
| 11 | + /// </summary> | |
| 12 | + /// <remarks> | |
| 13 | + /// 定义查询条件中支持的操作符类型 | |
| 14 | + /// 用于构建动态查询条件 | |
| 15 | + /// </remarks> | |
| 16 | + public enum QueryOperatorEnum | |
| 17 | + { | |
| 18 | + /// <summary> | |
| 19 | + /// 等于 | |
| 20 | + /// </summary> | |
| 21 | + Equal = 0, | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 模糊匹配 | |
| 25 | + /// </summary> | |
| 26 | + Like = 1, | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 大于 | |
| 30 | + /// </summary> | |
| 31 | + GreaterThan = 2, | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 大于或等于 | |
| 35 | + /// </summary> | |
| 36 | + GreaterThanOrEqual = 3, | |
| 37 | + | |
| 38 | + /// <summary> | |
| 39 | + /// 小于 | |
| 40 | + /// </summary> | |
| 41 | + LessThan = 4, | |
| 42 | + | |
| 43 | + /// <summary> | |
| 44 | + /// 小于或等于 | |
| 45 | + /// </summary> | |
| 46 | + LessThanOrEqual = 5, | |
| 47 | + | |
| 48 | + /// <summary> | |
| 49 | + /// 在指定集合中 | |
| 50 | + /// </summary> | |
| 51 | + In = 6, | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 不在指定集合中 | |
| 55 | + /// </summary> | |
| 56 | + NotIn = 7, | |
| 57 | + | |
| 58 | + /// <summary> | |
| 59 | + /// 左侧模糊匹配 | |
| 60 | + /// </summary> | |
| 61 | + LikeLeft = 8, | |
| 62 | + | |
| 63 | + /// <summary> | |
| 64 | + /// 右侧模糊匹配 | |
| 65 | + /// </summary> | |
| 66 | + LikeRight = 9, | |
| 67 | + | |
| 68 | + /// <summary> | |
| 69 | + /// 不等于 | |
| 70 | + /// </summary> | |
| 71 | + NoEqual = 10, | |
| 72 | + | |
| 73 | + /// <summary> | |
| 74 | + /// 为null或空 | |
| 75 | + /// </summary> | |
| 76 | + IsNullOrEmpty = 11, | |
| 77 | + | |
| 78 | + /// <summary> | |
| 79 | + /// 不为null | |
| 80 | + /// </summary> | |
| 81 | + IsNot = 12, | |
| 82 | + | |
| 83 | + /// <summary> | |
| 84 | + /// 不匹配 | |
| 85 | + /// </summary> | |
| 86 | + NoLike = 13, | |
| 87 | + | |
| 88 | + /// <summary> | |
| 89 | + /// 日期范围 | |
| 90 | + /// </summary> | |
| 91 | + /// <remarks> | |
| 92 | + /// 使用"|"分隔起始和结束日期 | |
| 93 | + /// </remarks> | |
| 94 | + DateRange = 14 | |
| 95 | + } | |
| 96 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Enums/ResultCodeEnum.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Enums | |
| 8 | +{ | |
| 9 | + /// <summary> | |
| 10 | + /// API返回状态码枚举 | |
| 11 | + /// </summary> | |
| 12 | + /// <remarks> | |
| 13 | + /// 定义API接口统一的返回状态码 | |
| 14 | + /// 遵循HTTP状态码规范 | |
| 15 | + /// </remarks> | |
| 16 | + public enum ResultCodeEnum | |
| 17 | + { | |
| 18 | + /// <summary> | |
| 19 | + /// 操作成功 | |
| 20 | + /// </summary> | |
| 21 | + Success = 200, | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 未授权访问 | |
| 25 | + /// </summary> | |
| 26 | + NoPermission = 401, | |
| 27 | + | |
| 28 | + /// <summary> | |
| 29 | + /// 访问被拒绝 | |
| 30 | + /// </summary> | |
| 31 | + Denied = 403, | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 操作失败 | |
| 35 | + /// </summary> | |
| 36 | + NotSuccess = 500 | |
| 37 | + } | |
| 38 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Extensions/HttpContextExtensions.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Extensions/HttpContextExtensions.cs | |
| 1 | +using System.Text; | |
| 2 | +using System.Text.RegularExpressions; | |
| 3 | +using Microsoft.AspNetCore.Http; | |
| 4 | + | |
| 5 | +namespace Yi.Framework.Core.Extensions | |
| 6 | +{ | |
| 7 | + /// <summary> | |
| 8 | + /// HttpContext扩展方法类 | |
| 9 | + /// </summary> | |
| 10 | + public static class HttpContextExtensions | |
| 11 | + { | |
| 12 | + /// <summary> | |
| 13 | + /// 设置内联文件下载响应头 | |
| 14 | + /// </summary> | |
| 15 | + /// <param name="httpContext">HTTP上下文</param> | |
| 16 | + /// <param name="fileName">文件名</param> | |
| 17 | + public static void FileInlineHandle(this HttpContext httpContext, string fileName) | |
| 18 | + { | |
| 19 | + var encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.UTF8); | |
| 20 | + httpContext.Response.Headers.Add("Content-Disposition", $"inline;filename={encodeFilename}"); | |
| 21 | + } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 设置附件下载响应头 | |
| 25 | + /// </summary> | |
| 26 | + /// <param name="httpContext">HTTP上下文</param> | |
| 27 | + /// <param name="fileName">文件名</param> | |
| 28 | + public static void FileAttachmentHandle(this HttpContext httpContext, string fileName) | |
| 29 | + { | |
| 30 | + var encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.UTF8); | |
| 31 | + httpContext.Response.Headers.Add("Content-Disposition", $"attachment;filename={encodeFilename}"); | |
| 32 | + } | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 获取客户端首选语言 | |
| 36 | + /// </summary> | |
| 37 | + /// <param name="httpContext">HTTP上下文</param> | |
| 38 | + /// <returns>语言代码,默认返回zh-CN</returns> | |
| 39 | + public static string GetLanguage(this HttpContext httpContext) | |
| 40 | + { | |
| 41 | + const string defaultLanguage = "zh-CN"; | |
| 42 | + var acceptLanguage = httpContext.Request.Headers["Accept-Language"].FirstOrDefault(); | |
| 43 | + | |
| 44 | + return string.IsNullOrEmpty(acceptLanguage) | |
| 45 | + ? defaultLanguage | |
| 46 | + : acceptLanguage.Split(',')[0]; | |
| 47 | + } | |
| 48 | + | |
| 49 | + /// <summary> | |
| 50 | + /// 判断是否为Ajax请求 | |
| 51 | + /// </summary> | |
| 52 | + /// <param name="request">HTTP请求</param> | |
| 53 | + /// <returns>是否为Ajax请求</returns> | |
| 54 | + public static bool IsAjaxRequest(this HttpRequest request) | |
| 55 | + { | |
| 56 | + const string ajaxHeader = "XMLHttpRequest"; | |
| 57 | + return ajaxHeader.Equals(request.Headers["X-Requested-With"], | |
| 58 | + StringComparison.OrdinalIgnoreCase); | |
| 59 | + } | |
| 60 | + | |
| 61 | + /// <summary> | |
| 62 | + /// 获取客户端IP地址 | |
| 63 | + /// </summary> | |
| 64 | + /// <param name="context">HTTP上下文</param> | |
| 65 | + /// <returns>客户端IP地址</returns> | |
| 66 | + public static string GetClientIp(this HttpContext context) | |
| 67 | + { | |
| 68 | + const string localhost = "127.0.0.1"; | |
| 69 | + if (context == null) return string.Empty; | |
| 70 | + | |
| 71 | + // 尝试获取X-Forwarded-For头 | |
| 72 | + var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); | |
| 73 | + | |
| 74 | + // 如果没有代理头,则获取远程IP | |
| 75 | + if (string.IsNullOrEmpty(ip)) | |
| 76 | + { | |
| 77 | + ip = context.Connection.RemoteIpAddress?.ToString(); | |
| 78 | + } | |
| 79 | + | |
| 80 | + // 处理特殊IP | |
| 81 | + if (string.IsNullOrEmpty(ip) || ip.Contains("::1")) | |
| 82 | + { | |
| 83 | + return localhost; | |
| 84 | + } | |
| 85 | + | |
| 86 | + // 清理IPv6格式 | |
| 87 | + ip = ip.Replace("::ffff:", localhost); | |
| 88 | + | |
| 89 | + // 移除端口号 | |
| 90 | + ip = Regex.Replace(ip, @":\d{1,5}$", ""); | |
| 91 | + | |
| 92 | + // 验证IP格式 | |
| 93 | + 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?)$") || | |
| 94 | + 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}$"); | |
| 95 | + | |
| 96 | + return isValidIp ? ip : localhost; | |
| 97 | + } | |
| 98 | + | |
| 99 | + /// <summary> | |
| 100 | + /// 获取User-Agent信息 | |
| 101 | + /// </summary> | |
| 102 | + /// <param name="context">HTTP上下文</param> | |
| 103 | + /// <returns>User-Agent字符串</returns> | |
| 104 | + public static string GetUserAgent(this HttpContext context) | |
| 105 | + { | |
| 106 | + return context.Request.Headers["User-Agent"].ToString(); | |
| 107 | + } | |
| 108 | + | |
| 109 | + /// <summary> | |
| 110 | + /// 获取用户权限声明值 | |
| 111 | + /// </summary> | |
| 112 | + /// <param name="context">HTTP上下文</param> | |
| 113 | + /// <param name="permissionsName">权限声明名称</param> | |
| 114 | + /// <returns>权限值数组</returns> | |
| 115 | + public static string[]? GetUserPermissions(this HttpContext context, string permissionsName) | |
| 116 | + { | |
| 117 | + return context.User.Claims | |
| 118 | + .Where(x => x.Type == permissionsName) | |
| 119 | + .Select(x => x.Value) | |
| 120 | + .ToArray(); | |
| 121 | + } | |
| 122 | + | |
| 123 | + /// <summary> | |
| 124 | + /// 判断是否为WebSocket请求 | |
| 125 | + /// </summary> | |
| 126 | + /// <param name="context">HTTP上下文</param> | |
| 127 | + /// <returns>是否为WebSocket请求</returns> | |
| 128 | + public static bool IsWebSocketRequest(this HttpContext context) | |
| 129 | + { | |
| 130 | + return context.WebSockets.IsWebSocketRequest || | |
| 131 | + context.Request.Path == "/ws"; | |
| 132 | + } | |
| 133 | + } | |
| 134 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/AssemblyHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/AssemblyHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Reflection; | |
| 5 | +using System.Text; | |
| 6 | +using System.Threading.Tasks; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.Core.Helper | |
| 9 | +{ | |
| 10 | + public static class AssemblyHelper | |
| 11 | + { | |
| 12 | + | |
| 13 | + /// <summary> | |
| 14 | + /// 此处统一获取程序集,排除微软内部相关 | |
| 15 | + /// </summary> | |
| 16 | + /// <returns></returns> | |
| 17 | + public static Assembly[] GetAllLoadAssembly() | |
| 18 | + { | |
| 19 | + return AppDomain.CurrentDomain.GetAssemblies(); | |
| 20 | + } | |
| 21 | + | |
| 22 | + public static List<Assembly> GetReferanceAssemblies(this AppDomain domain) | |
| 23 | + { | |
| 24 | + var list = new List<Assembly>(); | |
| 25 | + domain.GetAssemblies().ToList().ForEach(i => | |
| 26 | + { | |
| 27 | + GetReferanceAssemblies(i, list); | |
| 28 | + }); | |
| 29 | + return list; | |
| 30 | + } | |
| 31 | + private static void GetReferanceAssemblies(Assembly assembly, List<Assembly> list) | |
| 32 | + { | |
| 33 | + assembly.GetReferencedAssemblies().ToList().ForEach(i => | |
| 34 | + { | |
| 35 | + var ass = Assembly.Load(i); | |
| 36 | + if (!list.Contains(ass)) | |
| 37 | + { | |
| 38 | + list.Add(ass); | |
| 39 | + GetReferanceAssemblies(ass, list); | |
| 40 | + } | |
| 41 | + }); | |
| 42 | + } | |
| 43 | + | |
| 44 | + public static List<Type> GetClass(string assemblyFile, string? className = null, string? spaceName = null) | |
| 45 | + { | |
| 46 | + Assembly assembly = Assembly.Load(assemblyFile); | |
| 47 | + return assembly.GetTypes().Where(m => m.IsClass | |
| 48 | + && className == null ? true : m.Name == className | |
| 49 | + && spaceName == null ? true : m.Namespace == spaceName | |
| 50 | + && !m.Name.StartsWith("<>") | |
| 51 | + ).ToList(); | |
| 52 | + } | |
| 53 | + | |
| 54 | + public static List<Type> GetClassByParentClass(string assemblyFile, Type type) | |
| 55 | + { | |
| 56 | + Assembly assembly = Assembly.Load(assemblyFile); | |
| 57 | + | |
| 58 | + List<Type> resList = new List<Type>(); | |
| 59 | + | |
| 60 | + List<Type> typeList = assembly.GetTypes().Where(m => m.IsClass).ToList(); | |
| 61 | + foreach (var t in typeList) | |
| 62 | + { | |
| 63 | + var data = t.BaseType; | |
| 64 | + if (data == type) | |
| 65 | + { | |
| 66 | + resList.Add(t); | |
| 67 | + } | |
| 68 | + | |
| 69 | + } | |
| 70 | + return resList; | |
| 71 | + } | |
| 72 | + | |
| 73 | + | |
| 74 | + public static List<Type> GetClassByInterfaces(string assemblyFile, Type type) | |
| 75 | + { | |
| 76 | + Assembly assembly = Assembly.Load(assemblyFile); | |
| 77 | + | |
| 78 | + List<Type> resList = new List<Type>(); | |
| 79 | + | |
| 80 | + List<Type> typeList = assembly.GetTypes().Where(m => m.IsClass).ToList(); | |
| 81 | + foreach (var t in typeList) | |
| 82 | + { | |
| 83 | + var data = t.GetInterfaces(); | |
| 84 | + if (data.Contains(type)) | |
| 85 | + { | |
| 86 | + resList.Add(t); | |
| 87 | + } | |
| 88 | + | |
| 89 | + } | |
| 90 | + return resList; | |
| 91 | + } | |
| 92 | + | |
| 93 | + } | |
| 94 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/Base32Helper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/Base32Helper.cs | |
| 1 | +using System; | |
| 2 | +using System.Text; | |
| 3 | + | |
| 4 | +namespace Yi.Framework.Core.Helper | |
| 5 | +{ | |
| 6 | + public sealed class Base32Helper | |
| 7 | + { | |
| 8 | + | |
| 9 | + // the valid chars for the encoding | |
| 10 | + private static string ValidChars = "QAZ2WSX3" + "EDC4RFV5" + "TGB6YHN7" + "UJM8K9LP"; | |
| 11 | + | |
| 12 | + /// <summary> | |
| 13 | + /// Converts an array of bytes to a Base32-k string. | |
| 14 | + /// </summary> | |
| 15 | + public static string ToString(byte[] bytes) | |
| 16 | + { | |
| 17 | + StringBuilder sb = new StringBuilder(); // holds the base32 chars | |
| 18 | + byte index; | |
| 19 | + int hi = 5; | |
| 20 | + int currentByte = 0; | |
| 21 | + | |
| 22 | + while (currentByte < bytes.Length) | |
| 23 | + { | |
| 24 | + // do we need to use the next byte? | |
| 25 | + if (hi > 8) | |
| 26 | + { | |
| 27 | + // get the last piece from the current byte, shift it to the right | |
| 28 | + // and increment the byte counter | |
| 29 | + index = (byte)(bytes[currentByte++] >> hi - 5); | |
| 30 | + if (currentByte != bytes.Length) | |
| 31 | + { | |
| 32 | + // if we are not at the end, get the first piece from | |
| 33 | + // the next byte, clear it and shift it to the left | |
| 34 | + index = (byte)((byte)(bytes[currentByte] << 16 - hi) >> 3 | index); | |
| 35 | + } | |
| 36 | + | |
| 37 | + hi -= 3; | |
| 38 | + } | |
| 39 | + else if (hi == 8) | |
| 40 | + { | |
| 41 | + index = (byte)(bytes[currentByte++] >> 3); | |
| 42 | + hi -= 3; | |
| 43 | + } | |
| 44 | + else | |
| 45 | + { | |
| 46 | + | |
| 47 | + // simply get the stuff from the current byte | |
| 48 | + index = (byte)((byte)(bytes[currentByte] << 8 - hi) >> 3); | |
| 49 | + hi += 5; | |
| 50 | + } | |
| 51 | + | |
| 52 | + sb.Append(ValidChars[index]); | |
| 53 | + } | |
| 54 | + | |
| 55 | + return sb.ToString(); | |
| 56 | + } | |
| 57 | + | |
| 58 | + | |
| 59 | + /// <summary> | |
| 60 | + /// Converts a Base32-k string into an array of bytes. | |
| 61 | + /// </summary> | |
| 62 | + /// <exception cref="ArgumentException"> | |
| 63 | + /// Input string <paramref name="s">s</paramref> contains invalid Base32-k characters. | |
| 64 | + /// </exception> | |
| 65 | + public static byte[] FromBase32String(string str) | |
| 66 | + { | |
| 67 | + int numBytes = str.Length * 5 / 8; | |
| 68 | + byte[] bytes = new byte[numBytes]; | |
| 69 | + | |
| 70 | + // all UPPERCASE chars | |
| 71 | + str = str.ToUpper(); | |
| 72 | + | |
| 73 | + int bit_buffer; | |
| 74 | + int currentCharIndex; | |
| 75 | + int bits_in_buffer; | |
| 76 | + | |
| 77 | + if (str.Length < 3) | |
| 78 | + { | |
| 79 | + bytes[0] = (byte)(ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5); | |
| 80 | + return bytes; | |
| 81 | + } | |
| 82 | + | |
| 83 | + bit_buffer = ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5; | |
| 84 | + bits_in_buffer = 10; | |
| 85 | + currentCharIndex = 2; | |
| 86 | + for (int i = 0; i < bytes.Length; i++) | |
| 87 | + { | |
| 88 | + bytes[i] = (byte)bit_buffer; | |
| 89 | + bit_buffer >>= 8; | |
| 90 | + bits_in_buffer -= 8; | |
| 91 | + while (bits_in_buffer < 8 && currentCharIndex < str.Length) | |
| 92 | + { | |
| 93 | + bit_buffer |= ValidChars.IndexOf(str[currentCharIndex++]) << bits_in_buffer; | |
| 94 | + bits_in_buffer += 5; | |
| 95 | + } | |
| 96 | + } | |
| 97 | + | |
| 98 | + return bytes; | |
| 99 | + } | |
| 100 | + } | |
| 101 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ComputerHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ComputerHelper.cs | |
| 1 | +using System.Runtime.InteropServices; | |
| 2 | +using Newtonsoft.Json; | |
| 3 | + | |
| 4 | +namespace Yi.Framework.Core.Helper | |
| 5 | +{ | |
| 6 | + public class ComputerHelper | |
| 7 | + { | |
| 8 | + | |
| 9 | + /// <summary> | |
| 10 | + /// 将object转换为long,若转换失败,则返回0。不抛出异常。 | |
| 11 | + /// </summary> | |
| 12 | + /// <param name="str"></param> | |
| 13 | + /// <returns></returns> | |
| 14 | + private static long ParseToLong( object obj) | |
| 15 | + { | |
| 16 | + try | |
| 17 | + { | |
| 18 | + return long.Parse(obj.ToString()); | |
| 19 | + } | |
| 20 | + catch | |
| 21 | + { | |
| 22 | + return 0L; | |
| 23 | + } | |
| 24 | + } | |
| 25 | + | |
| 26 | + /// <summary> | |
| 27 | + /// 将string转换为DateTime,若转换失败,则返回日期最小值。不抛出异常。 | |
| 28 | + /// </summary> | |
| 29 | + /// <param name="str"></param> | |
| 30 | + /// <returns></returns> | |
| 31 | + private static DateTime ParseToDateTime( string str) | |
| 32 | + { | |
| 33 | + try | |
| 34 | + { | |
| 35 | + if (string.IsNullOrWhiteSpace(str)) | |
| 36 | + { | |
| 37 | + return DateTime.MinValue; | |
| 38 | + } | |
| 39 | + if (str.Contains("-") || str.Contains("/")) | |
| 40 | + { | |
| 41 | + return DateTime.Parse(str); | |
| 42 | + } | |
| 43 | + else | |
| 44 | + { | |
| 45 | + int length = str.Length; | |
| 46 | + switch (length) | |
| 47 | + { | |
| 48 | + case 4: | |
| 49 | + return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture); | |
| 50 | + case 6: | |
| 51 | + return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture); | |
| 52 | + case 8: | |
| 53 | + return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture); | |
| 54 | + case 10: | |
| 55 | + return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture); | |
| 56 | + case 12: | |
| 57 | + return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture); | |
| 58 | + case 14: | |
| 59 | + return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture); | |
| 60 | + default: | |
| 61 | + return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture); | |
| 62 | + } | |
| 63 | + } | |
| 64 | + } | |
| 65 | + catch | |
| 66 | + { | |
| 67 | + return DateTime.MinValue; | |
| 68 | + } | |
| 69 | + } | |
| 70 | + private static double ParseToDouble(object obj) | |
| 71 | + { | |
| 72 | + try | |
| 73 | + { | |
| 74 | + return double.Parse(obj.ToString()); | |
| 75 | + } | |
| 76 | + catch | |
| 77 | + { | |
| 78 | + return 0; | |
| 79 | + } | |
| 80 | + } | |
| 81 | + /// <summary> | |
| 82 | + /// CPU使用情况 | |
| 83 | + /// </summary> | |
| 84 | + /// <returns></returns> | |
| 85 | + public static CPUMetrics GetCPUMetrics() | |
| 86 | + { | |
| 87 | + CPUMetrics cpuMetrics = new CPUMetrics(); | |
| 88 | + var cpudetail = GetCPUDetails(); | |
| 89 | + cpuMetrics.CoreTotal = cpudetail.Cores; | |
| 90 | + cpuMetrics.LogicalProcessors =cpudetail.LogicalProcessors; | |
| 91 | + cpuMetrics.CPURate = Math.Ceiling(ParseToDouble(GetCPURate())); | |
| 92 | + cpuMetrics.FreeRate = 1 - cpuMetrics.CPURate; | |
| 93 | + return cpuMetrics; | |
| 94 | + } | |
| 95 | + /// <summary> | |
| 96 | + /// 内存使用情况 | |
| 97 | + /// </summary> | |
| 98 | + /// <returns></returns> | |
| 99 | + public static MemoryMetrics GetMemoryMetrics() | |
| 100 | + { | |
| 101 | + try | |
| 102 | + { | |
| 103 | + MemoryMetricsClient client = new(); | |
| 104 | + MemoryMetrics memoryMetrics = IsUnix() ? client.GetUnixMetrics() : client.GetWindowsMetrics(); | |
| 105 | + | |
| 106 | + memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB"; | |
| 107 | + memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB"; | |
| 108 | + memoryMetrics.TotalRAM = Math.Round(memoryMetrics.Total / 1024, 2) + "GB"; | |
| 109 | + memoryMetrics.RAMRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + "%"; | |
| 110 | + | |
| 111 | + return memoryMetrics; | |
| 112 | + } | |
| 113 | + catch (Exception ex) | |
| 114 | + { | |
| 115 | + Console.WriteLine("获取内存使用出错,msg=" + ex.Message + "," + ex.StackTrace); | |
| 116 | + } | |
| 117 | + return new MemoryMetrics(); | |
| 118 | + } | |
| 119 | + | |
| 120 | + /// <summary> | |
| 121 | + /// 获取磁盘信息 | |
| 122 | + /// </summary> | |
| 123 | + /// <returns></returns> | |
| 124 | + public static List<DiskInfo> GetDiskInfos() | |
| 125 | + { | |
| 126 | + List<DiskInfo> diskInfos = new(); | |
| 127 | + | |
| 128 | + if (IsUnix()) | |
| 129 | + { | |
| 130 | + try | |
| 131 | + { | |
| 132 | + string output = ShellHelper.Bash("df -m / | awk '{print $2,$3,$4,$5,$6}'"); | |
| 133 | + var arr = output.Split('\n', StringSplitOptions.RemoveEmptyEntries); | |
| 134 | + if (arr.Length == 0) return diskInfos; | |
| 135 | + | |
| 136 | + var rootDisk = arr[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries); | |
| 137 | + if (rootDisk == null || rootDisk.Length == 0) | |
| 138 | + { | |
| 139 | + return diskInfos; | |
| 140 | + } | |
| 141 | + DiskInfo diskInfo = new() | |
| 142 | + { | |
| 143 | + DiskName = "/", | |
| 144 | + TotalSize = long.Parse(rootDisk[0]) / 1024, | |
| 145 | + Used = long.Parse(rootDisk[1]) / 1024, | |
| 146 | + AvailableFreeSpace = long.Parse(rootDisk[2]) / 1024, | |
| 147 | + AvailablePercent = decimal.Parse(rootDisk[3].Replace("%", "")) | |
| 148 | + }; | |
| 149 | + diskInfos.Add(diskInfo); | |
| 150 | + } | |
| 151 | + catch (Exception ex) | |
| 152 | + { | |
| 153 | + Console.WriteLine("获取磁盘信息出错了" + ex.Message); | |
| 154 | + } | |
| 155 | + } | |
| 156 | + else | |
| 157 | + { | |
| 158 | + var driv = DriveInfo.GetDrives(); | |
| 159 | + foreach (var item in driv) | |
| 160 | + { | |
| 161 | + try | |
| 162 | + { | |
| 163 | + var obj = new DiskInfo() | |
| 164 | + { | |
| 165 | + DiskName = item.Name, | |
| 166 | + TypeName = item.DriveType.ToString(), | |
| 167 | + TotalSize = item.TotalSize / 1024 / 1024 / 1024, | |
| 168 | + AvailableFreeSpace = item.AvailableFreeSpace / 1024 / 1024 / 1024, | |
| 169 | + }; | |
| 170 | + obj.Used = obj.TotalSize - obj.AvailableFreeSpace; | |
| 171 | + obj.AvailablePercent = decimal.Ceiling(obj.Used / (decimal)obj.TotalSize * 100); | |
| 172 | + diskInfos.Add(obj); | |
| 173 | + } | |
| 174 | + catch (Exception ex) | |
| 175 | + { | |
| 176 | + Console.WriteLine("获取磁盘信息出错了" + ex.Message); | |
| 177 | + continue; | |
| 178 | + } | |
| 179 | + } | |
| 180 | + } | |
| 181 | + | |
| 182 | + return diskInfos; | |
| 183 | + } | |
| 184 | + | |
| 185 | + public static bool IsUnix() | |
| 186 | + { | |
| 187 | + var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux); | |
| 188 | + return isUnix; | |
| 189 | + } | |
| 190 | + | |
| 191 | + public static string GetCPURate() | |
| 192 | + { | |
| 193 | + string cpuRate; | |
| 194 | + if (IsUnix()) | |
| 195 | + { | |
| 196 | + string output = ShellHelper.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'"); | |
| 197 | + cpuRate = output.Trim(); | |
| 198 | + } | |
| 199 | + else | |
| 200 | + { | |
| 201 | + string output = ShellHelper.Cmd("wmic", "cpu get LoadPercentage"); | |
| 202 | + cpuRate = output.Replace("LoadPercentage", string.Empty).Trim(); | |
| 203 | + } | |
| 204 | + return cpuRate; | |
| 205 | + } | |
| 206 | + | |
| 207 | + /// <summary> | |
| 208 | + /// 获取系统运行时间 | |
| 209 | + /// </summary> | |
| 210 | + /// <returns></returns> | |
| 211 | + public static string GetRunTime() | |
| 212 | + { | |
| 213 | + string runTime = string.Empty; | |
| 214 | + try | |
| 215 | + { | |
| 216 | + if (IsUnix()) | |
| 217 | + { | |
| 218 | + string output = ShellHelper.Bash("uptime -s").Trim(); | |
| 219 | + runTime = DateTimeHelper.FormatTime(ParseToLong((DateTime.Now - ParseToDateTime(output)).TotalMilliseconds.ToString().Split('.')[0])); | |
| 220 | + } | |
| 221 | + else | |
| 222 | + { | |
| 223 | + string output = ShellHelper.Cmd("wmic", "OS get LastBootUpTime/Value"); | |
| 224 | + string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries); | |
| 225 | + if (outputArr.Length == 2) | |
| 226 | + { | |
| 227 | + runTime = DateTimeHelper.FormatTime(ParseToLong((DateTime.Now - ParseToDateTime( outputArr[1].Split('.')[0])).TotalMilliseconds.ToString().Split('.')[0])); | |
| 228 | + } | |
| 229 | + } | |
| 230 | + } | |
| 231 | + catch (Exception ex) | |
| 232 | + { | |
| 233 | + Console.WriteLine("获取runTime出错" + ex.Message); | |
| 234 | + } | |
| 235 | + return runTime; | |
| 236 | + } | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + public static CPUInfo GetCPUDetails() | |
| 241 | + { | |
| 242 | + int logicalProcessors = 0; | |
| 243 | + int cores = 0; | |
| 244 | + | |
| 245 | + if (IsUnix()) | |
| 246 | + { | |
| 247 | + string logicalOutput = ShellHelper.Bash("lscpu | grep '^CPU(s):' | awk '{print $2}'"); | |
| 248 | + logicalProcessors = int.Parse(logicalOutput.Trim()); | |
| 249 | + | |
| 250 | + string coresOutput = ShellHelper.Bash("lscpu | grep 'Core(s) per socket:' | awk '{print $4}'"); | |
| 251 | + string socketsOutput = ShellHelper.Bash("lscpu | grep 'Socket(s):' | awk '{print $2}'"); | |
| 252 | + cores = int.Parse(coresOutput.Trim()) * int.Parse(socketsOutput.Trim()); | |
| 253 | + } | |
| 254 | + else | |
| 255 | + { | |
| 256 | + string output = ShellHelper.Cmd("wmic", "cpu get NumberOfCores,NumberOfLogicalProcessors /format:csv"); | |
| 257 | + var lines = output.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); | |
| 258 | + | |
| 259 | + if (lines.Length > 1) | |
| 260 | + { | |
| 261 | + var values = lines[1].Split(','); | |
| 262 | + | |
| 263 | + cores = int.Parse(values[1].Trim()); | |
| 264 | + logicalProcessors =int.Parse(values[2].Trim()); | |
| 265 | + } | |
| 266 | + } | |
| 267 | + | |
| 268 | + return new CPUInfo | |
| 269 | + { | |
| 270 | + LogicalProcessors = logicalProcessors, | |
| 271 | + Cores = cores | |
| 272 | + }; | |
| 273 | + } | |
| 274 | + } | |
| 275 | + public class CPUInfo | |
| 276 | + { | |
| 277 | + public int LogicalProcessors { get; set; } | |
| 278 | + public int Cores { get; set; } | |
| 279 | + } | |
| 280 | + public class CPUMetrics | |
| 281 | + { | |
| 282 | + /// <summary> | |
| 283 | + /// 内核数 | |
| 284 | + /// </summary> | |
| 285 | + public int CoreTotal { get; set; } | |
| 286 | + /// <summary> | |
| 287 | + /// 逻辑处理器数 | |
| 288 | + /// </summary> | |
| 289 | + public int LogicalProcessors { get; set; } | |
| 290 | + /// <summary> | |
| 291 | + /// CPU使用率% | |
| 292 | + /// </summary> | |
| 293 | + public double CPURate { get; set; } | |
| 294 | + /// <summary> | |
| 295 | + /// CPU空闲率% | |
| 296 | + /// </summary> | |
| 297 | + public double FreeRate { get; set; } | |
| 298 | + } | |
| 299 | + | |
| 300 | + /// <summary> | |
| 301 | + /// 内存信息 | |
| 302 | + /// </summary> | |
| 303 | + public class MemoryMetrics | |
| 304 | + { | |
| 305 | + [JsonIgnore] | |
| 306 | + public double Total { get; set; } | |
| 307 | + [JsonIgnore] | |
| 308 | + public double Used { get; set; } | |
| 309 | + [JsonIgnore] | |
| 310 | + public double Free { get; set; } | |
| 311 | + | |
| 312 | + public string UsedRam { get; set; } | |
| 313 | + | |
| 314 | + /// <summary> | |
| 315 | + /// 总内存 GB | |
| 316 | + /// </summary> | |
| 317 | + public string TotalRAM { get; set; } | |
| 318 | + /// <summary> | |
| 319 | + /// 内存使用率 % | |
| 320 | + /// </summary> | |
| 321 | + public string RAMRate { get; set; } | |
| 322 | + /// <summary> | |
| 323 | + /// 空闲内存 | |
| 324 | + /// </summary> | |
| 325 | + public string FreeRam { get; set; } | |
| 326 | + } | |
| 327 | + | |
| 328 | + public class DiskInfo | |
| 329 | + { | |
| 330 | + /// <summary> | |
| 331 | + /// 磁盘名 | |
| 332 | + /// </summary> | |
| 333 | + public string DiskName { get; set; } | |
| 334 | + public string TypeName { get; set; } | |
| 335 | + public long TotalFree { get; set; } | |
| 336 | + public long TotalSize { get; set; } | |
| 337 | + /// <summary> | |
| 338 | + /// 已使用 | |
| 339 | + /// </summary> | |
| 340 | + public long Used { get; set; } | |
| 341 | + /// <summary> | |
| 342 | + /// 可使用 | |
| 343 | + /// </summary> | |
| 344 | + public long AvailableFreeSpace { get; set; } | |
| 345 | + public decimal AvailablePercent { get; set; } | |
| 346 | + } | |
| 347 | + | |
| 348 | + public class MemoryMetricsClient | |
| 349 | + { | |
| 350 | + #region 获取内存信息 | |
| 351 | + | |
| 352 | + /// <summary> | |
| 353 | + /// windows系统获取内存信息 | |
| 354 | + /// </summary> | |
| 355 | + /// <returns></returns> | |
| 356 | + public MemoryMetrics GetWindowsMetrics() | |
| 357 | + { | |
| 358 | + string output = ShellHelper.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value"); | |
| 359 | + var metrics = new MemoryMetrics(); | |
| 360 | + var lines = output.Trim().Split('\n', (char)StringSplitOptions.RemoveEmptyEntries); | |
| 361 | + | |
| 362 | + if (lines.Length <= 0) return metrics; | |
| 363 | + | |
| 364 | + var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries); | |
| 365 | + var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries); | |
| 366 | + | |
| 367 | + metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0); | |
| 368 | + metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);//m | |
| 369 | + metrics.Used = metrics.Total - metrics.Free; | |
| 370 | + | |
| 371 | + return metrics; | |
| 372 | + } | |
| 373 | + | |
| 374 | + /// <summary> | |
| 375 | + /// Unix系统获取 | |
| 376 | + /// </summary> | |
| 377 | + /// <returns></returns> | |
| 378 | + public MemoryMetrics GetUnixMetrics() | |
| 379 | + { | |
| 380 | + string output = ShellHelper.Bash(@" | |
| 381 | +# 从 /proc/meminfo 文件中提取总内存 | |
| 382 | + total_mem=$(cat /proc/meminfo | grep -i ""MemTotal"" | awk '{print $2}') | |
| 383 | + # 从 /proc/meminfo 文件中提取剩余内存 | |
| 384 | +free_mem=$(cat /proc/meminfo | grep -i ""MemFree"" | awk '{print $2}') | |
| 385 | +# 显示提取的信息 | |
| 386 | +echo $total_mem $used_mem $free_mem | |
| 387 | + "); | |
| 388 | + var metrics = new MemoryMetrics(); | |
| 389 | + | |
| 390 | + if (!string.IsNullOrWhiteSpace(output)) | |
| 391 | + { | |
| 392 | + var memory = output.Split(' ', (char)StringSplitOptions.RemoveEmptyEntries); | |
| 393 | + if (memory.Length >= 2) | |
| 394 | + { | |
| 395 | + metrics.Total = Math.Round(double.Parse(memory[0]) / 1024, 0); | |
| 396 | + | |
| 397 | + metrics.Free = Math.Round(double.Parse(memory[1])/ 1024, 0);//m | |
| 398 | + metrics.Used = metrics.Total - metrics.Free; | |
| 399 | + } | |
| 400 | + } | |
| 401 | + return metrics; | |
| 402 | + } | |
| 403 | + #endregion | |
| 404 | + } | |
| 405 | +} | |
| 0 | 406 | \ No newline at end of file | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ConsoleHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ConsoleHelper.cs | |
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace Yi.Framework.Core.Helper | |
| 4 | +{ | |
| 5 | + public static class ConsoleHelper | |
| 6 | + { | |
| 7 | + public static void WriteColorLine(string str, ConsoleColor color) | |
| 8 | + { | |
| 9 | + ConsoleColor currentForeColor = Console.ForegroundColor; | |
| 10 | + Console.ForegroundColor = color; | |
| 11 | + Console.WriteLine(str); | |
| 12 | + Console.ForegroundColor = currentForeColor; | |
| 13 | + } | |
| 14 | + | |
| 15 | + /// <summary> | |
| 16 | + /// 打印错误信息 | |
| 17 | + /// </summary> | |
| 18 | + /// <param name="str">待打印的字符串</param> | |
| 19 | + /// <param name="color">想要打印的颜色</param> | |
| 20 | + public static void WriteErrorLine(this string str, ConsoleColor color = ConsoleColor.Red) | |
| 21 | + { | |
| 22 | + WriteColorLine(str, color); | |
| 23 | + } | |
| 24 | + | |
| 25 | + /// <summary> | |
| 26 | + /// 打印警告信息 | |
| 27 | + /// </summary> | |
| 28 | + /// <param name="str">待打印的字符串</param> | |
| 29 | + /// <param name="color">想要打印的颜色</param> | |
| 30 | + public static void WriteWarningLine(this string str, ConsoleColor color = ConsoleColor.Yellow) | |
| 31 | + { | |
| 32 | + WriteColorLine(str, color); | |
| 33 | + } | |
| 34 | + /// <summary> | |
| 35 | + /// 打印正常信息 | |
| 36 | + /// </summary> | |
| 37 | + /// <param name="str">待打印的字符串</param> | |
| 38 | + /// <param name="color">想要打印的颜色</param> | |
| 39 | + public static void WriteInfoLine(this string str, ConsoleColor color = ConsoleColor.White) | |
| 40 | + { | |
| 41 | + WriteColorLine(str, color); | |
| 42 | + } | |
| 43 | + /// <summary> | |
| 44 | + /// 打印成功的信息 | |
| 45 | + /// </summary> | |
| 46 | + /// <param name="str">待打印的字符串</param> | |
| 47 | + /// <param name="color">想要打印的颜色</param> | |
| 48 | + public static void WriteSuccessLine(this string str, ConsoleColor color = ConsoleColor.Green) | |
| 49 | + { | |
| 50 | + WriteColorLine(str, color); | |
| 51 | + } | |
| 52 | + | |
| 53 | + } | |
| 54 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/DateHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/DateHelper.cs | |
| 1 | +using System; | |
| 2 | + | |
| 3 | +namespace Yi.Framework.Core.Helper | |
| 4 | +{ | |
| 5 | + public class DateHelper | |
| 6 | + { | |
| 7 | + public static DateTime StampToDateTime(string time) | |
| 8 | + { | |
| 9 | + time = time.Substring(0, 10); | |
| 10 | + double timestamp = Convert.ToInt64(time); | |
| 11 | + DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0); | |
| 12 | + dateTime = dateTime.AddSeconds(timestamp).ToLocalTime(); | |
| 13 | + return dateTime; | |
| 14 | + } | |
| 15 | + | |
| 16 | + public static string TimeSubTract(DateTime time1, DateTime time2) | |
| 17 | + { | |
| 18 | + TimeSpan subTract = time1.Subtract(time2); | |
| 19 | + return $"{subTract.Days} 天 {subTract.Hours} 时 {subTract.Minutes} 分 "; | |
| 20 | + } | |
| 21 | + /// <summary> | |
| 22 | + /// 时间戳转本地时间-时间戳精确到秒 | |
| 23 | + /// </summary> | |
| 24 | + public static DateTime ToLocalTimeDateBySeconds(long unix) | |
| 25 | + { | |
| 26 | + var dto = DateTimeOffset.FromUnixTimeSeconds(unix); | |
| 27 | + return dto.ToLocalTime().DateTime; | |
| 28 | + } | |
| 29 | + | |
| 30 | + /// <summary> | |
| 31 | + /// 时间转时间戳Unix-时间戳精确到秒 | |
| 32 | + /// </summary> | |
| 33 | + public static long ToUnixTimestampBySeconds(DateTime dt) | |
| 34 | + { | |
| 35 | + DateTimeOffset dto = new DateTimeOffset(dt); | |
| 36 | + return dto.ToUnixTimeSeconds(); | |
| 37 | + } | |
| 38 | + | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 时间戳转本地时间-时间戳精确到毫秒 | |
| 42 | + /// </summary> | |
| 43 | + public static DateTime ToLocalTimeDateByMilliseconds(long unix) | |
| 44 | + { | |
| 45 | + var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix); | |
| 46 | + return dto.ToLocalTime().DateTime; | |
| 47 | + } | |
| 48 | + | |
| 49 | + /// <summary> | |
| 50 | + /// 时间转时间戳Unix-时间戳精确到毫秒 | |
| 51 | + /// </summary> | |
| 52 | + public static long ToUnixTimestampByMilliseconds(DateTime dt) | |
| 53 | + { | |
| 54 | + DateTimeOffset dto = new DateTimeOffset(dt); | |
| 55 | + return dto.ToUnixTimeMilliseconds(); | |
| 56 | + } | |
| 57 | + } | |
| 58 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/DateTimeHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/DateTimeHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Text; | |
| 4 | + | |
| 5 | +namespace Yi.Framework.Core.Helper | |
| 6 | +{ | |
| 7 | + public class DateTimeHelper | |
| 8 | + { | |
| 9 | + /// <summary> | |
| 10 | + /// | |
| 11 | + /// </summary> | |
| 12 | + /// <param name="dateTime"></param> | |
| 13 | + /// <returns></returns> | |
| 14 | + public static DateTime GetBeginTime(DateTime? dateTime, int days = 0) | |
| 15 | + { | |
| 16 | + if (dateTime == DateTime.MinValue || dateTime == null) | |
| 17 | + { | |
| 18 | + return DateTime.Now.AddDays(days); | |
| 19 | + } | |
| 20 | + return dateTime ?? DateTime.Now; | |
| 21 | + } | |
| 22 | + #region 时间戳转换 | |
| 23 | + | |
| 24 | + /// <summary> | |
| 25 | + /// 时间戳转本地时间-时间戳精确到秒 | |
| 26 | + /// </summary> | |
| 27 | + public static DateTime ToLocalTimeDateBySeconds(long unix) | |
| 28 | + { | |
| 29 | + var dto = DateTimeOffset.FromUnixTimeSeconds(unix); | |
| 30 | + return dto.ToLocalTime().DateTime; | |
| 31 | + } | |
| 32 | + | |
| 33 | + /// <summary> | |
| 34 | + /// 时间转时间戳Unix-时间戳精确到秒 | |
| 35 | + /// </summary> | |
| 36 | + public static long ToUnixTimestampBySeconds(DateTime dt) | |
| 37 | + { | |
| 38 | + DateTimeOffset dto = new DateTimeOffset(dt); | |
| 39 | + return dto.ToUnixTimeSeconds(); | |
| 40 | + } | |
| 41 | + | |
| 42 | + /// <summary> | |
| 43 | + /// 时间戳转本地时间-时间戳精确到毫秒 | |
| 44 | + /// </summary> | |
| 45 | + public static DateTime ToLocalTimeDateByMilliseconds(long unix) | |
| 46 | + { | |
| 47 | + var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix); | |
| 48 | + return dto.ToLocalTime().DateTime; | |
| 49 | + } | |
| 50 | + | |
| 51 | + /// <summary> | |
| 52 | + /// 时间转时间戳Unix-时间戳精确到毫秒 | |
| 53 | + /// </summary> | |
| 54 | + public static long ToUnixTimestampByMilliseconds(DateTime dt) | |
| 55 | + { | |
| 56 | + DateTimeOffset dto = new DateTimeOffset(dt); | |
| 57 | + return dto.ToUnixTimeMilliseconds(); | |
| 58 | + } | |
| 59 | + | |
| 60 | + #endregion | |
| 61 | + | |
| 62 | + #region 毫秒转天时分秒 | |
| 63 | + /// <summary> | |
| 64 | + /// 毫秒转天时分秒 | |
| 65 | + /// </summary> | |
| 66 | + /// <param name="ms"></param> | |
| 67 | + /// <returns></returns> | |
| 68 | + public static string FormatTime(long ms) | |
| 69 | + { | |
| 70 | + int ss = 1000; | |
| 71 | + int mi = ss * 60; | |
| 72 | + int hh = mi * 60; | |
| 73 | + int dd = hh * 24; | |
| 74 | + | |
| 75 | + long day = ms / dd; | |
| 76 | + long hour = (ms - day * dd) / hh; | |
| 77 | + long minute = (ms - day * dd - hour * hh) / mi; | |
| 78 | + long second = (ms - day * dd - hour * hh - minute * mi) / ss; | |
| 79 | + long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss; | |
| 80 | + | |
| 81 | + string sDay = day < 10 ? "0" + day : "" + day; //天 | |
| 82 | + string sHour = hour < 10 ? "0" + hour : "" + hour;//小时 | |
| 83 | + string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟 | |
| 84 | + string sSecond = second < 10 ? "0" + second : "" + second;//秒 | |
| 85 | + string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒 | |
| 86 | + sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond; | |
| 87 | + | |
| 88 | + return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond); | |
| 89 | + } | |
| 90 | + #endregion | |
| 91 | + | |
| 92 | + #region 获取unix时间戳 | |
| 93 | + /// <summary> | |
| 94 | + /// 获取unix时间戳 | |
| 95 | + /// </summary> | |
| 96 | + /// <param name="dt"></param> | |
| 97 | + /// <returns></returns> | |
| 98 | + public static long GetUnixTimeStamp(DateTime dt) | |
| 99 | + { | |
| 100 | + long unixTime = ((DateTimeOffset)dt).ToUnixTimeMilliseconds(); | |
| 101 | + return unixTime; | |
| 102 | + } | |
| 103 | + #endregion | |
| 104 | + | |
| 105 | + #region 获取日期天的最小时间 | |
| 106 | + public static DateTime GetDayMinDate(DateTime dt) | |
| 107 | + { | |
| 108 | + DateTime min = new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0); | |
| 109 | + return min; | |
| 110 | + } | |
| 111 | + #endregion | |
| 112 | + | |
| 113 | + #region 获取日期天的最大时间 | |
| 114 | + public static DateTime GetDayMaxDate(DateTime dt) | |
| 115 | + { | |
| 116 | + DateTime max = new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59); | |
| 117 | + return max; | |
| 118 | + } | |
| 119 | + #endregion | |
| 120 | + | |
| 121 | + #region 获取日期天的最大时间 | |
| 122 | + public static string FormatDateTime(DateTime? dt) | |
| 123 | + { | |
| 124 | + if (dt != null) | |
| 125 | + { | |
| 126 | + if (dt.Value.Year == DateTime.Now.Year) | |
| 127 | + { | |
| 128 | + return dt.Value.ToString("MM-dd HH:mm"); | |
| 129 | + } | |
| 130 | + else | |
| 131 | + { | |
| 132 | + return dt.Value.ToString("yyyy-MM-dd HH:mm"); | |
| 133 | + } | |
| 134 | + } | |
| 135 | + return string.Empty; | |
| 136 | + } | |
| 137 | + #endregion | |
| 138 | + } | |
| 139 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/DistinctHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/DistinctHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Diagnostics.CodeAnalysis; | |
| 4 | +using System.Linq; | |
| 5 | +using System.Text; | |
| 6 | +using System.Threading.Tasks; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.Core.Helper | |
| 9 | +{ | |
| 10 | + public class Compare<T, C> : IEqualityComparer<T> | |
| 11 | + { | |
| 12 | + private Func<T, C> _getField; | |
| 13 | + public Compare(Func<T, C> getfield) | |
| 14 | + { | |
| 15 | + _getField = getfield; | |
| 16 | + } | |
| 17 | + public bool Equals(T? x, T? y) | |
| 18 | + { | |
| 19 | + return EqualityComparer<C>.Default.Equals(_getField(x!), _getField(y!)); | |
| 20 | + } | |
| 21 | + | |
| 22 | + public int GetHashCode(T obj) | |
| 23 | + { | |
| 24 | + return EqualityComparer<C>.Default.GetHashCode(_getField(obj)!); | |
| 25 | + } | |
| 26 | + } | |
| 27 | + public static class DistinctHelper | |
| 28 | + { | |
| 29 | + /// <summary> | |
| 30 | + /// 自定义Distinct扩展方法 | |
| 31 | + /// </summary> | |
| 32 | + /// <typeparam name="T">要去重的对象类</typeparam> | |
| 33 | + /// <typeparam name="C">自定义去重的字段类型</typeparam> | |
| 34 | + /// <param name="source">要去重的对象</param> | |
| 35 | + /// <param name="getfield">获取自定义去重字段的委托</param> | |
| 36 | + /// <returns></returns> | |
| 37 | + public static IEnumerable<T> DistinctNew<T, C>(this IEnumerable<T> source, Func<T, C> getfield) | |
| 38 | + { | |
| 39 | + return source.Distinct(new Compare<T, C>(getfield)); | |
| 40 | + } | |
| 41 | + } | |
| 42 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/EnumHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/EnumHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Helper | |
| 8 | +{ | |
| 9 | + public static class EnumHelper | |
| 10 | + { | |
| 11 | + public static New EnumToEnum<New>(this object oldEnum) | |
| 12 | + { | |
| 13 | + if (oldEnum is null) | |
| 14 | + { | |
| 15 | + throw new ArgumentNullException(nameof(oldEnum)); | |
| 16 | + } | |
| 17 | + return (New)Enum.ToObject(typeof(New), oldEnum.GetHashCode()); | |
| 18 | + } | |
| 19 | + | |
| 20 | + public static TEnum StringToEnum<TEnum>(this string str) | |
| 21 | + { | |
| 22 | + return (TEnum)Enum.Parse(typeof(TEnum), str); | |
| 23 | + } | |
| 24 | + } | |
| 25 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ExpressionHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ExpressionHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Linq.Expressions; | |
| 5 | +using System.Text; | |
| 6 | +using System.Threading.Tasks; | |
| 7 | + | |
| 8 | +namespace Yi.Framework.Core.Helper | |
| 9 | +{ | |
| 10 | + public static class ExpressionHelper | |
| 11 | + { | |
| 12 | + | |
| 13 | + | |
| 14 | + /// <summary> | |
| 15 | + /// Expression表达式树lambda参数拼接组合 | |
| 16 | + /// </summary> | |
| 17 | + /// <typeparam name="T"></typeparam> | |
| 18 | + /// <param name="first"></param> | |
| 19 | + /// <param name="second"></param> | |
| 20 | + /// <param name="merge"></param> | |
| 21 | + /// <returns></returns> | |
| 22 | + public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) | |
| 23 | + { | |
| 24 | + var parameterMap = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); | |
| 25 | + var secondBody = LambdaParameteRebinder.ReplaceParameter(parameterMap, second.Body); | |
| 26 | + return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters); | |
| 27 | + } | |
| 28 | + | |
| 29 | + /// <summary> | |
| 30 | + /// Expression表达式树lambda参数拼接--false | |
| 31 | + /// </summary> | |
| 32 | + /// <typeparam name="T"></typeparam> | |
| 33 | + /// <returns></returns> | |
| 34 | + public static Expression<Func<T, bool>> False<T>() => f => false; | |
| 35 | + | |
| 36 | + /// <summary> | |
| 37 | + /// Expression表达式树lambda参数拼接-true | |
| 38 | + /// </summary> | |
| 39 | + /// <typeparam name="T"></typeparam> | |
| 40 | + /// <returns></returns> | |
| 41 | + public static Expression<Func<T, bool>> True<T>() => f => true; | |
| 42 | + | |
| 43 | + /// <summary> | |
| 44 | + /// Expression表达式树lambda参数拼接--and | |
| 45 | + /// </summary> | |
| 46 | + /// <typeparam name="T"></typeparam> | |
| 47 | + /// <param name="first"></param> | |
| 48 | + /// <param name="second"></param> | |
| 49 | + /// <returns></returns> | |
| 50 | + public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) => first.Compose(second, Expression.And); | |
| 51 | + | |
| 52 | + /// <summary> | |
| 53 | + /// Expression表达式树lambda参数拼接--or | |
| 54 | + /// </summary> | |
| 55 | + /// <typeparam name="T"></typeparam> | |
| 56 | + /// <param name="first"></param> | |
| 57 | + /// <param name="second"></param> | |
| 58 | + /// <returns></returns> | |
| 59 | + public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) => first.Compose(second, Expression.Or); | |
| 60 | + } | |
| 61 | + | |
| 62 | + public class LambdaParameteRebinder : ExpressionVisitor | |
| 63 | + { | |
| 64 | + /// <summary> | |
| 65 | + /// 存放表达式树的参数的字典 | |
| 66 | + /// </summary> | |
| 67 | + private readonly Dictionary<ParameterExpression, ParameterExpression> map; | |
| 68 | + | |
| 69 | + /// <summary> | |
| 70 | + /// 构造函数 | |
| 71 | + /// </summary> | |
| 72 | + /// <param name="map"></param> | |
| 73 | + public LambdaParameteRebinder(Dictionary<ParameterExpression, ParameterExpression> map) | |
| 74 | + { | |
| 75 | + this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); | |
| 76 | + } | |
| 77 | + | |
| 78 | + /// <summary> | |
| 79 | + /// 重载参数访问的方法,访问表达式树参数,如果字典中包含,则取出 | |
| 80 | + /// </summary> | |
| 81 | + /// <param name="node">表达式树参数</param> | |
| 82 | + /// <returns></returns> | |
| 83 | + protected override Expression VisitParameter(ParameterExpression node) | |
| 84 | + { | |
| 85 | + if (map.TryGetValue(node, out ParameterExpression expression)) | |
| 86 | + { | |
| 87 | + node = expression; | |
| 88 | + } | |
| 89 | + return base.VisitParameter(node); | |
| 90 | + } | |
| 91 | + | |
| 92 | + public static Expression ReplaceParameter(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) | |
| 93 | + { | |
| 94 | + return new LambdaParameteRebinder(map).Visit(exp); | |
| 95 | + } | |
| 96 | + } | |
| 97 | + | |
| 98 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/FileHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/FileHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.IO; | |
| 4 | +using System.Linq; | |
| 5 | +using System.Text; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Helper | |
| 8 | +{ | |
| 9 | + public class FileHelper : IDisposable | |
| 10 | + { | |
| 11 | + | |
| 12 | + private bool _alreadyDispose = false; | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + #region 构造函数 | |
| 17 | + public FileHelper() | |
| 18 | + { | |
| 19 | + // | |
| 20 | + // TODO: 在此处添加构造函数逻辑 | |
| 21 | + // | |
| 22 | + } | |
| 23 | + ~FileHelper() | |
| 24 | + { | |
| 25 | + Dispose(); ; | |
| 26 | + } | |
| 27 | + | |
| 28 | + protected virtual void Dispose(bool isDisposing) | |
| 29 | + { | |
| 30 | + if (_alreadyDispose) return; | |
| 31 | + _alreadyDispose = true; | |
| 32 | + } | |
| 33 | + #endregion | |
| 34 | + | |
| 35 | + #region IDisposable 成员 | |
| 36 | + | |
| 37 | + public void Dispose() | |
| 38 | + { | |
| 39 | + Dispose(true); | |
| 40 | + GC.SuppressFinalize(this); | |
| 41 | + } | |
| 42 | + | |
| 43 | + #endregion | |
| 44 | + | |
| 45 | + #region 取得文件后缀名 | |
| 46 | + /**************************************** | |
| 47 | + * 函数名称:GetPostfixStr | |
| 48 | + * 功能说明:取得文件后缀名 | |
| 49 | + * 参 数:filename:文件名称 | |
| 50 | + * 调用示列: | |
| 51 | + * string filename = "aaa.aspx"; | |
| 52 | + * string s = EC.FileObj.GetPostfixStr(filename); | |
| 53 | + *****************************************/ | |
| 54 | + /// <summary> | |
| 55 | + /// 取后缀名 | |
| 56 | + /// </summary> | |
| 57 | + /// <param name="filename">文件名</param> | |
| 58 | + /// <returns>.gif|.html格式</returns> | |
| 59 | + public static string GetPostfixStr(string filename) | |
| 60 | + { | |
| 61 | + int start = filename.LastIndexOf("."); | |
| 62 | + int length = filename.Length; | |
| 63 | + string postfix = filename.Substring(start, length - start); | |
| 64 | + return postfix; | |
| 65 | + } | |
| 66 | + #endregion | |
| 67 | + | |
| 68 | + #region 根据文件大小获取指定前缀的可用文件名 | |
| 69 | + /// <summary> | |
| 70 | + /// 根据文件大小获取指定前缀的可用文件名 | |
| 71 | + /// </summary> | |
| 72 | + /// <param name="folderPath">文件夹</param> | |
| 73 | + /// <param name="prefix">文件前缀</param> | |
| 74 | + /// <param name="size">文件大小(1m)</param> | |
| 75 | + /// <param name="ext">文件后缀(.log)</param> | |
| 76 | + /// <returns>可用文件名</returns> | |
| 77 | + //public static string GetAvailableFileWithPrefixOrderSize(string folderPath, string prefix, int size = 1 * 1024 * 1024, string ext = ".log") | |
| 78 | + //{ | |
| 79 | + // var allFiles = new DirectoryInfo(folderPath); | |
| 80 | + // var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(prefix.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d=>d.Name).ToList(); | |
| 81 | + | |
| 82 | + // if (selectFiles.Count > 0) | |
| 83 | + // { | |
| 84 | + // return selectFiles.FirstOrDefault().FullName; | |
| 85 | + // } | |
| 86 | + | |
| 87 | + // return Path.Combine(folderPath, $@"{prefix}_{DateTime.Now.DateToTimeStamp()}.log"); | |
| 88 | + //} | |
| 89 | + //public static string GetAvailableFileNameWithPrefixOrderSize(string _contentRoot, string prefix, int size = 1 * 1024 * 1024, string ext = ".log") | |
| 90 | + //{ | |
| 91 | + // var folderPath = Path.Combine(_contentRoot, "Log"); | |
| 92 | + // if (!Directory.Exists(folderPath)) | |
| 93 | + // { | |
| 94 | + // Directory.CreateDirectory(folderPath); | |
| 95 | + // } | |
| 96 | + | |
| 97 | + // var allFiles = new DirectoryInfo(folderPath); | |
| 98 | + // var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(prefix.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d => d.Name).ToList(); | |
| 99 | + | |
| 100 | + // if (selectFiles.Count > 0) | |
| 101 | + // { | |
| 102 | + // return selectFiles.FirstOrDefault().Name.Replace(".log",""); | |
| 103 | + // } | |
| 104 | + | |
| 105 | + // return $@"{prefix}_{DateTime.Now.DateToTimeStamp()}"; | |
| 106 | + //} | |
| 107 | + #endregion | |
| 108 | + | |
| 109 | + #region 写文件 | |
| 110 | + /**************************************** | |
| 111 | + * 函数名称:WriteFile | |
| 112 | + * 功能说明:写文件,会覆盖掉以前的内容 | |
| 113 | + * 参 数:Path:文件路径,Strings:文本内容 | |
| 114 | + * 调用示列: | |
| 115 | + * string Path = Server.MapPath("Default2.aspx"); | |
| 116 | + * string Strings = "这是我写的内容啊"; | |
| 117 | + * EC.FileObj.WriteFile(Path,Strings); | |
| 118 | + *****************************************/ | |
| 119 | + /// <summary> | |
| 120 | + /// 写文件 | |
| 121 | + /// </summary> | |
| 122 | + /// <param name="Path">文件路径</param> | |
| 123 | + /// <param name="Strings">文件内容</param> | |
| 124 | + public static void WriteFile(string Path, string Strings) | |
| 125 | + { | |
| 126 | + if (!File.Exists(Path)) | |
| 127 | + { | |
| 128 | + FileStream f = File.Create(Path); | |
| 129 | + f.Close(); | |
| 130 | + } | |
| 131 | + StreamWriter f2 = new StreamWriter(Path, false, Encoding.GetEncoding("gb2312")); | |
| 132 | + f2.Write(Strings); | |
| 133 | + f2.Close(); | |
| 134 | + f2.Dispose(); | |
| 135 | + } | |
| 136 | + | |
| 137 | + /// <summary> | |
| 138 | + /// 写文件 | |
| 139 | + /// </summary> | |
| 140 | + /// <param name="Path">文件路径</param> | |
| 141 | + /// <param name="Strings">文件内容</param> | |
| 142 | + /// <param name="encode">编码格式</param> | |
| 143 | + public static void WriteFile(string Path, string Strings, Encoding encode) | |
| 144 | + { | |
| 145 | + if (!File.Exists(Path)) | |
| 146 | + { | |
| 147 | + FileStream f = File.Create(Path); | |
| 148 | + f.Close(); | |
| 149 | + } | |
| 150 | + StreamWriter f2 = new StreamWriter(Path, false, encode); | |
| 151 | + f2.Write(Strings); | |
| 152 | + f2.Close(); | |
| 153 | + f2.Dispose(); | |
| 154 | + } | |
| 155 | + #endregion | |
| 156 | + | |
| 157 | + #region 读文件 | |
| 158 | + /**************************************** | |
| 159 | + * 函数名称:ReadFile | |
| 160 | + * 功能说明:读取文本内容 | |
| 161 | + * 参 数:Path:文件路径 | |
| 162 | + * 调用示列: | |
| 163 | + * string Path = Server.MapPath("Default2.aspx"); | |
| 164 | + * string s = EC.FileObj.ReadFile(Path); | |
| 165 | + *****************************************/ | |
| 166 | + /// <summary> | |
| 167 | + /// 读文件 | |
| 168 | + /// </summary> | |
| 169 | + /// <param name="Path">文件路径</param> | |
| 170 | + /// <returns></returns> | |
| 171 | + public static string ReadFile(string Path) | |
| 172 | + { | |
| 173 | + string s = ""; | |
| 174 | + if (!File.Exists(Path)) | |
| 175 | + s = "不存在相应的目录"; | |
| 176 | + else | |
| 177 | + { | |
| 178 | + StreamReader f2 = new StreamReader(Path, Encoding.GetEncoding("gb2312")); | |
| 179 | + s = f2.ReadToEnd(); | |
| 180 | + f2.Close(); | |
| 181 | + f2.Dispose(); | |
| 182 | + } | |
| 183 | + | |
| 184 | + return s; | |
| 185 | + } | |
| 186 | + | |
| 187 | + /// <summary> | |
| 188 | + /// 读文件 | |
| 189 | + /// </summary> | |
| 190 | + /// <param name="Path">文件路径</param> | |
| 191 | + /// <param name="encode">编码格式</param> | |
| 192 | + /// <returns></returns> | |
| 193 | + public static string ReadFile(string Path, Encoding encode) | |
| 194 | + { | |
| 195 | + string s = ""; | |
| 196 | + if (!File.Exists(Path)) | |
| 197 | + s = "不存在相应的目录"; | |
| 198 | + else | |
| 199 | + { | |
| 200 | + StreamReader f2 = new StreamReader(Path, encode); | |
| 201 | + s = f2.ReadToEnd(); | |
| 202 | + f2.Close(); | |
| 203 | + f2.Dispose(); | |
| 204 | + } | |
| 205 | + | |
| 206 | + return s; | |
| 207 | + } | |
| 208 | + #endregion | |
| 209 | + | |
| 210 | + #region 追加文件 | |
| 211 | + /**************************************** | |
| 212 | + * 函数名称:FileAdd | |
| 213 | + * 功能说明:追加文件内容 | |
| 214 | + * 参 数:Path:文件路径,strings:内容 | |
| 215 | + * 调用示列: | |
| 216 | + * string Path = Server.MapPath("Default2.aspx"); | |
| 217 | + * string Strings = "新追加内容"; | |
| 218 | + * EC.FileObj.FileAdd(Path, Strings); | |
| 219 | + *****************************************/ | |
| 220 | + /// <summary> | |
| 221 | + /// 追加文件 | |
| 222 | + /// </summary> | |
| 223 | + /// <param name="Path">文件路径</param> | |
| 224 | + /// <param name="strings">内容</param> | |
| 225 | + public static void FileAdd(string Path, string strings) | |
| 226 | + { | |
| 227 | + StreamWriter sw = File.AppendText(Path); | |
| 228 | + sw.Write(strings); | |
| 229 | + sw.Flush(); | |
| 230 | + sw.Close(); | |
| 231 | + } | |
| 232 | + #endregion | |
| 233 | + | |
| 234 | + #region 拷贝文件 | |
| 235 | + /**************************************** | |
| 236 | + * 函数名称:FileCoppy | |
| 237 | + * 功能说明:拷贝文件 | |
| 238 | + * 参 数:OrignFile:原始文件,NewFile:新文件路径 | |
| 239 | + * 调用示列: | |
| 240 | + * string orignFile = Server.MapPath("Default2.aspx"); | |
| 241 | + * string NewFile = Server.MapPath("Default3.aspx"); | |
| 242 | + * EC.FileObj.FileCoppy(OrignFile, NewFile); | |
| 243 | + *****************************************/ | |
| 244 | + /// <summary> | |
| 245 | + /// 拷贝文件 | |
| 246 | + /// </summary> | |
| 247 | + /// <param name="OrignFile">原始文件</param> | |
| 248 | + /// <param name="NewFile">新文件路径</param> | |
| 249 | + public static void FileCoppy(string orignFile, string NewFile) | |
| 250 | + { | |
| 251 | + File.Copy(orignFile, NewFile, true); | |
| 252 | + } | |
| 253 | + | |
| 254 | + #endregion | |
| 255 | + | |
| 256 | + #region 删除文件 | |
| 257 | + /**************************************** | |
| 258 | + * 函数名称:FileDel | |
| 259 | + * 功能说明:删除文件 | |
| 260 | + * 参 数:Path:文件路径 | |
| 261 | + * 调用示列: | |
| 262 | + * string Path = Server.MapPath("Default3.aspx"); | |
| 263 | + * EC.FileObj.FileDel(Path); | |
| 264 | + *****************************************/ | |
| 265 | + /// <summary> | |
| 266 | + /// 删除文件 | |
| 267 | + /// </summary> | |
| 268 | + /// <param name="Path">路径</param> | |
| 269 | + public static void FileDel(string Path) | |
| 270 | + { | |
| 271 | + File.Delete(Path); | |
| 272 | + } | |
| 273 | + #endregion | |
| 274 | + | |
| 275 | + #region 移动文件 | |
| 276 | + /**************************************** | |
| 277 | + * 函数名称:FileMove | |
| 278 | + * 功能说明:移动文件 | |
| 279 | + * 参 数:OrignFile:原始路径,NewFile:新文件路径 | |
| 280 | + * 调用示列: | |
| 281 | + * string orignFile = Server.MapPath("../说明.txt"); | |
| 282 | + * string NewFile = Server.MapPath("http://www.cnblogs.com/说明.txt"); | |
| 283 | + * EC.FileObj.FileMove(OrignFile, NewFile); | |
| 284 | + *****************************************/ | |
| 285 | + /// <summary> | |
| 286 | + /// 移动文件 | |
| 287 | + /// </summary> | |
| 288 | + /// <param name="OrignFile">原始路径</param> | |
| 289 | + /// <param name="NewFile">新路径</param> | |
| 290 | + public static void FileMove(string orignFile, string NewFile) | |
| 291 | + { | |
| 292 | + File.Move(orignFile, NewFile); | |
| 293 | + } | |
| 294 | + #endregion | |
| 295 | + | |
| 296 | + #region 在当前目录下创建目录 | |
| 297 | + /**************************************** | |
| 298 | + * 函数名称:FolderCreate | |
| 299 | + * 功能说明:在当前目录下创建目录 | |
| 300 | + * 参 数:OrignFolder:当前目录,NewFloder:新目录 | |
| 301 | + * 调用示列: | |
| 302 | + * string orignFolder = Server.MapPath("test/"); | |
| 303 | + * string NewFloder = "new"; | |
| 304 | + * EC.FileObj.FolderCreate(OrignFolder, NewFloder); | |
| 305 | + *****************************************/ | |
| 306 | + /// <summary> | |
| 307 | + /// 在当前目录下创建目录 | |
| 308 | + /// </summary> | |
| 309 | + /// <param name="OrignFolder">当前目录</param> | |
| 310 | + /// <param name="NewFloder">新目录</param> | |
| 311 | + public static void FolderCreate(string orignFolder, string NewFloder) | |
| 312 | + { | |
| 313 | + Directory.SetCurrentDirectory(orignFolder); | |
| 314 | + Directory.CreateDirectory(NewFloder); | |
| 315 | + } | |
| 316 | + #endregion | |
| 317 | + | |
| 318 | + #region 递归删除文件夹目录及文件 | |
| 319 | + /**************************************** | |
| 320 | + * 函数名称:DeleteFolder | |
| 321 | + * 功能说明:递归删除文件夹目录及文件 | |
| 322 | + * 参 数:dir:文件夹路径 | |
| 323 | + * 调用示列: | |
| 324 | + * string dir = Server.MapPath("test/"); | |
| 325 | + * EC.FileObj.DeleteFolder(dir); | |
| 326 | + *****************************************/ | |
| 327 | + /// <summary> | |
| 328 | + /// 递归删除文件夹目录及文件 | |
| 329 | + /// </summary> | |
| 330 | + /// <param name="dir"></param> | |
| 331 | + /// <returns></returns> | |
| 332 | + public static void DeleteFolder(string dir) | |
| 333 | + { | |
| 334 | + if (Directory.Exists(dir)) //如果存在这个文件夹删除之 | |
| 335 | + { | |
| 336 | + foreach (string d in Directory.GetFileSystemEntries(dir)) | |
| 337 | + { | |
| 338 | + if (File.Exists(d)) | |
| 339 | + File.Delete(d); //直接删除其中的文件 | |
| 340 | + else | |
| 341 | + DeleteFolder(d); //递归删除子文件夹 | |
| 342 | + } | |
| 343 | + Directory.Delete(dir); //删除已空文件夹 | |
| 344 | + } | |
| 345 | + | |
| 346 | + } | |
| 347 | + #endregion | |
| 348 | + | |
| 349 | + #region 将指定文件夹下面的所有内容copy到目标文件夹下面 果目标文件夹为只读属性就会报错。 | |
| 350 | + /**************************************** | |
| 351 | + * 函数名称:CopyDir | |
| 352 | + * 功能说明:将指定文件夹下面的所有内容copy到目标文件夹下面 果目标文件夹为只读属性就会报错。 | |
| 353 | + * 参 数:srcPath:原始路径,aimPath:目标文件夹 | |
| 354 | + * 调用示列: | |
| 355 | + * string srcPath = Server.MapPath("test/"); | |
| 356 | + * string aimPath = Server.MapPath("test1/"); | |
| 357 | + * EC.FileObj.CopyDir(srcPath,aimPath); | |
| 358 | + *****************************************/ | |
| 359 | + /// <summary> | |
| 360 | + /// 指定文件夹下面的所有内容copy到目标文件夹下面 | |
| 361 | + /// </summary> | |
| 362 | + /// <param name="srcPath">原始路径</param> | |
| 363 | + /// <param name="aimPath">目标文件夹</param> | |
| 364 | + public static void CopyDir(string srcPath, string aimPath) | |
| 365 | + { | |
| 366 | + try | |
| 367 | + { | |
| 368 | + // 检查目标目录是否以目录分割字符结束如果不是则添加之 | |
| 369 | + if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar) | |
| 370 | + aimPath += Path.DirectorySeparatorChar; | |
| 371 | + // 判断目标目录是否存在如果不存在则新建之 | |
| 372 | + if (!Directory.Exists(aimPath)) | |
| 373 | + Directory.CreateDirectory(aimPath); | |
| 374 | + // 得到源目录的文件列表,该里面是包含文件以及目录路径的一个数组 | |
| 375 | + //如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法 | |
| 376 | + //string[] fileList = Directory.GetFiles(srcPath); | |
| 377 | + string[] fileList = Directory.GetFileSystemEntries(srcPath); | |
| 378 | + //遍历所有的文件和目录 | |
| 379 | + foreach (string file in fileList) | |
| 380 | + { | |
| 381 | + //先当作目录处理如果存在这个目录就递归Copy该目录下面的文件 | |
| 382 | + | |
| 383 | + if (Directory.Exists(file)) | |
| 384 | + CopyDir(file, aimPath + Path.GetFileName(file)); | |
| 385 | + //否则直接Copy文件 | |
| 386 | + else | |
| 387 | + File.Copy(file, aimPath + Path.GetFileName(file), true); | |
| 388 | + } | |
| 389 | + | |
| 390 | + } | |
| 391 | + catch (Exception ee) | |
| 392 | + { | |
| 393 | + throw new Exception(ee.ToString()); | |
| 394 | + } | |
| 395 | + } | |
| 396 | + #endregion | |
| 397 | + | |
| 398 | + /// <summary> | |
| 399 | + /// 获取目录下全部文件名 | |
| 400 | + /// </summary> | |
| 401 | + /// <param name="path"></param> | |
| 402 | + /// <param name="pattern"></param> | |
| 403 | + /// <returns></returns> | |
| 404 | + public static List<string> GetAllFileNames(string path, string pattern = "*") | |
| 405 | + { | |
| 406 | + List<FileInfo> folder = new DirectoryInfo(path).GetFiles(pattern).ToList(); | |
| 407 | + | |
| 408 | + return folder.Select(x => x.Name).ToList(); | |
| 409 | + } | |
| 410 | + /// <summary> | |
| 411 | + /// 文件内容替换 | |
| 412 | + /// </summary> | |
| 413 | + public static string FileContentReplace(string path, string oldStr, string newStr) | |
| 414 | + { | |
| 415 | + var content = File.ReadAllText(path); | |
| 416 | + | |
| 417 | + if (content.Contains(oldStr)) | |
| 418 | + { | |
| 419 | + File.Delete(path); | |
| 420 | + File.WriteAllText(path, content.Replace(oldStr, newStr)); | |
| 421 | + } | |
| 422 | + | |
| 423 | + return path; | |
| 424 | + } | |
| 425 | + /// <summary> | |
| 426 | + /// 文件名称 | |
| 427 | + /// </summary> | |
| 428 | + public static string FileNameReplace(string path, string oldStr, string newStr) | |
| 429 | + { | |
| 430 | + string fileName = Path.GetFileName(path); | |
| 431 | + if (!fileName.Contains(oldStr)) | |
| 432 | + { | |
| 433 | + return path; | |
| 434 | + } | |
| 435 | + | |
| 436 | + string? directoryName = Path.GetDirectoryName(path); | |
| 437 | + string newFileName = fileName.Replace(oldStr, newStr); | |
| 438 | + string newPath = Path.Combine(directoryName ?? "", newFileName); | |
| 439 | + File.Move(path, newPath); | |
| 440 | + | |
| 441 | + return newPath; | |
| 442 | + } | |
| 443 | + /// <summary> | |
| 444 | + /// 目录名替换 | |
| 445 | + /// </summary> | |
| 446 | + public static string DirectoryNameReplace(string path, string oldStr, string newStr) | |
| 447 | + { | |
| 448 | + string fileName = Path.GetFileName(path); | |
| 449 | + if (!fileName.Contains(oldStr)) | |
| 450 | + { | |
| 451 | + return path; | |
| 452 | + } | |
| 453 | + | |
| 454 | + string? directoryName = Path.GetDirectoryName(path); | |
| 455 | + string newFileName = fileName.Replace(oldStr, newStr); | |
| 456 | + string newPath = Path.Combine(directoryName ?? "", newFileName); | |
| 457 | + Directory.Move(path, newPath); | |
| 458 | + return newPath; | |
| 459 | + } | |
| 460 | + | |
| 461 | + /// <summary> | |
| 462 | + /// 全部信息递归替换 | |
| 463 | + /// </summary> | |
| 464 | + /// <param name="dirPath"></param> | |
| 465 | + /// <param name="oldStr"></param> | |
| 466 | + /// <param name="newStr"></param> | |
| 467 | + public static void AllInfoReplace(string dirPath, string oldStr, string newStr) | |
| 468 | + { | |
| 469 | + var path = DirectoryNameReplace(dirPath, oldStr, newStr); | |
| 470 | + var dirInfo = new DirectoryInfo(path); | |
| 471 | + var files = dirInfo.GetFiles(); | |
| 472 | + var dirs = dirInfo.GetDirectories(); | |
| 473 | + if (files.Length > 0) | |
| 474 | + { | |
| 475 | + foreach (var f in files) | |
| 476 | + { | |
| 477 | + FileContentReplace(f.FullName, oldStr, newStr); | |
| 478 | + FileNameReplace(f.FullName, oldStr, newStr); | |
| 479 | + } | |
| 480 | + } | |
| 481 | + if (dirs.Length > 0) | |
| 482 | + { | |
| 483 | + foreach (var d in dirs) | |
| 484 | + { | |
| 485 | + AllInfoReplace(d.FullName, oldStr, newStr); | |
| 486 | + } | |
| 487 | + } | |
| 488 | + } | |
| 489 | + } | |
| 490 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/HtmlHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/HtmlHelper.cs | |
| 1 | +namespace Yi.Framework.Core.Helper | |
| 2 | +{ | |
| 3 | + public static class HtmlHelper | |
| 4 | + { | |
| 5 | + #region 去除富文本中的HTML标签 | |
| 6 | + /// <summary> | |
| 7 | + /// 去除富文本中的HTML标签 | |
| 8 | + /// </summary> | |
| 9 | + /// <param name="html"></param> | |
| 10 | + /// <param name="length"></param> | |
| 11 | + /// <returns></returns> | |
| 12 | + public static string ReplaceHtmlTag(string html, int length = 0) | |
| 13 | + { | |
| 14 | + string strText = System.Text.RegularExpressions.Regex.Replace(html, "<[^>]+>", ""); | |
| 15 | + strText = System.Text.RegularExpressions.Regex.Replace(strText, "&[^;]+;", ""); | |
| 16 | + | |
| 17 | + if (length > 0 && strText.Length > length) | |
| 18 | + return strText.Substring(0, length); | |
| 19 | + | |
| 20 | + return strText; | |
| 21 | + } | |
| 22 | + #endregion | |
| 23 | + } | |
| 24 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/HttpHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/HttpHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.IO; | |
| 4 | +using System.Linq; | |
| 5 | +using System.Net; | |
| 6 | +using System.Net.Http; | |
| 7 | +using System.Net.Mime; | |
| 8 | +using System.Text; | |
| 9 | +using System.Text.Json; | |
| 10 | +using System.Text.RegularExpressions; | |
| 11 | +using System.Threading.Tasks; | |
| 12 | + | |
| 13 | +namespace Yi.Framework.Core.Helper | |
| 14 | +{ | |
| 15 | + public static class HttpHelper | |
| 16 | + { | |
| 17 | + | |
| 18 | + public static HttpClient Client { get; set; } = new HttpClient(); | |
| 19 | + | |
| 20 | + public static async Task<string> Get(string url) | |
| 21 | + { | |
| 22 | + return await Client.GetStringAsync(url); | |
| 23 | + } | |
| 24 | + | |
| 25 | + public static async Task<Stream> GetIO(string url) | |
| 26 | + { | |
| 27 | + return await Client.GetStreamAsync(url); | |
| 28 | + } | |
| 29 | + | |
| 30 | + | |
| 31 | + public static async Task<string> Post(string url, object? item = null, Dictionary<string, string>? head = null) | |
| 32 | + { | |
| 33 | + | |
| 34 | + using StringContent json = new(JsonSerializer.Serialize(item), Encoding.UTF8, MediaTypeNames.Application.Json); | |
| 35 | + | |
| 36 | + | |
| 37 | + if (head is not null) | |
| 38 | + { | |
| 39 | + foreach (var d in head) | |
| 40 | + { | |
| 41 | + json.Headers.Add(d.Key, d.Value); | |
| 42 | + } | |
| 43 | + } | |
| 44 | + | |
| 45 | + var httpResponse = await Client.PostAsync(url, json); | |
| 46 | + | |
| 47 | + httpResponse.EnsureSuccessStatusCode(); | |
| 48 | + | |
| 49 | + var content = httpResponse.Content; | |
| 50 | + | |
| 51 | + return await content.ReadAsStringAsync(); | |
| 52 | + } | |
| 53 | + | |
| 54 | + | |
| 55 | + // public static string HttpGet(string Url, string postDataStr="") | |
| 56 | + // { | |
| 57 | + //#pragma warning disable SYSLIB0014 // 类型或成员已过时 | |
| 58 | + // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr); | |
| 59 | + //#pragma warning restore SYSLIB0014 // 类型或成员已过时 | |
| 60 | + // request.Method = "GET"; | |
| 61 | + // request.ContentType = "text/html;charset=UTF-8"; | |
| 62 | + | |
| 63 | + // HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | |
| 64 | + // Stream myResponseStream = response.GetResponseStream(); | |
| 65 | + // StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); | |
| 66 | + // string retString = myStreamReader.ReadToEnd(); | |
| 67 | + // myStreamReader.Close(); | |
| 68 | + // myResponseStream.Close(); | |
| 69 | + | |
| 70 | + // return retString; | |
| 71 | + // } | |
| 72 | + | |
| 73 | + // public static bool HttpIOGet(string Url, string file, string postDataStr="") | |
| 74 | + // { | |
| 75 | + // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr); | |
| 76 | + // request.Method = "GET"; | |
| 77 | + // request.ContentType = "text/html;charset=UTF-8"; | |
| 78 | + | |
| 79 | + // HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | |
| 80 | + // Stream myResponseStream = response.GetResponseStream(); | |
| 81 | + // FileStream writer = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write); | |
| 82 | + // byte[] buffer = new byte[1024]; | |
| 83 | + // int c; | |
| 84 | + // while ((c = myResponseStream.Read(buffer, 0, buffer.Length)) > 0) | |
| 85 | + // { | |
| 86 | + // writer.Write(buffer, 0, c); | |
| 87 | + // } | |
| 88 | + // writer.Close(); | |
| 89 | + // myResponseStream.Close(); | |
| 90 | + | |
| 91 | + // return true; | |
| 92 | + // } | |
| 93 | + | |
| 94 | + // public static string HttpPost(string Url, string postDataStr="") | |
| 95 | + // { | |
| 96 | + // CookieContainer cookie = new CookieContainer(); | |
| 97 | + //#pragma warning disable SYSLIB0014 // 类型或成员已过时 | |
| 98 | + // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url); | |
| 99 | + //#pragma warning restore SYSLIB0014 // 类型或成员已过时 | |
| 100 | + // request.Method = "POST"; | |
| 101 | + // request.ContentType = "application/x-www-form-urlencoded"; | |
| 102 | + // request.ContentLength = Encoding.UTF8.GetByteCount(postDataStr); | |
| 103 | + // request.CookieContainer = cookie; | |
| 104 | + | |
| 105 | + // Stream myRequestStream = request.GetRequestStream(); | |
| 106 | + // StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312")); | |
| 107 | + // myStreamWriter.Write(postDataStr); | |
| 108 | + // myStreamWriter.Close(); | |
| 109 | + | |
| 110 | + // HttpWebResponse response = (HttpWebResponse)request.GetResponse(); | |
| 111 | + | |
| 112 | + // response.Cookies = cookie.GetCookies(response.ResponseUri); | |
| 113 | + // Stream myResponseStream = response.GetResponseStream(); | |
| 114 | + // StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); | |
| 115 | + // string retString = myStreamReader.ReadToEnd(); | |
| 116 | + // myStreamReader.Close(); | |
| 117 | + // myResponseStream.Close(); | |
| 118 | + | |
| 119 | + // return retString; | |
| 120 | + // } | |
| 121 | + } | |
| 122 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/IdHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/IdHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Helper | |
| 8 | +{ | |
| 9 | + public static class IdHelper | |
| 10 | + { | |
| 11 | + public static dynamic[] ToDynamicArray(this IEnumerable<long> ids) | |
| 12 | + { | |
| 13 | + return ids.Select(id => (dynamic)id).ToArray(); | |
| 14 | + } | |
| 15 | + } | |
| 16 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/IpHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/IpHelper.cs | |
| 1 | +using System.Linq; | |
| 2 | +using System.Net; | |
| 3 | +using System.Net.NetworkInformation; | |
| 4 | +using System.Net.Sockets; | |
| 5 | + | |
| 6 | +namespace Yi.Framework.Core.Helper | |
| 7 | +{ | |
| 8 | + public class IpHelper | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 获取当前IP地址 | |
| 12 | + /// </summary> | |
| 13 | + /// <param name="preferredNetworks"></param> | |
| 14 | + /// <returns></returns> | |
| 15 | + public static string GetCurrentIp(string preferredNetworks) | |
| 16 | + { | |
| 17 | + var instanceIp = "127.0.0.1"; | |
| 18 | + | |
| 19 | + try | |
| 20 | + { | |
| 21 | + // 获取可用网卡 | |
| 22 | + var nics = NetworkInterface.GetAllNetworkInterfaces()?.Where(network => network.OperationalStatus == OperationalStatus.Up); | |
| 23 | + | |
| 24 | + // 获取所有可用网卡IP信息 | |
| 25 | + var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses); | |
| 26 | + | |
| 27 | + if (ipCollection is null) | |
| 28 | + { | |
| 29 | + return instanceIp; | |
| 30 | + } | |
| 31 | + | |
| 32 | + foreach (var ipadd in ipCollection) | |
| 33 | + { | |
| 34 | + if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork) | |
| 35 | + { | |
| 36 | + if (string.IsNullOrEmpty(preferredNetworks)) | |
| 37 | + { | |
| 38 | + instanceIp = ipadd.Address.ToString(); | |
| 39 | + break; | |
| 40 | + } | |
| 41 | + | |
| 42 | + if (!ipadd.Address.ToString().StartsWith(preferredNetworks)) continue; | |
| 43 | + instanceIp = ipadd.Address.ToString(); | |
| 44 | + break; | |
| 45 | + } | |
| 46 | + } | |
| 47 | + } | |
| 48 | + catch | |
| 49 | + { | |
| 50 | + // ignored | |
| 51 | + } | |
| 52 | + | |
| 53 | + return instanceIp; | |
| 54 | + } | |
| 55 | + } | |
| 56 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/JsonHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/JsonHelper.cs | |
| 1 | +using Newtonsoft.Json; | |
| 2 | +using Newtonsoft.Json.Converters; | |
| 3 | + | |
| 4 | +namespace Yi.Framework.Core.Helper | |
| 5 | +{ | |
| 6 | + public class JsonHelper | |
| 7 | + { | |
| 8 | + public static string ObjToStr<T>(T obj, string dateTimeFormat) | |
| 9 | + { | |
| 10 | + IsoDateTimeConverter timeConverter = new IsoDateTimeConverter() | |
| 11 | + { | |
| 12 | + DateTimeFormat = dateTimeFormat | |
| 13 | + }; | |
| 14 | + return JsonConvert.SerializeObject(obj, Formatting.Indented, timeConverter); | |
| 15 | + } | |
| 16 | + | |
| 17 | + public static string ObjToStr<T>(T obj) | |
| 18 | + { | |
| 19 | + return JsonConvert.SerializeObject(obj); | |
| 20 | + } | |
| 21 | + | |
| 22 | + public static T StrToObj<T>(string str) | |
| 23 | + { | |
| 24 | + return JsonConvert.DeserializeObject<T>(str)!; | |
| 25 | + } | |
| 26 | + /// <summary> | |
| 27 | + /// 转换对象为JSON格式数据 | |
| 28 | + /// </summary> | |
| 29 | + /// <typeparam name="T">类</typeparam> | |
| 30 | + /// <param name="obj">对象</param> | |
| 31 | + /// <returns>字符格式的JSON数据</returns> | |
| 32 | + public static string GetJSON<T>(object obj) | |
| 33 | + { | |
| 34 | + string result = string.Empty; | |
| 35 | + try | |
| 36 | + { | |
| 37 | + System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = | |
| 38 | + new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T)); | |
| 39 | + using (MemoryStream ms = new MemoryStream()) | |
| 40 | + { | |
| 41 | + serializer.WriteObject(ms, obj); | |
| 42 | + result = System.Text.Encoding.UTF8.GetString(ms.ToArray()); | |
| 43 | + } | |
| 44 | + } | |
| 45 | + catch (Exception) | |
| 46 | + { | |
| 47 | + throw; | |
| 48 | + } | |
| 49 | + return result; | |
| 50 | + } | |
| 51 | + /// <summary> | |
| 52 | + /// 转换List<T>的数据为JSON格式 | |
| 53 | + /// </summary> | |
| 54 | + /// <typeparam name="T">类</typeparam> | |
| 55 | + /// <param name="vals">列表值</param> | |
| 56 | + /// <returns>JSON格式数据</returns> | |
| 57 | + public string JSON<T>(List<T> vals) | |
| 58 | + { | |
| 59 | + System.Text.StringBuilder st = new System.Text.StringBuilder(); | |
| 60 | + try | |
| 61 | + { | |
| 62 | + System.Runtime.Serialization.Json.DataContractJsonSerializer s = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T)); | |
| 63 | + | |
| 64 | + foreach (T city in vals) | |
| 65 | + { | |
| 66 | + using (MemoryStream ms = new MemoryStream()) | |
| 67 | + { | |
| 68 | + s.WriteObject(ms, city); | |
| 69 | + st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray())); | |
| 70 | + } | |
| 71 | + } | |
| 72 | + } | |
| 73 | + catch (Exception) | |
| 74 | + { | |
| 75 | + } | |
| 76 | + | |
| 77 | + return st.ToString(); | |
| 78 | + } | |
| 79 | + /// <summary> | |
| 80 | + /// JSON格式字符转换为T类型的对象 | |
| 81 | + /// </summary> | |
| 82 | + /// <typeparam name="T"></typeparam> | |
| 83 | + /// <param name="jsonStr"></param> | |
| 84 | + /// <returns></returns> | |
| 85 | + public static T ParseFormByJson<T>(string jsonStr) | |
| 86 | + { | |
| 87 | + T obj = Activator.CreateInstance<T>(); | |
| 88 | + using (MemoryStream ms = | |
| 89 | + new MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonStr))) | |
| 90 | + { | |
| 91 | + System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = | |
| 92 | + new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T)); | |
| 93 | + return (T)serializer.ReadObject(ms)!; | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + public string JSON1<SendData>(List<SendData> vals) | |
| 98 | + { | |
| 99 | + System.Text.StringBuilder st = new System.Text.StringBuilder(); | |
| 100 | + try | |
| 101 | + { | |
| 102 | + System.Runtime.Serialization.Json.DataContractJsonSerializer s = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(SendData)); | |
| 103 | + | |
| 104 | + foreach (SendData city in vals) | |
| 105 | + { | |
| 106 | + using (MemoryStream ms = new MemoryStream()) | |
| 107 | + { | |
| 108 | + s.WriteObject(ms, city); | |
| 109 | + st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray())); | |
| 110 | + } | |
| 111 | + } | |
| 112 | + } | |
| 113 | + catch (Exception) | |
| 114 | + { | |
| 115 | + } | |
| 116 | + | |
| 117 | + return st.ToString(); | |
| 118 | + } | |
| 119 | + | |
| 120 | + private static bool IsJsonStart(ref string json) | |
| 121 | + { | |
| 122 | + if (!string.IsNullOrEmpty(json)) | |
| 123 | + { | |
| 124 | + json = json.Trim('\r', '\n', ' '); | |
| 125 | + if (json.Length > 1) | |
| 126 | + { | |
| 127 | + char s = json[0]; | |
| 128 | + char e = json[json.Length - 1]; | |
| 129 | + return s == '{' && e == '}' || s == '[' && e == ']'; | |
| 130 | + } | |
| 131 | + } | |
| 132 | + return false; | |
| 133 | + } | |
| 134 | + public static bool IsJson(string json) | |
| 135 | + { | |
| 136 | + int errIndex; | |
| 137 | + return IsJson(json, out errIndex); | |
| 138 | + } | |
| 139 | + public static bool IsJson(string json, out int errIndex) | |
| 140 | + { | |
| 141 | + errIndex = 0; | |
| 142 | + if (IsJsonStart(ref json)) | |
| 143 | + { | |
| 144 | + CharState cs = new CharState(); | |
| 145 | + char c; | |
| 146 | + for (int i = 0; i < json.Length; i++) | |
| 147 | + { | |
| 148 | + c = json[i]; | |
| 149 | + if (SetCharState(c, ref cs) && cs.childrenStart)//设置关键符号状态。 | |
| 150 | + { | |
| 151 | + string item = json.Substring(i); | |
| 152 | + int err; | |
| 153 | + int length = GetValueLength(item, true, out err); | |
| 154 | + cs.childrenStart = false; | |
| 155 | + if (err > 0) | |
| 156 | + { | |
| 157 | + errIndex = i + err; | |
| 158 | + return false; | |
| 159 | + } | |
| 160 | + i = i + length - 1; | |
| 161 | + } | |
| 162 | + if (cs.isError) | |
| 163 | + { | |
| 164 | + errIndex = i; | |
| 165 | + return false; | |
| 166 | + } | |
| 167 | + } | |
| 168 | + | |
| 169 | + return !cs.arrayStart && !cs.jsonStart; | |
| 170 | + } | |
| 171 | + return false; | |
| 172 | + } | |
| 173 | + | |
| 174 | + /// <summary> | |
| 175 | + /// 获取值的长度(当Json值嵌套以"{"或"["开头时) | |
| 176 | + /// </summary> | |
| 177 | + private static int GetValueLength(string json, bool breakOnErr, out int errIndex) | |
| 178 | + { | |
| 179 | + errIndex = 0; | |
| 180 | + int len = 0; | |
| 181 | + if (!string.IsNullOrEmpty(json)) | |
| 182 | + { | |
| 183 | + CharState cs = new CharState(); | |
| 184 | + char c; | |
| 185 | + for (int i = 0; i < json.Length; i++) | |
| 186 | + { | |
| 187 | + c = json[i]; | |
| 188 | + if (!SetCharState(c, ref cs))//设置关键符号状态。 | |
| 189 | + { | |
| 190 | + if (!cs.jsonStart && !cs.arrayStart)//json结束,又不是数组,则退出。 | |
| 191 | + { | |
| 192 | + break; | |
| 193 | + } | |
| 194 | + } | |
| 195 | + else if (cs.childrenStart)//正常字符,值状态下。 | |
| 196 | + { | |
| 197 | + int length = GetValueLength(json.Substring(i), breakOnErr, out errIndex);//递归子值,返回一个长度。。。 | |
| 198 | + cs.childrenStart = false; | |
| 199 | + cs.valueStart = 0; | |
| 200 | + //cs.state = 0; | |
| 201 | + i = i + length - 1; | |
| 202 | + } | |
| 203 | + if (breakOnErr && cs.isError) | |
| 204 | + { | |
| 205 | + errIndex = i; | |
| 206 | + return i; | |
| 207 | + } | |
| 208 | + if (!cs.jsonStart && !cs.arrayStart)//记录当前结束位置。 | |
| 209 | + { | |
| 210 | + len = i + 1;//长度比索引+1 | |
| 211 | + break; | |
| 212 | + } | |
| 213 | + } | |
| 214 | + } | |
| 215 | + return len; | |
| 216 | + } | |
| 217 | + | |
| 218 | + /// <summary> | |
| 219 | + /// 设置字符状态(返回true则为关键词,返回false则当为普通字符处理) | |
| 220 | + /// </summary> | |
| 221 | + private static bool SetCharState(char c, ref CharState cs) | |
| 222 | + { | |
| 223 | + cs.CheckIsError(c); | |
| 224 | + switch (c) | |
| 225 | + { | |
| 226 | + case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}] | |
| 227 | + #region 大括号 | |
| 228 | + if (cs.keyStart <= 0 && cs.valueStart <= 0) | |
| 229 | + { | |
| 230 | + cs.keyStart = 0; | |
| 231 | + cs.valueStart = 0; | |
| 232 | + if (cs.jsonStart && cs.state == 1) | |
| 233 | + { | |
| 234 | + cs.childrenStart = true; | |
| 235 | + } | |
| 236 | + else | |
| 237 | + { | |
| 238 | + cs.state = 0; | |
| 239 | + } | |
| 240 | + cs.jsonStart = true;//开始。 | |
| 241 | + return true; | |
| 242 | + } | |
| 243 | + #endregion | |
| 244 | + break; | |
| 245 | + case '}': | |
| 246 | + #region 大括号结束 | |
| 247 | + if (cs.keyStart <= 0 && cs.valueStart < 2 && cs.jsonStart) | |
| 248 | + { | |
| 249 | + cs.jsonStart = false;//正常结束。 | |
| 250 | + cs.state = 0; | |
| 251 | + cs.keyStart = 0; | |
| 252 | + cs.valueStart = 0; | |
| 253 | + cs.setDicValue = true; | |
| 254 | + return true; | |
| 255 | + } | |
| 256 | + // cs.isError = !cs.jsonStart && cs.state == 0; | |
| 257 | + #endregion | |
| 258 | + break; | |
| 259 | + case '[': | |
| 260 | + #region 中括号开始 | |
| 261 | + if (!cs.jsonStart) | |
| 262 | + { | |
| 263 | + cs.arrayStart = true; | |
| 264 | + return true; | |
| 265 | + } | |
| 266 | + else if (cs.jsonStart && cs.state == 1) | |
| 267 | + { | |
| 268 | + cs.childrenStart = true; | |
| 269 | + return true; | |
| 270 | + } | |
| 271 | + #endregion | |
| 272 | + break; | |
| 273 | + case ']': | |
| 274 | + #region 中括号结束 | |
| 275 | + if (cs.arrayStart && !cs.jsonStart && cs.keyStart <= 2 && cs.valueStart <= 0)//[{},333]//这样结束。 | |
| 276 | + { | |
| 277 | + cs.keyStart = 0; | |
| 278 | + cs.valueStart = 0; | |
| 279 | + cs.arrayStart = false; | |
| 280 | + return true; | |
| 281 | + } | |
| 282 | + #endregion | |
| 283 | + break; | |
| 284 | + case '"': | |
| 285 | + case '\'': | |
| 286 | + #region 引号 | |
| 287 | + if (cs.jsonStart || cs.arrayStart) | |
| 288 | + { | |
| 289 | + if (cs.state == 0)//key阶段,有可能是数组["aa",{}] | |
| 290 | + { | |
| 291 | + if (cs.keyStart <= 0) | |
| 292 | + { | |
| 293 | + cs.keyStart = c == '"' ? 3 : 2; | |
| 294 | + return true; | |
| 295 | + } | |
| 296 | + else if (cs.keyStart == 2 && c == '\'' || cs.keyStart == 3 && c == '"') | |
| 297 | + { | |
| 298 | + if (!cs.escapeChar) | |
| 299 | + { | |
| 300 | + cs.keyStart = -1; | |
| 301 | + return true; | |
| 302 | + } | |
| 303 | + else | |
| 304 | + { | |
| 305 | + cs.escapeChar = false; | |
| 306 | + } | |
| 307 | + } | |
| 308 | + } | |
| 309 | + else if (cs.state == 1 && cs.jsonStart)//值阶段必须是Json开始了。 | |
| 310 | + { | |
| 311 | + if (cs.valueStart <= 0) | |
| 312 | + { | |
| 313 | + cs.valueStart = c == '"' ? 3 : 2; | |
| 314 | + return true; | |
| 315 | + } | |
| 316 | + else if (cs.valueStart == 2 && c == '\'' || cs.valueStart == 3 && c == '"') | |
| 317 | + { | |
| 318 | + if (!cs.escapeChar) | |
| 319 | + { | |
| 320 | + cs.valueStart = -1; | |
| 321 | + return true; | |
| 322 | + } | |
| 323 | + else | |
| 324 | + { | |
| 325 | + cs.escapeChar = false; | |
| 326 | + } | |
| 327 | + } | |
| 328 | + | |
| 329 | + } | |
| 330 | + } | |
| 331 | + #endregion | |
| 332 | + break; | |
| 333 | + case ':': | |
| 334 | + #region 冒号 | |
| 335 | + if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 0) | |
| 336 | + { | |
| 337 | + if (cs.keyStart == 1) | |
| 338 | + { | |
| 339 | + cs.keyStart = -1; | |
| 340 | + } | |
| 341 | + cs.state = 1; | |
| 342 | + return true; | |
| 343 | + } | |
| 344 | + // cs.isError = !cs.jsonStart || (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1); | |
| 345 | + #endregion | |
| 346 | + break; | |
| 347 | + case ',': | |
| 348 | + #region 逗号 //["aa",{aa:12,}] | |
| 349 | + | |
| 350 | + if (cs.jsonStart) | |
| 351 | + { | |
| 352 | + if (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1) | |
| 353 | + { | |
| 354 | + cs.state = 0; | |
| 355 | + cs.keyStart = 0; | |
| 356 | + cs.valueStart = 0; | |
| 357 | + //if (cs.valueStart == 1) | |
| 358 | + //{ | |
| 359 | + // cs.valueStart = 0; | |
| 360 | + //} | |
| 361 | + cs.setDicValue = true; | |
| 362 | + return true; | |
| 363 | + } | |
| 364 | + } | |
| 365 | + else if (cs.arrayStart && cs.keyStart <= 2) | |
| 366 | + { | |
| 367 | + cs.keyStart = 0; | |
| 368 | + //if (cs.keyStart == 1) | |
| 369 | + //{ | |
| 370 | + // cs.keyStart = -1; | |
| 371 | + //} | |
| 372 | + return true; | |
| 373 | + } | |
| 374 | + #endregion | |
| 375 | + break; | |
| 376 | + case ' ': | |
| 377 | + case '\r': | |
| 378 | + case '\n'://[ "a",\r\n{} ] | |
| 379 | + case '\0': | |
| 380 | + case '\t': | |
| 381 | + if (cs.keyStart <= 0 && cs.valueStart <= 0) //cs.jsonStart && | |
| 382 | + { | |
| 383 | + return true;//跳过空格。 | |
| 384 | + } | |
| 385 | + break; | |
| 386 | + default: //值开头。。 | |
| 387 | + if (c == '\\') //转义符号 | |
| 388 | + { | |
| 389 | + if (cs.escapeChar) | |
| 390 | + { | |
| 391 | + cs.escapeChar = false; | |
| 392 | + } | |
| 393 | + else | |
| 394 | + { | |
| 395 | + cs.escapeChar = true; | |
| 396 | + return true; | |
| 397 | + } | |
| 398 | + } | |
| 399 | + else | |
| 400 | + { | |
| 401 | + cs.escapeChar = false; | |
| 402 | + } | |
| 403 | + if (cs.jsonStart || cs.arrayStart) // Json 或数组开始了。 | |
| 404 | + { | |
| 405 | + if (cs.keyStart <= 0 && cs.state == 0) | |
| 406 | + { | |
| 407 | + cs.keyStart = 1;//无引号的 | |
| 408 | + } | |
| 409 | + else if (cs.valueStart <= 0 && cs.state == 1 && cs.jsonStart)//只有Json开始才有值。 | |
| 410 | + { | |
| 411 | + cs.valueStart = 1;//无引号的 | |
| 412 | + } | |
| 413 | + } | |
| 414 | + break; | |
| 415 | + } | |
| 416 | + return false; | |
| 417 | + } | |
| 418 | + } | |
| 419 | + /// <summary> | |
| 420 | + /// 字符状态 | |
| 421 | + /// </summary> | |
| 422 | + public class CharState | |
| 423 | + { | |
| 424 | + internal bool jsonStart = false;//以 "{"开始了... | |
| 425 | + internal bool setDicValue = false;// 可以设置字典值了。 | |
| 426 | + internal bool escapeChar = false;//以"\"转义符号开始了 | |
| 427 | + /// <summary> | |
| 428 | + /// 数组开始【仅第一开头才算】,值嵌套的以【childrenStart】来标识。 | |
| 429 | + /// </summary> | |
| 430 | + internal bool arrayStart = false;//以"[" 符号开始了 | |
| 431 | + internal bool childrenStart = false;//子级嵌套开始了。 | |
| 432 | + /// <summary> | |
| 433 | + /// 【0 初始状态,或 遇到“,”逗号】;【1 遇到“:”冒号】 | |
| 434 | + /// </summary> | |
| 435 | + internal int state = 0; | |
| 436 | + | |
| 437 | + /// <summary> | |
| 438 | + /// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】 | |
| 439 | + /// </summary> | |
| 440 | + internal int keyStart = 0; | |
| 441 | + /// <summary> | |
| 442 | + /// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】 | |
| 443 | + /// </summary> | |
| 444 | + internal int valueStart = 0; | |
| 445 | + internal bool isError = false;//是否语法错误。 | |
| 446 | + | |
| 447 | + internal void CheckIsError(char c)//只当成一级处理(因为GetLength会递归到每一个子项处理) | |
| 448 | + { | |
| 449 | + if (keyStart > 1 || valueStart > 1) | |
| 450 | + { | |
| 451 | + return; | |
| 452 | + } | |
| 453 | + //示例 ["aa",{"bbbb":123,"fff","Ddd"}] | |
| 454 | + switch (c) | |
| 455 | + { | |
| 456 | + case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}] | |
| 457 | + isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。 | |
| 458 | + break; | |
| 459 | + case '}': | |
| 460 | + isError = !jsonStart || keyStart != 0 && state == 0;//重复结束错误 或者 提前结束{"aa"}。正常的有{} | |
| 461 | + break; | |
| 462 | + case '[': | |
| 463 | + isError = arrayStart && state == 0;//重复开始错误 | |
| 464 | + break; | |
| 465 | + case ']': | |
| 466 | + isError = !arrayStart || jsonStart;//重复开始错误 或者 Json 未结束 | |
| 467 | + break; | |
| 468 | + case '"': | |
| 469 | + case '\'': | |
| 470 | + isError = !(jsonStart || arrayStart); //json 或数组开始。 | |
| 471 | + if (!isError) | |
| 472 | + { | |
| 473 | + //重复开始 [""",{"" "}] | |
| 474 | + isError = state == 0 && keyStart == -1 || state == 1 && valueStart == -1; | |
| 475 | + } | |
| 476 | + if (!isError && arrayStart && !jsonStart && c == '\'')//['aa',{}] | |
| 477 | + { | |
| 478 | + isError = true; | |
| 479 | + } | |
| 480 | + break; | |
| 481 | + case ':': | |
| 482 | + isError = !jsonStart || state == 1;//重复出现。 | |
| 483 | + break; | |
| 484 | + case ',': | |
| 485 | + isError = !(jsonStart || arrayStart); //json 或数组开始。 | |
| 486 | + if (!isError) | |
| 487 | + { | |
| 488 | + if (jsonStart) | |
| 489 | + { | |
| 490 | + isError = state == 0 || state == 1 && valueStart > 1;//重复出现。 | |
| 491 | + } | |
| 492 | + else if (arrayStart)//["aa,] [,] [{},{}] | |
| 493 | + { | |
| 494 | + isError = keyStart == 0 && !setDicValue; | |
| 495 | + } | |
| 496 | + } | |
| 497 | + break; | |
| 498 | + case ' ': | |
| 499 | + case '\r': | |
| 500 | + case '\n'://[ "a",\r\n{} ] | |
| 501 | + case '\0': | |
| 502 | + case '\t': | |
| 503 | + break; | |
| 504 | + default: //值开头。。 | |
| 505 | + isError = !jsonStart && !arrayStart || state == 0 && keyStart == -1 || valueStart == -1 && state == 1;// | |
| 506 | + break; | |
| 507 | + } | |
| 508 | + //if (isError) | |
| 509 | + //{ | |
| 510 | + | |
| 511 | + //} | |
| 512 | + } | |
| 513 | + } | |
| 514 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/MD5Hepler.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/MD5Hepler.cs | |
| 1 | +using System; | |
| 2 | +using System.IO; | |
| 3 | +using System.Security.Cryptography; | |
| 4 | +using System.Text; | |
| 5 | + | |
| 6 | +namespace Yi.Framework.Core.Helper | |
| 7 | +{ | |
| 8 | + public class MD5Helper | |
| 9 | + { | |
| 10 | + /// <summary> | |
| 11 | + /// 生成PasswordSalt | |
| 12 | + /// </summary> | |
| 13 | + /// <returns>返回string</returns> | |
| 14 | + public static string GenerateSalt() | |
| 15 | + { | |
| 16 | + byte[] buf = new byte[16]; | |
| 17 | +#pragma warning disable SYSLIB0023 // 类型或成员已过时 | |
| 18 | + new RNGCryptoServiceProvider().GetBytes(buf); | |
| 19 | +#pragma warning restore SYSLIB0023 // 类型或成员已过时 | |
| 20 | + return Convert.ToBase64String(buf); | |
| 21 | + } | |
| 22 | + | |
| 23 | + /// <summary> | |
| 24 | + /// 加密密码 | |
| 25 | + /// </summary> | |
| 26 | + /// <param name="pass">密码</param> | |
| 27 | + /// <param name="passwordFormat">加密类型</param> | |
| 28 | + /// <param name="salt">PasswordSalt</param> | |
| 29 | + /// <returns>加密后的密码</returns> | |
| 30 | + public static string SHA2Encode(string pass, string salt, int passwordFormat = 1) | |
| 31 | + { | |
| 32 | + if (passwordFormat == 0) // MembershipPasswordFormat.Clear | |
| 33 | + return pass; | |
| 34 | + | |
| 35 | + byte[] bIn = Encoding.Unicode.GetBytes(pass); | |
| 36 | + byte[] bSalt = Convert.FromBase64String(salt); | |
| 37 | + byte[] bAll = new byte[bSalt.Length + bIn.Length]; | |
| 38 | + byte[]? bRet = null; | |
| 39 | + | |
| 40 | + Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length); | |
| 41 | + Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length); | |
| 42 | + | |
| 43 | +#pragma warning disable SYSLIB0021 // 类型或成员已过时 | |
| 44 | + var s = SHA512.Create(); | |
| 45 | +#pragma warning restore SYSLIB0021 // 类型或成员已过时 | |
| 46 | + bRet = s.ComputeHash(bAll); | |
| 47 | + | |
| 48 | + return ConvertEx.ToUrlBase64String(bRet); | |
| 49 | + } | |
| 50 | + | |
| 51 | + /// <summary> | |
| 52 | + /// 16位MD5加密 | |
| 53 | + /// </summary> | |
| 54 | + /// <param name="password"></param> | |
| 55 | + /// <returns></returns> | |
| 56 | + public static string MD5Encrypt16(string password) | |
| 57 | + { | |
| 58 | + var md5 = MD5.Create(); | |
| 59 | + string t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password)), 4, 8); | |
| 60 | + t2 = t2.Replace("-", string.Empty); | |
| 61 | + return t2; | |
| 62 | + } | |
| 63 | + | |
| 64 | + /// <summary> | |
| 65 | + /// 32位MD5加密 | |
| 66 | + /// </summary> | |
| 67 | + /// <param name="password"></param> | |
| 68 | + /// <returns></returns> | |
| 69 | + public static string MD5Encrypt32(string password = "") | |
| 70 | + { | |
| 71 | + string pwd = string.Empty; | |
| 72 | + try | |
| 73 | + { | |
| 74 | + if (!string.IsNullOrEmpty(password) && !string.IsNullOrWhiteSpace(password)) | |
| 75 | + { | |
| 76 | + MD5 md5 = MD5.Create(); //实例化一个md5对像 | |
| 77 | + // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择 | |
| 78 | + byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password)); | |
| 79 | + // 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得 | |
| 80 | + foreach (var item in s) | |
| 81 | + { | |
| 82 | + // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 | |
| 83 | + pwd = string.Concat(pwd, item.ToString("X2")); | |
| 84 | + } | |
| 85 | + } | |
| 86 | + } | |
| 87 | + catch | |
| 88 | + { | |
| 89 | + throw new Exception($"错误的 password 字符串:【{password}】"); | |
| 90 | + } | |
| 91 | + return pwd; | |
| 92 | + } | |
| 93 | + | |
| 94 | + /// <summary> | |
| 95 | + /// 64位MD5加密 | |
| 96 | + /// </summary> | |
| 97 | + /// <param name="password"></param> | |
| 98 | + /// <returns></returns> | |
| 99 | + public static string MD5Encrypt64(string password) | |
| 100 | + { | |
| 101 | + // 实例化一个md5对像 | |
| 102 | + // 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择 | |
| 103 | + MD5 md5 = MD5.Create(); | |
| 104 | + byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password)); | |
| 105 | + return Convert.ToBase64String(s); | |
| 106 | + } | |
| 107 | + } | |
| 108 | + public class ConvertEx | |
| 109 | + { | |
| 110 | + static readonly char[] padding = { '=' }; | |
| 111 | + public static string ToUrlBase64String(byte[] inArray) | |
| 112 | + { | |
| 113 | + var str = Convert.ToBase64String(inArray); | |
| 114 | + str = str.TrimEnd(padding).Replace('+', '-').Replace('/', '_'); | |
| 115 | + | |
| 116 | + return str; | |
| 117 | + } | |
| 118 | + | |
| 119 | + public static byte[] FromUrlBase64String(string s) | |
| 120 | + { | |
| 121 | + string incoming = s.Replace('_', '/').Replace('-', '+'); | |
| 122 | + switch (s.Length % 4) | |
| 123 | + { | |
| 124 | + case 2: incoming += "=="; break; | |
| 125 | + case 3: incoming += "="; break; | |
| 126 | + } | |
| 127 | + byte[] bytes = Convert.FromBase64String(incoming); | |
| 128 | + | |
| 129 | + return bytes; | |
| 130 | + } | |
| 131 | + } | |
| 132 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/MimeHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/MimeHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections; | |
| 3 | +using System.Collections.Generic; | |
| 4 | +using System.Linq; | |
| 5 | +using System.Text; | |
| 6 | +using System.Threading.Tasks; | |
| 7 | +using Yi.Framework.Core.Enums; | |
| 8 | + | |
| 9 | +namespace Yi.Framework.Core.Helper | |
| 10 | +{ | |
| 11 | + public static class MimeHelper | |
| 12 | + { | |
| 13 | + // 通过自己定义一个静态类 | |
| 14 | + // 将所有的Content Type都扔进去吧 | |
| 15 | + // 调用的时候直接调用静态方法即可。 | |
| 16 | + | |
| 17 | + public static List<string> ImageType { get; set; } = new List<string> | |
| 18 | + { | |
| 19 | + ".jpg",".png",".jpeg" | |
| 20 | + }; | |
| 21 | + | |
| 22 | + private static Hashtable _mimeMappingTable; | |
| 23 | + | |
| 24 | + private static void AddMimeMapping(string extension, string MimeType) | |
| 25 | + { | |
| 26 | + _mimeMappingTable.Add(extension, MimeType); | |
| 27 | + } | |
| 28 | + | |
| 29 | + public static string GetMimeMapping(string FileName) | |
| 30 | + { | |
| 31 | + string text = null!; | |
| 32 | + int num = FileName.LastIndexOf('.'); | |
| 33 | + if (0 < num && num > FileName.LastIndexOf('\\')) | |
| 34 | + { | |
| 35 | + text = (string)_mimeMappingTable[FileName.Substring(num)]!; | |
| 36 | + } | |
| 37 | + if (text == null) | |
| 38 | + { | |
| 39 | + text = (string)_mimeMappingTable[".*"]!; | |
| 40 | + } | |
| 41 | + return text; | |
| 42 | + } | |
| 43 | + | |
| 44 | + public static FileTypeEnum GetFileType(string fileName) | |
| 45 | + { | |
| 46 | + var extension = Path.GetExtension(fileName); | |
| 47 | + if (ImageType.Contains(extension.ToLower())) | |
| 48 | + return FileTypeEnum.image; | |
| 49 | + return FileTypeEnum.file; | |
| 50 | + | |
| 51 | + | |
| 52 | + } | |
| 53 | + | |
| 54 | + static MimeHelper() | |
| 55 | + { | |
| 56 | + _mimeMappingTable = new Hashtable(190, StringComparer.CurrentCultureIgnoreCase); | |
| 57 | + AddMimeMapping(".323", "text/h323"); | |
| 58 | + AddMimeMapping(".asx", "video/x-ms-asf"); | |
| 59 | + AddMimeMapping(".acx", "application/internet-property-stream"); | |
| 60 | + AddMimeMapping(".ai", "application/postscript"); | |
| 61 | + AddMimeMapping(".aif", "audio/x-aiff"); | |
| 62 | + AddMimeMapping(".aiff", "audio/aiff"); | |
| 63 | + AddMimeMapping(".axs", "application/olescript"); | |
| 64 | + AddMimeMapping(".aifc", "audio/aiff"); | |
| 65 | + AddMimeMapping(".asr", "video/x-ms-asf"); | |
| 66 | + AddMimeMapping(".avi", "video/x-msvideo"); | |
| 67 | + AddMimeMapping(".asf", "video/x-ms-asf"); | |
| 68 | + AddMimeMapping(".au", "audio/basic"); | |
| 69 | + AddMimeMapping(".application", "application/x-ms-application"); | |
| 70 | + AddMimeMapping(".bin", "application/octet-stream"); | |
| 71 | + AddMimeMapping(".bas", "text/plain"); | |
| 72 | + AddMimeMapping(".bcpio", "application/x-bcpio"); | |
| 73 | + AddMimeMapping(".bmp", "image/bmp"); | |
| 74 | + AddMimeMapping(".cdf", "application/x-cdf"); | |
| 75 | + AddMimeMapping(".cat", "application/vndms-pkiseccat"); | |
| 76 | + AddMimeMapping(".crt", "application/x-x509-ca-cert"); | |
| 77 | + AddMimeMapping(".c", "text/plain"); | |
| 78 | + AddMimeMapping(".css", "text/css"); | |
| 79 | + AddMimeMapping(".cer", "application/x-x509-ca-cert"); | |
| 80 | + AddMimeMapping(".crl", "application/pkix-crl"); | |
| 81 | + AddMimeMapping(".cmx", "image/x-cmx"); | |
| 82 | + AddMimeMapping(".csh", "application/x-csh"); | |
| 83 | + AddMimeMapping(".cod", "image/cis-cod"); | |
| 84 | + AddMimeMapping(".cpio", "application/x-cpio"); | |
| 85 | + AddMimeMapping(".clp", "application/x-msclip"); | |
| 86 | + AddMimeMapping(".crd", "application/x-mscardfile"); | |
| 87 | + AddMimeMapping(".deploy", "application/octet-stream"); | |
| 88 | + AddMimeMapping(".dll", "application/x-msdownload"); | |
| 89 | + AddMimeMapping(".dot", "application/msword"); | |
| 90 | + AddMimeMapping(".doc", "application/msword"); | |
| 91 | + AddMimeMapping(".dvi", "application/x-dvi"); | |
| 92 | + AddMimeMapping(".dir", "application/x-director"); | |
| 93 | + AddMimeMapping(".dxr", "application/x-director"); | |
| 94 | + AddMimeMapping(".der", "application/x-x509-ca-cert"); | |
| 95 | + AddMimeMapping(".dib", "image/bmp"); | |
| 96 | + AddMimeMapping(".dcr", "application/x-director"); | |
| 97 | + AddMimeMapping(".disco", "text/xml"); | |
| 98 | + AddMimeMapping(".exe", "application/octet-stream"); | |
| 99 | + AddMimeMapping(".etx", "text/x-setext"); | |
| 100 | + AddMimeMapping(".evy", "application/envoy"); | |
| 101 | + AddMimeMapping(".eml", "message/rfc822"); | |
| 102 | + AddMimeMapping(".eps", "application/postscript"); | |
| 103 | + AddMimeMapping(".flr", "x-world/x-vrml"); | |
| 104 | + AddMimeMapping(".fif", "application/fractals"); | |
| 105 | + AddMimeMapping(".gtar", "application/x-gtar"); | |
| 106 | + AddMimeMapping(".gif", "image/gif"); | |
| 107 | + AddMimeMapping(".gz", "application/x-gzip"); | |
| 108 | + AddMimeMapping(".hta", "application/hta"); | |
| 109 | + AddMimeMapping(".htc", "text/x-component"); | |
| 110 | + AddMimeMapping(".htt", "text/webviewhtml"); | |
| 111 | + AddMimeMapping(".h", "text/plain"); | |
| 112 | + AddMimeMapping(".hdf", "application/x-hdf"); | |
| 113 | + AddMimeMapping(".hlp", "application/winhlp"); | |
| 114 | + AddMimeMapping(".html", "text/html"); | |
| 115 | + AddMimeMapping(".htm", "text/html"); | |
| 116 | + AddMimeMapping(".hqx", "application/mac-binhex40"); | |
| 117 | + AddMimeMapping(".isp", "application/x-internet-signup"); | |
| 118 | + AddMimeMapping(".iii", "application/x-iphone"); | |
| 119 | + AddMimeMapping(".ief", "image/ief"); | |
| 120 | + AddMimeMapping(".ivf", "video/x-ivf"); | |
| 121 | + AddMimeMapping(".ins", "application/x-internet-signup"); | |
| 122 | + AddMimeMapping(".ico", "image/x-icon"); | |
| 123 | + AddMimeMapping(".jpg", "image/jpeg"); | |
| 124 | + AddMimeMapping(".jfif", "image/pjpeg"); | |
| 125 | + AddMimeMapping(".jpe", "image/jpeg"); | |
| 126 | + AddMimeMapping(".jpeg", "image/jpeg"); | |
| 127 | + AddMimeMapping(".js", "application/x-javascript"); | |
| 128 | + AddMimeMapping(".lsx", "video/x-la-asf"); | |
| 129 | + AddMimeMapping(".latex", "application/x-latex"); | |
| 130 | + AddMimeMapping(".lsf", "video/x-la-asf"); | |
| 131 | + AddMimeMapping(".manifest", "application/x-ms-manifest"); | |
| 132 | + AddMimeMapping(".mhtml", "message/rfc822"); | |
| 133 | + AddMimeMapping(".mny", "application/x-msmoney"); | |
| 134 | + AddMimeMapping(".mht", "message/rfc822"); | |
| 135 | + AddMimeMapping(".mid", "audio/mid"); | |
| 136 | + AddMimeMapping(".mpv2", "video/mpeg"); | |
| 137 | + AddMimeMapping(".man", "application/x-troff-man"); | |
| 138 | + AddMimeMapping(".mvb", "application/x-msmediaview"); | |
| 139 | + AddMimeMapping(".mpeg", "video/mpeg"); | |
| 140 | + AddMimeMapping(".m3u", "audio/x-mpegurl"); | |
| 141 | + AddMimeMapping(".mdb", "application/x-msaccess"); | |
| 142 | + AddMimeMapping(".mpp", "application/vnd.ms-project"); | |
| 143 | + AddMimeMapping(".m1v", "video/mpeg"); | |
| 144 | + AddMimeMapping(".mpa", "video/mpeg"); | |
| 145 | + AddMimeMapping(".me", "application/x-troff-me"); | |
| 146 | + AddMimeMapping(".m13", "application/x-msmediaview"); | |
| 147 | + AddMimeMapping(".movie", "video/x-sgi-movie"); | |
| 148 | + AddMimeMapping(".m14", "application/x-msmediaview"); | |
| 149 | + AddMimeMapping(".mpe", "video/mpeg"); | |
| 150 | + AddMimeMapping(".mp2", "video/mpeg"); | |
| 151 | + AddMimeMapping(".mov", "video/quicktime"); | |
| 152 | + AddMimeMapping(".mp3", "audio/mpeg"); | |
| 153 | + AddMimeMapping(".mpg", "video/mpeg"); | |
| 154 | + AddMimeMapping(".ms", "application/x-troff-ms"); | |
| 155 | + AddMimeMapping(".nc", "application/x-netcdf"); | |
| 156 | + AddMimeMapping(".nws", "message/rfc822"); | |
| 157 | + AddMimeMapping(".oda", "application/oda"); | |
| 158 | + AddMimeMapping(".ods", "application/oleobject"); | |
| 159 | + AddMimeMapping(".pmc", "application/x-perfmon"); | |
| 160 | + AddMimeMapping(".p7r", "application/x-pkcs7-certreqresp"); | |
| 161 | + AddMimeMapping(".p7b", "application/x-pkcs7-certificates"); | |
| 162 | + AddMimeMapping(".p7s", "application/pkcs7-signature"); | |
| 163 | + AddMimeMapping(".pmw", "application/x-perfmon"); | |
| 164 | + AddMimeMapping(".ps", "application/postscript"); | |
| 165 | + AddMimeMapping(".p7c", "application/pkcs7-mime"); | |
| 166 | + AddMimeMapping(".pbm", "image/x-portable-bitmap"); | |
| 167 | + AddMimeMapping(".ppm", "image/x-portable-pixmap"); | |
| 168 | + AddMimeMapping(".pub", "application/x-mspublisher"); | |
| 169 | + AddMimeMapping(".pnm", "image/x-portable-anymap"); | |
| 170 | + AddMimeMapping(".png", "image/png"); | |
| 171 | + AddMimeMapping(".pml", "application/x-perfmon"); | |
| 172 | + AddMimeMapping(".p10", "application/pkcs10"); | |
| 173 | + AddMimeMapping(".pfx", "application/x-pkcs12"); | |
| 174 | + AddMimeMapping(".p12", "application/x-pkcs12"); | |
| 175 | + AddMimeMapping(".pdf", "application/pdf"); | |
| 176 | + AddMimeMapping(".pps", "application/vnd.ms-powerpoint"); | |
| 177 | + AddMimeMapping(".p7m", "application/pkcs7-mime"); | |
| 178 | + AddMimeMapping(".pko", "application/vndms-pkipko"); | |
| 179 | + AddMimeMapping(".ppt", "application/vnd.ms-powerpoint"); | |
| 180 | + AddMimeMapping(".pmr", "application/x-perfmon"); | |
| 181 | + AddMimeMapping(".pma", "application/x-perfmon"); | |
| 182 | + AddMimeMapping(".pot", "application/vnd.ms-powerpoint"); | |
| 183 | + AddMimeMapping(".prf", "application/pics-rules"); | |
| 184 | + AddMimeMapping(".pgm", "image/x-portable-graymap"); | |
| 185 | + AddMimeMapping(".qt", "video/quicktime"); | |
| 186 | + AddMimeMapping(".ra", "audio/x-pn-realaudio"); | |
| 187 | + AddMimeMapping(".rgb", "image/x-rgb"); | |
| 188 | + AddMimeMapping(".ram", "audio/x-pn-realaudio"); | |
| 189 | + AddMimeMapping(".rmi", "audio/mid"); | |
| 190 | + AddMimeMapping(".ras", "image/x-cmu-raster"); | |
| 191 | + AddMimeMapping(".roff", "application/x-troff"); | |
| 192 | + AddMimeMapping(".rtf", "application/rtf"); | |
| 193 | + AddMimeMapping(".rtx", "text/richtext"); | |
| 194 | + AddMimeMapping(".sv4crc", "application/x-sv4crc"); | |
| 195 | + AddMimeMapping(".spc", "application/x-pkcs7-certificates"); | |
| 196 | + AddMimeMapping(".setreg", "application/set-registration-initiation"); | |
| 197 | + AddMimeMapping(".snd", "audio/basic"); | |
| 198 | + AddMimeMapping(".stl", "application/vndms-pkistl"); | |
| 199 | + AddMimeMapping(".setpay", "application/set-payment-initiation"); | |
| 200 | + AddMimeMapping(".stm", "text/html"); | |
| 201 | + AddMimeMapping(".shar", "application/x-shar"); | |
| 202 | + AddMimeMapping(".sh", "application/x-sh"); | |
| 203 | + AddMimeMapping(".sit", "application/x-stuffit"); | |
| 204 | + AddMimeMapping(".spl", "application/futuresplash"); | |
| 205 | + AddMimeMapping(".sct", "text/scriptlet"); | |
| 206 | + AddMimeMapping(".scd", "application/x-msschedule"); | |
| 207 | + AddMimeMapping(".sst", "application/vndms-pkicertstore"); | |
| 208 | + AddMimeMapping(".src", "application/x-wais-source"); | |
| 209 | + AddMimeMapping(".sv4cpio", "application/x-sv4cpio"); | |
| 210 | + AddMimeMapping(".tex", "application/x-tex"); | |
| 211 | + AddMimeMapping(".tgz", "application/x-compressed"); | |
| 212 | + AddMimeMapping(".t", "application/x-troff"); | |
| 213 | + AddMimeMapping(".tar", "application/x-tar"); | |
| 214 | + AddMimeMapping(".tr", "application/x-troff"); | |
| 215 | + AddMimeMapping(".tif", "image/tiff"); | |
| 216 | + AddMimeMapping(".txt", "text/plain"); | |
| 217 | + AddMimeMapping(".texinfo", "application/x-texinfo"); | |
| 218 | + AddMimeMapping(".trm", "application/x-msterminal"); | |
| 219 | + AddMimeMapping(".tiff", "image/tiff"); | |
| 220 | + AddMimeMapping(".tcl", "application/x-tcl"); | |
| 221 | + AddMimeMapping(".texi", "application/x-texinfo"); | |
| 222 | + AddMimeMapping(".tsv", "text/tab-separated-values"); | |
| 223 | + AddMimeMapping(".ustar", "application/x-ustar"); | |
| 224 | + AddMimeMapping(".uls", "text/iuls"); | |
| 225 | + AddMimeMapping(".vcf", "text/x-vcard"); | |
| 226 | + AddMimeMapping(".wps", "application/vnd.ms-works"); | |
| 227 | + AddMimeMapping(".wav", "audio/wav"); | |
| 228 | + AddMimeMapping(".wrz", "x-world/x-vrml"); | |
| 229 | + AddMimeMapping(".wri", "application/x-mswrite"); | |
| 230 | + AddMimeMapping(".wks", "application/vnd.ms-works"); | |
| 231 | + AddMimeMapping(".wmf", "application/x-msmetafile"); | |
| 232 | + AddMimeMapping(".wcm", "application/vnd.ms-works"); | |
| 233 | + AddMimeMapping(".wrl", "x-world/x-vrml"); | |
| 234 | + AddMimeMapping(".wdb", "application/vnd.ms-works"); | |
| 235 | + AddMimeMapping(".wsdl", "text/xml"); | |
| 236 | + AddMimeMapping(".xap", "application/x-silverlight-app"); | |
| 237 | + AddMimeMapping(".xml", "text/xml"); | |
| 238 | + AddMimeMapping(".xlm", "application/vnd.ms-excel"); | |
| 239 | + AddMimeMapping(".xaf", "x-world/x-vrml"); | |
| 240 | + AddMimeMapping(".xla", "application/vnd.ms-excel"); | |
| 241 | + AddMimeMapping(".xls", "application/vnd.ms-excel"); | |
| 242 | + AddMimeMapping(".xlsx", "application/vnd.ms-excel"); | |
| 243 | + AddMimeMapping(".xof", "x-world/x-vrml"); | |
| 244 | + AddMimeMapping(".xlt", "application/vnd.ms-excel"); | |
| 245 | + AddMimeMapping(".xlc", "application/vnd.ms-excel"); | |
| 246 | + AddMimeMapping(".xsl", "text/xml"); | |
| 247 | + AddMimeMapping(".xbm", "image/x-xbitmap"); | |
| 248 | + AddMimeMapping(".xlw", "application/vnd.ms-excel"); | |
| 249 | + AddMimeMapping(".xpm", "image/x-xpixmap"); | |
| 250 | + AddMimeMapping(".xwd", "image/x-xwindowdump"); | |
| 251 | + AddMimeMapping(".xsd", "text/xml"); | |
| 252 | + AddMimeMapping(".z", "application/x-compress"); | |
| 253 | + AddMimeMapping(".zip", "application/x-zip-compressed"); | |
| 254 | + AddMimeMapping(".*", "application/octet-stream"); | |
| 255 | + } | |
| 256 | + } | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/RSAFileHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/RSAFileHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.IO; | |
| 4 | +using System.Linq; | |
| 5 | +using System.Security.Cryptography; | |
| 6 | +using System.Text; | |
| 7 | +using System.Threading.Tasks; | |
| 8 | + | |
| 9 | +namespace Yi.Framework.Core.Helper | |
| 10 | +{ | |
| 11 | + public class RSAFileHelper | |
| 12 | + { | |
| 13 | + public static RSA GetKey() | |
| 14 | + { | |
| 15 | + return GetRSA("key.pem"); | |
| 16 | + } | |
| 17 | + public static RSA GetPublicKey() | |
| 18 | + { | |
| 19 | + return GetRSA("public.pem"); | |
| 20 | + } | |
| 21 | + | |
| 22 | + private static RSA GetRSA(string fileName) | |
| 23 | + { | |
| 24 | + string rootPath = Directory.GetCurrentDirectory(); | |
| 25 | + string filePath = Path.Combine(rootPath, fileName); | |
| 26 | + if (!File.Exists(filePath)) | |
| 27 | + throw new Exception("文件不存在"); | |
| 28 | + string key = File.ReadAllText(filePath); | |
| 29 | + var rsa = RSA.Create(); | |
| 30 | + rsa.ImportFromPem(key.AsSpan()); | |
| 31 | + return rsa; | |
| 32 | + } | |
| 33 | + } | |
| 34 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/RSAHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/RSAHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.IO; | |
| 3 | +using System.Security.Cryptography; | |
| 4 | +using System.Text; | |
| 5 | + | |
| 6 | +namespace Yi.Framework.Core.Helper | |
| 7 | +{ | |
| 8 | + /// <summary> | |
| 9 | + /// RSA加解密 使用OpenSSL的公钥加密/私钥解密 | |
| 10 | + /// 公私钥请使用openssl生成 | |
| 11 | + /// </summary> | |
| 12 | + public class RSAHelper | |
| 13 | + { | |
| 14 | + public readonly RSA? _privateKeyRsaProvider; | |
| 15 | + public readonly RSA? _publicKeyRsaProvider; | |
| 16 | + private readonly HashAlgorithmName _hashAlgorithmName; | |
| 17 | + private readonly Encoding _encoding; | |
| 18 | + | |
| 19 | + /// <summary> | |
| 20 | + /// 实例化RSAHelper | |
| 21 | + /// </summary> | |
| 22 | + /// <param name="rsaType">加密算法类型 RSA SHA1;RSA2 SHA256 密钥长度至少为2048</param> | |
| 23 | + /// <param name="encoding">编码类型</param> | |
| 24 | + /// <param name="privateKey">私钥</param> | |
| 25 | + /// <param name="publicKey">公钥</param> | |
| 26 | + public RSAHelper(RSAType rsaType, Encoding encoding, string privateKey, string? publicKey = null) | |
| 27 | + { | |
| 28 | + _encoding = encoding; | |
| 29 | + if (!string.IsNullOrEmpty(privateKey)) | |
| 30 | + { | |
| 31 | + _privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey); | |
| 32 | + } | |
| 33 | + | |
| 34 | + if (!string.IsNullOrEmpty(publicKey)) | |
| 35 | + { | |
| 36 | + _publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey); | |
| 37 | + } | |
| 38 | + | |
| 39 | + _hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256; | |
| 40 | + } | |
| 41 | + | |
| 42 | + #region 使用私钥签名 | |
| 43 | + | |
| 44 | + /// <summary> | |
| 45 | + /// 使用私钥签名 | |
| 46 | + /// </summary> | |
| 47 | + /// <param name="data">原始数据</param> | |
| 48 | + /// <returns></returns> | |
| 49 | + public string Sign(string data) | |
| 50 | + { | |
| 51 | + byte[] dataBytes = _encoding.GetBytes(data); | |
| 52 | + | |
| 53 | + var signatureBytes = _privateKeyRsaProvider!.SignData(dataBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1); | |
| 54 | + | |
| 55 | + return Convert.ToBase64String(signatureBytes); | |
| 56 | + } | |
| 57 | + | |
| 58 | + #endregion | |
| 59 | + | |
| 60 | + #region 使用公钥验签 | |
| 61 | + | |
| 62 | + /// <summary> | |
| 63 | + /// 使用公钥验签 | |
| 64 | + /// </summary> | |
| 65 | + /// <param name="data">原始数据</param> | |
| 66 | + /// <param name="sign">签名</param> | |
| 67 | + /// <returns></returns> | |
| 68 | + public bool Verify(string data, string sign) | |
| 69 | + { | |
| 70 | + byte[] dataBytes = _encoding.GetBytes(data); | |
| 71 | + byte[] signBytes = Convert.FromBase64String(sign); | |
| 72 | + | |
| 73 | + var verify = _publicKeyRsaProvider!.VerifyData(dataBytes, signBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1); | |
| 74 | + | |
| 75 | + return verify; | |
| 76 | + } | |
| 77 | + | |
| 78 | + #endregion | |
| 79 | + | |
| 80 | + #region 解密 | |
| 81 | + /// <summary> | |
| 82 | + /// 私钥解密(原) | |
| 83 | + /// </summary> | |
| 84 | + /// <param name="cipherText">解密字符串(base64)</param> | |
| 85 | + /// <returns></returns> | |
| 86 | + | |
| 87 | + //public string Decrypt(string cipherText) | |
| 88 | + //{ | |
| 89 | + // if (_privateKeyRsaProvider == null) | |
| 90 | + // { | |
| 91 | + // throw new Exception("_privateKeyRsaProvider is null"); | |
| 92 | + // } | |
| 93 | + // return _encoding.GetString(_privateKeyRsaProvider.Decrypt(Convert.FromBase64String(cipherText), RSAEncryptionPadding.Pkcs1)); | |
| 94 | + //} | |
| 95 | + /// <summary> | |
| 96 | + /// 私钥解密(支持大量数据) | |
| 97 | + /// </summary> | |
| 98 | + /// <param name="cipherText"></param> | |
| 99 | + /// <returns></returns> | |
| 100 | + public string Decrypt(string cipherText) | |
| 101 | + { | |
| 102 | + if (_privateKeyRsaProvider == null) | |
| 103 | + { | |
| 104 | + throw new Exception("_privateKeyRsaProvider is null"); | |
| 105 | + } | |
| 106 | + var bufferSize = _privateKeyRsaProvider.KeySize / 8; | |
| 107 | + byte[] buffer = new byte[bufferSize];//待解密块 | |
| 108 | + using (MemoryStream msInput = new MemoryStream(Convert.FromBase64String(cipherText))) | |
| 109 | + { | |
| 110 | + using (MemoryStream msOutput = new MemoryStream()) | |
| 111 | + { | |
| 112 | + int readLen; while ((readLen = msInput.Read(buffer, 0, bufferSize)) > 0) | |
| 113 | + { | |
| 114 | + byte[] dataToEnc = new byte[readLen]; | |
| 115 | + Array.Copy(buffer, 0, dataToEnc, 0, readLen); byte[] encData = _privateKeyRsaProvider.Decrypt(dataToEnc, RSAEncryptionPadding.Pkcs1); | |
| 116 | + msOutput.Write(encData, 0, encData.Length); | |
| 117 | + } | |
| 118 | + byte[] result = msOutput.ToArray(); | |
| 119 | + return _encoding.GetString(result); | |
| 120 | + } | |
| 121 | + } | |
| 122 | + } | |
| 123 | + | |
| 124 | + #endregion | |
| 125 | + | |
| 126 | + #region 加密 | |
| 127 | + | |
| 128 | + /// <summary> | |
| 129 | + /// 公钥加密(原) | |
| 130 | + /// </summary> | |
| 131 | + /// <param name="text"></param> | |
| 132 | + /// <returns></returns> | |
| 133 | + //public string Encrypt(string text) | |
| 134 | + //{ | |
| 135 | + // if (_publicKeyRsaProvider == null) | |
| 136 | + // { | |
| 137 | + // throw new Exception("_publicKeyRsaProvider is null"); | |
| 138 | + // } | |
| 139 | + // return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.Pkcs1)); | |
| 140 | + //} | |
| 141 | + /// <summary> | |
| 142 | + /// 公钥加密(支持大量数据) | |
| 143 | + /// </summary> | |
| 144 | + /// <param name="text"></param> | |
| 145 | + /// <returns></returns> | |
| 146 | + public string Encrypt(string text) | |
| 147 | + { | |
| 148 | + if (_publicKeyRsaProvider == null) | |
| 149 | + { | |
| 150 | + throw new Exception("_publicKeyRsaProvider is null"); | |
| 151 | + } | |
| 152 | + var bufferSize = _publicKeyRsaProvider.KeySize / 8 - 11; | |
| 153 | + byte[] buffer = new byte[bufferSize];//待加密块 | |
| 154 | + | |
| 155 | + using (MemoryStream msInput = new MemoryStream(_encoding.GetBytes(text))) | |
| 156 | + { | |
| 157 | + using (MemoryStream msOutput = new MemoryStream()) | |
| 158 | + { | |
| 159 | + int readLen; while ((readLen = msInput.Read(buffer, 0, bufferSize)) > 0) | |
| 160 | + { | |
| 161 | + byte[] dataToEnc = new byte[readLen]; | |
| 162 | + Array.Copy(buffer, 0, dataToEnc, 0, readLen); byte[] encData = _publicKeyRsaProvider.Encrypt(dataToEnc, RSAEncryptionPadding.Pkcs1); | |
| 163 | + msOutput.Write(encData, 0, encData.Length); | |
| 164 | + } | |
| 165 | + byte[] result = msOutput.ToArray(); | |
| 166 | + return Convert.ToBase64String(result); | |
| 167 | + } | |
| 168 | + } | |
| 169 | + } | |
| 170 | + | |
| 171 | + #endregion | |
| 172 | + | |
| 173 | + #region 使用私钥创建RSA实例 | |
| 174 | + /// <summary> | |
| 175 | + /// 使用私钥创建RSA实例 | |
| 176 | + /// </summary> | |
| 177 | + /// <param name="privateKey"></param> | |
| 178 | + /// <returns></returns> | |
| 179 | + private RSA CreateRsaProviderFromPrivateKey(string privateKey) | |
| 180 | + { | |
| 181 | + var privateKeyBits = Convert.FromBase64String(privateKey); | |
| 182 | + | |
| 183 | + var rsa = RSA.Create(); | |
| 184 | + var rsaParameters = new RSAParameters(); | |
| 185 | + | |
| 186 | + using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits))) | |
| 187 | + { | |
| 188 | + byte bt = 0; | |
| 189 | + ushort twobytes = 0; | |
| 190 | + twobytes = binr.ReadUInt16(); | |
| 191 | + if (twobytes == 0x8130) | |
| 192 | + binr.ReadByte(); | |
| 193 | + else if (twobytes == 0x8230) | |
| 194 | + binr.ReadInt16(); | |
| 195 | + else | |
| 196 | + throw new Exception("Unexpected value read binr.ReadUInt16()"); | |
| 197 | + | |
| 198 | + twobytes = binr.ReadUInt16(); | |
| 199 | + if (twobytes != 0x0102) | |
| 200 | + throw new Exception("Unexpected version"); | |
| 201 | + | |
| 202 | + bt = binr.ReadByte(); | |
| 203 | + if (bt != 0x00) | |
| 204 | + throw new Exception("Unexpected value read binr.ReadByte()"); | |
| 205 | + | |
| 206 | + rsaParameters.Modulus = binr.ReadBytes(GetIntegerSize(binr)); | |
| 207 | + rsaParameters.Exponent = binr.ReadBytes(GetIntegerSize(binr)); | |
| 208 | + rsaParameters.D = binr.ReadBytes(GetIntegerSize(binr)); | |
| 209 | + rsaParameters.P = binr.ReadBytes(GetIntegerSize(binr)); | |
| 210 | + rsaParameters.Q = binr.ReadBytes(GetIntegerSize(binr)); | |
| 211 | + rsaParameters.DP = binr.ReadBytes(GetIntegerSize(binr)); | |
| 212 | + rsaParameters.DQ = binr.ReadBytes(GetIntegerSize(binr)); | |
| 213 | + rsaParameters.InverseQ = binr.ReadBytes(GetIntegerSize(binr)); | |
| 214 | + } | |
| 215 | + | |
| 216 | + rsa.ImportParameters(rsaParameters); | |
| 217 | + return rsa; | |
| 218 | + } | |
| 219 | + | |
| 220 | + #endregion | |
| 221 | + | |
| 222 | + #region 使用公钥创建RSA实例 | |
| 223 | + /// <summary> | |
| 224 | + /// 使用公钥创建RSA实例 | |
| 225 | + /// </summary> | |
| 226 | + /// <param name="publicKeyString"></param> | |
| 227 | + /// <returns></returns> | |
| 228 | + public RSA? CreateRsaProviderFromPublicKey(string publicKeyString) | |
| 229 | + { | |
| 230 | + // encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" | |
| 231 | + byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; | |
| 232 | + byte[] seq = new byte[15]; | |
| 233 | + | |
| 234 | + var x509Key = Convert.FromBase64String(publicKeyString); | |
| 235 | + | |
| 236 | + // --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ | |
| 237 | + using (MemoryStream mem = new MemoryStream(x509Key)) | |
| 238 | + { | |
| 239 | + using (BinaryReader binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading | |
| 240 | + { | |
| 241 | + byte bt = 0; | |
| 242 | + ushort twobytes = 0; | |
| 243 | + | |
| 244 | + twobytes = binr.ReadUInt16(); | |
| 245 | + if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
| 246 | + binr.ReadByte(); //advance 1 byte | |
| 247 | + else if (twobytes == 0x8230) | |
| 248 | + binr.ReadInt16(); //advance 2 bytes | |
| 249 | + else | |
| 250 | + return null; | |
| 251 | + | |
| 252 | + seq = binr.ReadBytes(15); //read the Sequence OID | |
| 253 | + if (!CompareBytearrays(seq, seqOid)) //make sure Sequence for OID is correct | |
| 254 | + return null; | |
| 255 | + | |
| 256 | + twobytes = binr.ReadUInt16(); | |
| 257 | + if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81) | |
| 258 | + binr.ReadByte(); //advance 1 byte | |
| 259 | + else if (twobytes == 0x8203) | |
| 260 | + binr.ReadInt16(); //advance 2 bytes | |
| 261 | + else | |
| 262 | + return null; | |
| 263 | + | |
| 264 | + bt = binr.ReadByte(); | |
| 265 | + if (bt != 0x00) //expect null byte next | |
| 266 | + return null; | |
| 267 | + | |
| 268 | + twobytes = binr.ReadUInt16(); | |
| 269 | + if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
| 270 | + binr.ReadByte(); //advance 1 byte | |
| 271 | + else if (twobytes == 0x8230) | |
| 272 | + binr.ReadInt16(); //advance 2 bytes | |
| 273 | + else | |
| 274 | + return null; | |
| 275 | + | |
| 276 | + twobytes = binr.ReadUInt16(); | |
| 277 | + byte lowbyte = 0x00; | |
| 278 | + byte highbyte = 0x00; | |
| 279 | + | |
| 280 | + if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) | |
| 281 | + lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus | |
| 282 | + else if (twobytes == 0x8202) | |
| 283 | + { | |
| 284 | + highbyte = binr.ReadByte(); //advance 2 bytes | |
| 285 | + lowbyte = binr.ReadByte(); | |
| 286 | + } | |
| 287 | + else | |
| 288 | + return null; | |
| 289 | + byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order | |
| 290 | + int modsize = BitConverter.ToInt32(modint, 0); | |
| 291 | + | |
| 292 | + int firstbyte = binr.PeekChar(); | |
| 293 | + if (firstbyte == 0x00) | |
| 294 | + { //if first byte (highest order) of modulus is zero, don't include it | |
| 295 | + binr.ReadByte(); //skip this null byte | |
| 296 | + modsize -= 1; //reduce modulus buffer size by 1 | |
| 297 | + } | |
| 298 | + | |
| 299 | + byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes | |
| 300 | + | |
| 301 | + if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data | |
| 302 | + return null; | |
| 303 | + int expbytes = binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values) | |
| 304 | + byte[] exponent = binr.ReadBytes(expbytes); | |
| 305 | + | |
| 306 | + // ------- create RSACryptoServiceProvider instance and initialize with public key ----- | |
| 307 | + var rsa = RSA.Create(); | |
| 308 | + RSAParameters rsaKeyInfo = new RSAParameters | |
| 309 | + { | |
| 310 | + Modulus = modulus, | |
| 311 | + Exponent = exponent | |
| 312 | + }; | |
| 313 | + rsa.ImportParameters(rsaKeyInfo); | |
| 314 | + | |
| 315 | + return rsa; | |
| 316 | + } | |
| 317 | + | |
| 318 | + } | |
| 319 | + } | |
| 320 | + | |
| 321 | + #endregion | |
| 322 | + | |
| 323 | + #region 导入密钥算法 | |
| 324 | + | |
| 325 | + private int GetIntegerSize(BinaryReader binr) | |
| 326 | + { | |
| 327 | + byte bt = 0; | |
| 328 | + int count = 0; | |
| 329 | + bt = binr.ReadByte(); | |
| 330 | + if (bt != 0x02) | |
| 331 | + return 0; | |
| 332 | + bt = binr.ReadByte(); | |
| 333 | + | |
| 334 | + if (bt == 0x81) | |
| 335 | + count = binr.ReadByte(); | |
| 336 | + else | |
| 337 | + if (bt == 0x82) | |
| 338 | + { | |
| 339 | + var highbyte = binr.ReadByte(); | |
| 340 | + var lowbyte = binr.ReadByte(); | |
| 341 | + byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; | |
| 342 | + count = BitConverter.ToInt32(modint, 0); | |
| 343 | + } | |
| 344 | + else | |
| 345 | + { | |
| 346 | + count = bt; | |
| 347 | + } | |
| 348 | + | |
| 349 | + while (binr.ReadByte() == 0x00) | |
| 350 | + { | |
| 351 | + count -= 1; | |
| 352 | + } | |
| 353 | + binr.BaseStream.Seek(-1, SeekOrigin.Current); | |
| 354 | + return count; | |
| 355 | + } | |
| 356 | + | |
| 357 | + private bool CompareBytearrays(byte[] a, byte[] b) | |
| 358 | + { | |
| 359 | + if (a.Length != b.Length) | |
| 360 | + return false; | |
| 361 | + int i = 0; | |
| 362 | + foreach (byte c in a) | |
| 363 | + { | |
| 364 | + if (c != b[i]) | |
| 365 | + return false; | |
| 366 | + i++; | |
| 367 | + } | |
| 368 | + return true; | |
| 369 | + } | |
| 370 | + | |
| 371 | + #endregion | |
| 372 | + | |
| 373 | + } | |
| 374 | + | |
| 375 | + /// <summary> | |
| 376 | + /// RSA算法类型 | |
| 377 | + /// </summary> | |
| 378 | + public enum RSAType | |
| 379 | + { | |
| 380 | + /// <summary> | |
| 381 | + /// SHA1 | |
| 382 | + /// </summary> | |
| 383 | + RSA = 0, | |
| 384 | + /// <summary> | |
| 385 | + /// RSA2 密钥长度至少为2048 | |
| 386 | + /// SHA256 | |
| 387 | + /// </summary> | |
| 388 | + RSA2 | |
| 389 | + } | |
| 390 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/RandomHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/RandomHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Text; | |
| 4 | +using System.Text.RegularExpressions; | |
| 5 | + | |
| 6 | +namespace Yi.Framework.Core.Helper | |
| 7 | +{ | |
| 8 | + public class RandomHelper | |
| 9 | + { | |
| 10 | + public static string replaceBianLiang(string content) | |
| 11 | + { | |
| 12 | + content = content.Replace("{当前时间}", DateTime.Now.TimeOfDay.ToString()); | |
| 13 | + string[] bianliang = new string[] { "{随机字母}", "{随机数字}", "{随机汉字}" }; | |
| 14 | + Regex r; | |
| 15 | + int count; | |
| 16 | + string readstr = ""; | |
| 17 | + foreach (string str in bianliang) | |
| 18 | + { | |
| 19 | + count = (content.Length - content.Replace(str, "").Length) / str.Length; | |
| 20 | + if (str == "{随机汉字}") readstr = RandChina(count); | |
| 21 | + if (str == "{随机数字}") readstr = GenerateCheckCodeNum(count); | |
| 22 | + if (str == "{随机字母}") readstr = GenerateRandomLetter(count); | |
| 23 | + if (count > readstr.Length) count = readstr.Length; | |
| 24 | + r = new Regex(str.Replace("{", "\\{").Replace("}", "\\}")); | |
| 25 | + for (int i = 0; i < count; i++) | |
| 26 | + { | |
| 27 | + content = r.Replace(content, readstr.Substring(i, 1), 1); | |
| 28 | + } | |
| 29 | + } | |
| 30 | + return content; | |
| 31 | + } | |
| 32 | + | |
| 33 | + | |
| 34 | + /// <summary> | |
| 35 | + /// 随机生成字母 | |
| 36 | + /// </summary> | |
| 37 | + /// <param name="Length"></param> | |
| 38 | + /// <returns></returns> | |
| 39 | + public static string GenerateRandomLetter(int Length) | |
| 40 | + { | |
| 41 | + char[] Pattern = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; | |
| 42 | + string result = ""; | |
| 43 | + int n = Pattern.Length; | |
| 44 | + Random random = new Random(~unchecked((int)DateTime.Now.Ticks)); | |
| 45 | + for (int i = 0; i < Length; i++) | |
| 46 | + { | |
| 47 | + int rnd = random.Next(0, n); | |
| 48 | + result += Pattern[rnd]; | |
| 49 | + } | |
| 50 | + return result; | |
| 51 | + } | |
| 52 | + | |
| 53 | + /// <summary> | |
| 54 | + /// 随机生成数字 | |
| 55 | + /// </summary> | |
| 56 | + /// <param name="codeCount"></param> | |
| 57 | + /// <returns></returns> | |
| 58 | + public static string GenerateCheckCodeNum(int codeCount) | |
| 59 | + { | |
| 60 | + int rep = 0; | |
| 61 | + string str = string.Empty; | |
| 62 | + long num2 = DateTime.Now.Ticks + rep; | |
| 63 | + rep++; | |
| 64 | + Random random = new Random((int)((ulong)num2 & 0xffffffffL) | (int)(num2 >> rep)); | |
| 65 | + for (int i = 0; i < codeCount; i++) | |
| 66 | + { | |
| 67 | + int num = random.Next(); | |
| 68 | + str = str + ((char)(0x30 + (ushort)(num % 10))).ToString(); | |
| 69 | + } | |
| 70 | + return str; | |
| 71 | + } | |
| 72 | + | |
| 73 | + /// <summary> | |
| 74 | + /// 此函数为生成指定数目的汉字 | |
| 75 | + /// </summary> | |
| 76 | + /// <param name="charLen">汉字数目</param> | |
| 77 | + /// <returns>所有汉字</returns> | |
| 78 | + public static string RandChina(int charLen) | |
| 79 | + { | |
| 80 | + int area, code;//汉字由区位和码位组成(都为0-94,其中区位16-55为一级汉字区,56-87为二级汉字区,1-9为特殊字符区) | |
| 81 | + StringBuilder strtem = new StringBuilder(); | |
| 82 | + Random rand = new Random(); | |
| 83 | + for (int i = 0; i < charLen; i++) | |
| 84 | + { | |
| 85 | + area = rand.Next(16, 88); | |
| 86 | + if (area == 55)//第55区只有89个字符 | |
| 87 | + { | |
| 88 | + code = rand.Next(1, 90); | |
| 89 | + } | |
| 90 | + else | |
| 91 | + { | |
| 92 | + code = rand.Next(1, 94); | |
| 93 | + } | |
| 94 | + strtem.Append(Encoding.GetEncoding("GB2312").GetString(new byte[] { Convert.ToByte(area + 160), Convert.ToByte(code + 160) })); | |
| 95 | + } | |
| 96 | + return strtem.ToString(); | |
| 97 | + } | |
| 98 | + } | |
| 99 | +} | ... | ... |
Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ReflexHelper.cs
0 → 100644
| 1 | +++ a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/ReflexHelper.cs | |
| 1 | +using System; | |
| 2 | +using System.Collections.Generic; | |
| 3 | +using System.Linq; | |
| 4 | +using System.Text; | |
| 5 | +using System.Threading.Tasks; | |
| 6 | + | |
| 7 | +namespace Yi.Framework.Core.Helper | |
| 8 | +{ | |
| 9 | + public static class ReflexHelper | |
| 10 | + { | |
| 11 | + | |
| 12 | + #region 对象相关 | |
| 13 | + /// <summary> | |
| 14 | + /// 取对象属性值 | |
| 15 | + /// </summary> | |
| 16 | + /// <param name="FieldName"></param> | |
| 17 | + /// <param name="obj"></param> | |
| 18 | + /// <returns></returns> | |
| 19 | + public static string GetModelValue(string FieldName, object obj) | |
| 20 | + { | |
| 21 | + try | |
| 22 | + { | |
| 23 | + Type Ts = obj.GetType(); | |
| 24 | + object o = Ts.GetProperty(FieldName).GetValue(obj, null); | |
| 25 | + if (null == o) | |
| 26 | + return null; | |
| 27 | + string Value = Convert.ToString(o); | |
| 28 | + if (string.IsNullOrEmpty(Value)) | |
| 29 | + return null; | |
| 30 | + return Value; | |
| 31 | + } | |
| 32 | + catch (Exception ex) | |
| 33 | + { | |
| 34 | + throw ex; | |
| 35 | + } | |
| 36 | + return null; | |
| 37 | + } | |
| 38 | + | |
| 39 | + | |
| 40 | + /// <summary> | |
| 41 | + /// 设置对象属性值 | |
| 42 | + /// </summary> | |
| 43 | + /// <param name="FieldName"></param> | |
| 44 | + /// <param name="Value"></param> | |
| 45 | + /// <param name="obj"></param> | |
| 46 | + /// <returns></returns> | |
| 47 | + public static bool SetModelValue(string FieldName, object Value, object obj) | |
| 48 | + { | |
| 49 | + try | |
| 50 | + { | |
| 51 | + Type Ts = obj.GetType(); | |
| 52 | + Ts.GetProperty(FieldName).SetValue(obj, Value, null); | |
| 53 | + return true; | |
| 54 | + } | |
| 55 | + catch (Exception ex) | |
| 56 | + { | |
| 57 | + throw ex; | |
| 58 | + } | |
| 59 | + return false; | |
| 60 | + } | |
| 61 | + #endregion | |
| 62 | + } | |
| 63 | +} | ... | ... |