Compare commits

..

1 Commits

Author SHA1 Message Date
陈淳
d919e07096 fix: 修复大小写问题 2023-02-20 19:57:13 +08:00
1965 changed files with 58746 additions and 65448 deletions

139
.gitignore vendored
View File

@@ -1,7 +1,20 @@
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons. ## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
WebFirst/SoEasyPlatform.exe
WebFirst/excel
WebFirst/wwwroot
WebFirst/SoEasyPlatform.exe
WebFirst/appsettings.Development.json
WebFirst/appsettings.json
WebFirst/SoEasyPlatform.pdb
WebFirst/SoEasyPlatform.Views.pdb
WebFirst/web.config
WebFirst/WebFirst.exe
# User-specific files # User-specific files
*.rsuser
*.suo *.suo
*.user *.user
*.userosscache *.userosscache
@@ -17,16 +30,21 @@
[Rr]eleases/ [Rr]eleases/
x64/ x64/
x86/ x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/ bld/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
[Ll]og/ [Ll]og/
# Visual Studio 2015 cache/options directory # Visual Studio 2015/2017 cache/options directory
.vs/ .vs/
# Uncomment if you have tasks that create the project's static files in wwwroot # Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/ #wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results # MSTest test Results
[Tt]est[Rr]esult*/ [Tt]est[Rr]esult*/
[Bb]uild[Ll]og.* [Bb]uild[Ll]og.*
@@ -40,18 +58,28 @@ TestResult.xml
[Rr]eleasePS/ [Rr]eleasePS/
dlldata.c dlldata.c
# DNX # Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json project.lock.json
project.fragment.lock.json
artifacts/ artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c *_i.c
*_p.c *_p.c
*_i.h *_h.h
*.ilk *.ilk
*.meta *.meta
*.obj *.obj
*.iobj
*.pch *.pch
*.pdb *.pdb
*.ipdb
*.pgc *.pgc
*.pgd *.pgd
*.rsp *.rsp
@@ -61,6 +89,7 @@ artifacts/
*.tlh *.tlh
*.tmp *.tmp
*.tmp_proj *.tmp_proj
*_wpftmp.csproj
*.log *.log
*.vspscc *.vspscc
*.vssscc *.vssscc
@@ -89,6 +118,9 @@ ipch/
*.vspx *.vspx
*.sap *.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace # TFS 2012 Local Workspace
$tf/ $tf/
@@ -109,6 +141,14 @@ _TeamCity*
# DotCover is a Code Coverage Tool # DotCover is a Code Coverage Tool
*.dotCover *.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch # NCrunch
_NCrunch_* _NCrunch_*
.*crunch*.local.xml .*crunch*.local.xml
@@ -140,7 +180,7 @@ publish/
# Publish Web Output # Publish Web Output
*.[Pp]ublish.xml *.[Pp]ublish.xml
*.azurePubxml *.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings # Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted # but database connection strings (with potential passwords) will be unencrypted
*.pubxml *.pubxml
*.publishproj *.publishproj
@@ -153,12 +193,12 @@ PublishScripts/
# NuGet Packages # NuGet Packages
*.nupkg *.nupkg
# The packages folder can be ignored because of Package Restore # The packages folder can be ignored because of Package Restore
**/packages/* **/[Pp]ackages/*
# except build/, which is used as an MSBuild target. # except build/, which is used as an MSBuild target.
!**/packages/build/ !**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed # Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config #!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignoreable files # NuGet v3's project.json files produces more ignorable files
*.nuget.props *.nuget.props
*.nuget.targets *.nuget.targets
@@ -175,12 +215,13 @@ AppPackages/
BundleArtifacts/ BundleArtifacts/
Package.StoreAssociation.xml Package.StoreAssociation.xml
_pkginfo.txt _pkginfo.txt
*.appx
# Visual Studio cache files # Visual Studio cache files
# files ending in .cache can be ignored # files ending in .cache can be ignored
*.[Cc]ache *.[Cc]ache
# but keep track of directories ending in .cache # but keep track of directories ending in .cache
!*.[Cc]ache/ !?*.[Cc]ache/
# Others # Others
ClientBin/ ClientBin/
@@ -188,11 +229,15 @@ ClientBin/
*~ *~
*.dbmdl *.dbmdl
*.dbproj.schemaview *.dbproj.schemaview
*.jfm
*.pfx *.pfx
*.publishsettings *.publishsettings
node_modules/
orleans.codegen.cs orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components # Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/ #bower_components/
@@ -207,15 +252,20 @@ _UpgradeReport_Files/
Backup*/ Backup*/
UpgradeLog*.XML UpgradeLog*.XML
UpgradeLog*.htm UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files # SQL Server files
*.mdf *.mdf
*.ldf *.ldf
*.ndf
# Business Intelligence projects # Business Intelligence projects
*.rdl.data *.rdl.data
*.bim.layout *.bim.layout
*.bim_*.settings *.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl
# Microsoft Fakes # Microsoft Fakes
FakesAssemblies/ FakesAssemblies/
@@ -225,6 +275,7 @@ FakesAssemblies/
# Node.js Tools for Visual Studio # Node.js Tools for Visual Studio
.ntvs_analysis.dat .ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log # Visual Studio 6 build log
*.plg *.plg
@@ -232,6 +283,9 @@ FakesAssemblies/
# Visual Studio 6 workspace options file # Visual Studio 6 workspace options file
*.opt *.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output # Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts **/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts
@@ -251,25 +305,48 @@ paket-files/
.idea/ .idea/
*.sln.iml *.sln.iml
# BookStore # CodeRush personal settings
src/Acme.BookStore.Web/Logs/* .cr/personal
src/Acme.BookStore.Web.Host/Logs/*
src/Acme.BookStore.AuthServer/Logs/*
src/Acme.BookStore.HttpApi.Host/Logs/*
src/Acme.BookStore.HttpApi.HostWithIds/Logs/*
src/Acme.BookStore.DbMigrator/Logs/*
src/Acme.BookStore.Blazor.Server/Logs/*
src/Acme.BookStore.Blazor.Server.Tiered/Logs/*
# Use abp install-libs to restore. # Python Tools for Visual Studio (PTVS)
**/wwwroot/libs/* __pycache__/
dist *.pyc
.vscode
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Development.json # Cake - Uncomment if you are using it
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Production.json # tools/**
Logs # !tools/packages.config
logs
/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Development.json # Tabs Studio
/Yi.Abp.Net8/test/Yi.Abp.Test/appsettings.Production.json *.tss
database_backup
/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Staging.json # Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
appsettings.Development.json

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 橙子 Copyright (c) 2022 jacktang
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

387
README.md
View File

@@ -1,144 +1,100 @@
<h1 align="center"><img align="left" height="150px" src="https://ccnetcore.com/prod-api/wwwroot/logo.png"> Yi框架</h1>
<h4 align="center">一套以用户体验出发的.Net8 Web开源框架</h4>
<h5 align="center">支持Abp.vNext 版本原生版本、Furion版本前端后台接入Ruoyi Vue3.0</h5> <h1 align="center"><img align="left" height="100px" src="https://user-images.githubusercontent.com/68722157/138828506-f58b7c57-5e10-4178-8f7d-5d5e12050113.png"> Yi框架</h1>
<h4 align="center">一套与SqlSugar一样爽的.Net6开源框架</h4>
<h2 align="center">集大成者,终究轮子</h2> <h2 align="center">集大成者,终究轮子</h2>
[![star](https://gitee.com/ccnetcore/yi/badge/star.svg?theme=dark)](https://gitee.com/ccnetcore/Yi)
[![fork](https://gitee.com/ccnetcore/yi/badge/fork.svg?theme=dark)](https://gitee.com/ccnetcore/Yi)
[![license](https://img.shields.io/badge/license-MIT-yellow)](https://gitee.com/ccnetcore/Yi)
[English](README-en.md) | 简体中文 [English](README-en.md) | 简体中文
![sdk](https://img.shields.io/badge/sdk-6.0.1-d.svg)![License MIT](https://img.shields.io/badge/license-Apache-blue.svg?style=flat-square)
**** ****
## :tw-1f34e: 简介: ### 简介:
YiFramework是一个基于.Net8+Abp.vNext+SqlSugar的DDD领域驱动设计后端开源框架
谁说Abp复杂谁说DDD难`打破常规,化繁为简`,新人入门,项目二开,最佳方式之一
**中文:意框架**和他的名字一样“简易”同时接入Java的Ruoyi Vue3.0前端) **中文:意框架**和他的名字一样“简易”同时接入Java的Ruoyi Vue3.0前端)
模块,可根据业务自行引用或抛弃,集大成者,大而全乎,也许你能从中学习到一些独特见解 模块分化较多,可根据业务自行引用或抛弃,集大成者,大而全乎,也许你能从中学习到一些独特见解
正在持续更进业务模块已接入ruoyi
**英文YiFramework** **英文YiFramework**
Yi框架-一套与SqlSugar一样爽的.Net8开源框架。 Yi框架-一套与SqlSugar一样爽的.Net6低代码开源框架。
与Sqlsugar理念一致以用户体验出发。 与Sqlsugar理念一致以用户体验出发。
适合.Net8学习、Sqlsugar学习 、项目二次开发。 架构干净整洁、无业务代码、采用微软风格原生框架封装、CodeFrist+配套自研文件模板代码生成器 开发。
适合.Net6学习、Sqlsugar学习 、项目二次开发。
集大成者,终究轮子 集大成者,终究轮子
更新频繁可watching持续关注。 Yi框架最新版本标签`v1.2.1`,具体版本可以查看标签迭代
项目与Sqlsugar同步更新但这作者老杰哥代码天天爆肝到凌晨两点我们也尽量会跟上他的脚步。更新频繁所以可watching持续关注。
————这不仅仅是一个程序,更是一个艺术品,面向艺术的开发! ————这不仅仅是一个程序,更是一个艺术品,面向艺术的开发!
> 核心特点简单好用框架不以打包形式引用而是直接以项目附带源码给出自由度拉满遵循Mit协议允许随意修改请注明来源即可 **分支**
**分支:** 本项目由EFCore版本历经3年不断迭代至Sqlsugar版本现EFcore版本已弃用目前sqlsugar已带业务功能
- (推荐) **Abp**: 基于Abp.vNext分支DDD领域驱动设计,回归开发本质,极度简单,用起来贼爽 **SqlSugar**:.Net6 DDD领域驱动设计 简单分层微服务架构
- **Furion**: 基于Furion分支 - Yi.Framework.Net6.NetCore 6 意框架 (后端)
- Yi.Vue3.X.RuoYiVue3 RuoYi前端框架 (前端后台)
你没有听错已经接入java流行指数最高最火爆的框架之一与其他框架不同Yi框架后端为完全重制版并非为ruoyi java模仿版
- Yi.Vue3.x.VantVue3 移动端前端框架 (前端前台)持续迭代
**SqlSugar-Dev**为sqlsugar分支的实时开发版本
~~**ec**: EFcore完整电商项目~~
**** ****
## :tw-1f350: 官网及演示地址: ### 演示地址:
废话少说直接上地址 废话少说直接上地址**请不要**更改里面的数据
Yi社区官网网址[ccnetcore.com](https://ccnetcore.com) (已上线,欢迎加入) API服务[yi.ccnetcore.com](http://yi.ccnetcore.com) 管理员账号cc 、 123456
Rbac后台管理系统已上线暂不提供演示地址可本地部署访问 网关地址:~~[gate.ccnetcore.com/swagger](http://gate.ccnetcore.com/swagger)~~
App移动端系统已上线暂不提供演示地址可本地部署访问 ~~WebFirst开发所有代码生成器已经配置完成无需任何操作数据库及任何代码只需要网页表格上点点点即可~~
Rbac演示地址https://ccnetcore.com:1000 用户cc、密码123456 代码自动生成:
![代码生成](Readme/%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90.gif)
## :tw-1f351: 支持: ### 支持:
- [x] 完全支持单体应用架构 - [x] 完全支持单体应用架构
- [x] 完全支持分布式应用架构 - [x] 完全支持分布式应用架构
- [x] 完全支持微服务架构 - [x] 完全支持微服务架构
- [ ] 即将支持网格服务架构我们将在后续版本加入dapr
**** ****
## :tw-1f352: 详细到爆炸的Yi框架教程导航 ### 软件架构:
1. [框架快速开始教程](https://ccnetcore.com/article/aaa00329-7f35-d3fe-d258-3a0f8380b742)(已完成) **架构**:后端.NET6(Asp.NetCore 6)、WebFirst代码生成器~~与.NET5(Asp.NetCore 5)、前端Vue2.0~~
2. [框架功能模块教程](https://ccnetcore.com/article/8c464ab3-8ba5-2761-a4b0-3a0f83a9f312)(已完成)
3. [实战演练开发教程](https://ccnetcore.com/article/e89c9593-f337-ada7-d108-3a0f83ae48e6) **关系型数据库**mysql、sql server、sqlite、oracle(正在兼容中)
4. [橙子运维CICD教程](https://ccnetcore.com/article/6b80ed42-50cd-db15-c073-3a0fa8f7fd77)(已完成)
5. [版本更新日志](https://ccnetcore.com/article/e9e69a38-ce1e-06f5-7944-3a0fdc942ef3)(已完成) **操作系统**Windows、Linux
**身份验证**JWT、IdentityServer4
**组件**SqlSugar、Autofac、Castle、Swagger、Log4Net、Redis、RabbitMq、ES、Quartz.net、~~T4~~
**分布式**CAP、Lock
**微服务**Consul、Ocelot、IdentityService、Apollo、Docker、Jenkins、Nginx、K8s、ELK、Polly
**封装**Json处理模块滑动验证码模块base64图片处理模块异常捕捉模块、邮件处理模块、linq封装模块、随机数模块、统一接口模块、基于策略的jwt验证、过滤器、数据库连接、跨域、初始化种子数据、Base32、Console输出、日期处理、文件传输、html筛选、http请求、ip过滤、md5加密、Rsa加密、序列化、雪花算法、字符串处理、编码处理、地址处理、xml处理、心跳检查。。。
**** ****
## :tw-1f353: 它的理念: <h3>业务支持模块</h3>
谁说Abp复杂谁说DDD难打破常规化繁为简新人入门项目二开最佳方式之一
> 一百个人就有一百种DDDYi框架不一定是极度严格的DDD而是站在巨人的肩膀上经过极多项目的提炼摸索出一种最佳实践 RABC权限管理系统正在更新
大部分ruoyi功能采用ruoyi前端
优雅的进行快速开发通常简单程度与优雅程度不可兼得Yi框架并不一昧的追求极致的解耦会站在用户使用角度上在使用难易度进行考虑衡量
> 一个面向用户的快速开发后端框架
在真正的使用这,你会明白这一点,极致的简单,也是优雅的一种体现。
****
## :tw-1f354: 特点
- 面向用户的后端框架,使用简单,适合小型、中型、企业级项目
- 项目直接内置源码,不打包,非常适合进行二开改造
- 内置包含大量通用场景模块
- 优雅支持分布式及微服务架构
- 等等
## :tw-1f340: 基础设施简介
以下全部功能可直接使用:
- [Abp.vNext官网](https://docs.abp.io/zh-Hans/abp/latest/)
- [SqlSugar官网](https://www.donet5.com/home/doc)
## :tw-1f341: 内置模块简介
- Rbac权限管理系统已上线
- Bbs论坛社区系统已上线
> 重复的东西,无需再写一遍,这也是优雅的体现之一
****
## :tw-1f31e: 核心技术
#### 后端
C# Asp.NetCore 8.0
- [x] 动态ApiAbp.vNext
- [x] 鉴权授权Jwt
- [x] 日志Serilog
- [x] 模块化Abp.vNext
- [x] 依赖注入Autofac
- [x] 对象映射Mapster
- [x] ORM: SqlsugarCore
- [x] 多租户Abp.vNext
- [x] 后台任务Quartz.Net
- [x] 本地缓存Abp.vNext
- [x] 分布式缓存Abp.vNext
- [x] 事件总线Abp.vNext
#### 前端
js Vue3.2
- [x] 异步请求axios
- [x] 图表echarts
- [x] uielement-plus
- [x] 存储pinia
- [x] 路由vue-router
- [x] 打包vite
#### 运维
- [x] 部署nginx
- [x] CICDgitlab+Jenkins
- [x] Dockerharbor
****
## :tw-1f366: 业务支持模块:
#### :tw-1f42f: RABC权限管理系统持续更新
采用ruoyi前端
- 用户管理 - 用户管理
- 角色管理 - 角色管理
- 菜单管理 - 菜单管理
@@ -149,100 +105,177 @@ js Vue3.2
- 用户在线 - 用户在线
- 操作日志 - 操作日志
- 登录日志 - 登录日志
- 定时任务 - 等等
- 缓存列表
- 服务监控
- WebFirst代码生成工具
#### :tw-1f431: BBS社区论坛系统(持续更新) ERP进销存系统(正在更新)
采用vue3前端 - 供货商管理
- 文章功能 - 等等
- 板块功能
- 主题功能
- 个人中心
- 授权中心
- 权限管理
#### :star: 演示截图: BBS论坛系统持续迭代
<table> - 文章管理
<tr> - 评论管理
<td><img src="readme/101.png"/></td> - 等等
<td><img src="readme/102.png"/></td>
</tr>
<tr>
<td><img src="readme/103.png"/></td>
<td><img src="readme/104.png"/></td>
</tr>
</table>
<table>
<tr>
<td><img src="readme/1.png"/></td>
<td><img src="readme/2.png"/></td>
</tr>
<tr>
<td><img src="readme/3.png"/></td>
<td><img src="readme/4.png"/></td>
</tr>
<tr>
<td><img src="readme/3.png"/></td>
<td><img src="readme/4.png"/></td>
</tr>
<tr>
<td><img src="readme/5.png"/></td>
<td><img src="readme/6.png"/></td>
</tr>
<tr>
<td><img src="readme/7.png"/></td>
<td><img src="readme/8.png"/></td>
</tr>
<tr>
<td><img src="readme/9.png"/></td>
<td><img src="readme/10.png"/></td>
</tr>
<tr>
<td><img src="readme/11.png"/></td>
<td><img src="readme/12.png"/></td>
</tr>
</table>
## :tw-1f44f: 感谢: SHOP电商系统持续迭代
- SPU管理
- SKU管理
- 商品规格
- 商品分类
- 等等
![输入图片说明](Readme/%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86.png)
![输入图片说明](Readme/%E8%8F%9C%E5%8D%95%E7%AE%A1%E7%90%86.png)
### 框架支持模块:
大致如图:
![image](https://user-images.githubusercontent.com/68722157/142923071-2fa524eb-e833-4143-a926-51566e56e889.png)
![image](https://user-images.githubusercontent.com/68722157/142923150-ebe1b538-c3fc-42dd-bea8-83e10e0f819a.png)
![image](https://user-images.githubusercontent.com/68722157/142923529-e4fbb2f6-def1-4702-b9da-5adbd22f0a2f.png)
(删除线代表已实现功能还未迁移过来)
- [x] 支持大致`DDD领域驱动设计`进行分层,支持微服务扩展
- [x] 支持采用`异步`开发awit/async
- [x] 支持数据库主从`读写分离`
- [x] 支持功能替换,无需改动代码,只需配置`json文件`进行装配即可
- [x] 支持`Aop封装`FilterAop、IocAop、LogAop、SqlAop
- [x] 支持`Log4Net日志`记录自动生成至bin目录下的logs文件夹
- [x] 支持`DbSeed数据库种子数据`接入
- [x] 支持主流`数据库随意切换`Mysql/Sqlite/Sqlserver/Oracle
- [x] 支持上海杰哥官方`SqlSugar ORM`封装
- [x] 支持新版`SwaggerWebAPI`jwt身份认证接入
- [x] 支持`Cors`跨域
- [x] 支持`AutoFac`自动映射依赖注入
- [x] 支持`consul`服务器注册与发现
- [x] 支持`健康检查`
- [x] 支持`RabbitMQ`消息队列
- [x] 支持`Redis`多级缓存
- [x] 支持`MemoryCache`多级缓存
- [x] 支持`Ocelot`网关路由、服务聚合、服务发现、认证、鉴权、限流、熔断、缓存、Header头传递
- [x] 支持`Apollo`全局配置中心;
- [x] 支持`docker`镜像制作
- [x] 支持`Quartz.net`任务调度,实现任意接口被调度
- [x] 支持`ThumbnailSharp`缩略图封装
- [x] 支持`ELK`log4net+kafka+es+logstach+kibana
- [x] 支持`IdentityService4`授权中心
- [x] 支持`Es`分词查询
- [x] 支持多级`缓存`
- [x] 支持`CAP`分布式事务mysql+rabbitMq
- [x] 支持`Docker+k8s`部署
- [x] 支持`Jenkins+CI/CD`
- [x] 支持`AutoMapper`模块映射
- [x] 支持`微信支付`模块
- [x] 支持`单表多租户`常用功能
- [x] 支持`逻辑删除`常用功能
- [x] 支持`操作日志`常用功能
- [x] 支持`自动分表`
- [x] 支持`数据权限`
- [x] 支持`CodeFrist`快速构建数据库
- [x] 支持自研文件版`代码生成器`快速构建通用代码
- [x] 支持完整`Dto`模式
- [x] 支持 太多了忘了
****
### 目录结构:
![image](https://s1.ax1x.com/2022/04/09/LCTleH.png)
![image](https://s1.ax1x.com/2022/04/24/L4qlSs.png)
![image](https://s1.ax1x.com/2022/04/24/L4q1ln.png)
我们大致依照DDD领域驱动设计分层
分层如此清晰什么还感觉太复杂了用户只需关注Api、Service其他都是轮子啊
- BackGround后台进程通常使用消息队列进行消费任务
- Test测试单元测试
- Domain领域层Dto、服务接口层、模型层、仓储层、服务层
- Infrastructure基础实例层(通用工具层、核心层、定时任务Job、国际化、Web扩展层)
- Module模块层其他模块可按需进行引入例如微信支付、代码生成
- MicroServiceInstance服务层微服务
****
### 安装教程:
我们将在之后更新教程手册!
后端
1. 下载全部源码默认使用sqlite数据库已经生成
2. 直接点击sln文件运行即可没有任何其他依赖
前端
1. 下载全部源码npm i 安装依赖
2. 使用npm run dev进行运行
****
### 使用说明:
~~1. 导入使用仓库中的WebFirst数据库~~
~~2. 使用WebFirst添加实体、同步实体、修改模板生成路径并生成方案~~
没了,恭喜你已经成功完成了项目,并且已经具备大部分通用场景业务
是不是一个字?爽!
到此为止,你无需写任何一个代码!
**爽点**
新人,看这里,项目下载之后直接可以启动,无任何依赖,之后你可以查看`Test控制器`,迫不及待的快来爽一爽!
我们将使用说明转移至我们的官方论坛中,正在制作中,尽情期待!
****
### 感谢:
**大力支持** Eleven神、Sqlsugar上海杰哥、Gerry、哲学的老张
[橙子]https://ccnetcore.com [橙子]https://ccnetcore.com
[XWen]https://gitee.com/on-wensil [lzw]https://github.com/yeslode
[朝夕教育]https://www.zhaoxiedu.net [朝夕教育]https://www.zhaoxiedu.net
[Sqlsugar老杰哥]https://www.donet5.com/Home/Doc [Sqlsugar]https://www.donet5.com/Home/Doc
[车神]微信公众号搜索Dotnet技术进阶 [RuYiAdmin]https://gitee.com/pang-mingjun/RuYiAdmin
[RuYiAdmin如意老兄]https://gitee.com/pang-mingjun/RuYiAdmin [ZrAdminNetCore]https://gitee.com/izory/ZrAdminNetCore
[ZrAdminNetCore字母老哥]https://gitee.com/izory/ZrAdminNetCore
[Admin.NET]https://gitee.com/zuohuaijun/Admin.NET
[Furion百小僧]https://furion.baiqian.ltd/
**** ****
## :tw-1f438: 联系我们: ### 联系我们:
作者QQ`454313500`2029年之前作者24小时在线时刻保持活跃更新。 作者QQ`454313500`2029年之前作者24小时在线时刻保持活跃更新。
QQ交流群官方一群已满、官方二群已满、官方三群`786308927`已满)、官方四群:`498310311`(基本已满)、官方五群:`981136525`(新群 QQ交流群官方一群已满、官方二群已满、官方三群`786308927`加作者QQ后同意
微信交流群:加作者微信 chengzilaoge520 橙子老哥520备注拉群
联系作者,这里人人都是顾问 联系作者,这里人人都是顾问
官方网址留言区:[ccnetcore.com](https://ccnetcore.com) 官方网址:正在建设
**** ****
## :tw-1f41e: FQA: ### FQA:
前往官网查看留言区 问1为什么不采用EFcore
[留言区](https://ccnetcore.com/discuss/1641030787056930818) 答1别问问就是Sqlsugar和本框架一样爽
问2以后会持续更新下去吗
答2一定会的我们的标题是 一个和Sqlsugar一样爽的.Net6开源框架 只要Sqlsugar在我们将一直更新下去。
问3这个框架的针对人群是哪些人适合所有人吗
答3并不是适合所有人应该算适合需要有一定基础的开发人员当然如果你是大神你完全可以将这个框架二次开发
问4花如此多的精力制作这个框架是为了什么是为了赚钱吗和目前主流的abp等框架比又有什么意义呢
答4我们与Sqlsugar作者理念一致我们是从用户角度出发框架是为用户服务与ABP复杂上手理念完全是相反的。
问5为何不出版一个详细的说明书呢
答5暂时不会了之后可能会代码都是基于Asp.NetCore框架适用于新手不用造轮子整个框架较为简单阅读源码后基本能自定义改造使用了过难也已经封装完毕别忘了其意义是为了开发更加简易建议添加作者好友这里人人都是顾问。
我大抵要厌倦了负重前行。

BIN
Readme/代码生成.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

BIN
Readme/用户管理.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
Readme/菜单管理.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View File

@@ -1,509 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34202.233
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Web", "src\Yi.Abp.Web\Yi.Abp.Web.csproj", "{15913E44-DA92-44B9-9AC5-E9457EA34BF5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SqlSugarCore", "framework\Yi.Framework.SqlSugarCore\Yi.Framework.SqlSugarCore.csproj", "{DC431ECC-C75D-4B01-8B79-4861948179BB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B782C78B-6C17-49E6-A237-3383BA720766}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0D10EEF2-FBAE-4C72-B816-A52823FC299B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "framework", "framework", "{77B949E9-530E-45A5-9657-20F7D5C6875C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "module", "module", "{2317227D-7796-4E7B-BEDB-7CD1CAE7B853}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.SqlSugarCore", "src\Yi.Abp.SqlSugarCore\Yi.Abp.SqlSugarCore.csproj", "{9A7BBA40-28D6-4900-9E1D-D627A516EE72}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Application", "src\Yi.Abp.Application\Yi.Abp.Application.csproj", "{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Application.Contracts", "src\Yi.Abp.Application.Contracts\Yi.Abp.Application.Contracts.csproj", "{51EEBF59-3D37-4681-981D-56F8D8F8968D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Domain", "src\Yi.Abp.Domain\Yi.Abp.Domain.csproj", "{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Domain.Shared", "src\Yi.Abp.Domain.Shared\Yi.Abp.Domain.Shared.csproj", "{F4D5A496-BFBE-470B-A05B-CB5823B47E72}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6A5375C6-1D55-4E93-9B19-736F1C68CBC3}"
ProjectSection(SolutionItems) = preProject
common.props = common.props
end.sh = end.sh
logo.png = logo.png
start.sh = start.sh
tool.bat = tool.bat
usings.props = usings.props
version.props = version.props
publish.bat = publish.bat
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SqlSugarCore.Abstractions", "framework\Yi.Framework.SqlSugarCore.Abstractions\Yi.Framework.SqlSugarCore.Abstractions.csproj", "{FD6D6860-3753-4747-8A26-977E4A3001F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core", "framework\Yi.Framework.Core\Yi.Framework.Core.csproj", "{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Mapster", "framework\Yi.Framework.Mapster\Yi.Framework.Mapster.csproj", "{1995A019-C8AE-467E-B427-ED57D6CBF44F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore", "framework\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj", "{F5011C0D-209B-4A98-BBE3-68157503EEF8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Ddd.Application.Contracts", "framework\Yi.Framework.Ddd.Application.Contracts\Yi.Framework.Ddd.Application.Contracts.csproj", "{0A8296A3-C11F-4F13-8E49-6BC8188D4804}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Ddd.Application", "framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj", "{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rbac", "rbac", "{9CC7A457-1236-40BA-B47B-E7B710A3F061}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Application.Contracts", "module\rbac\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj", "{1C360956-8CD8-407E-B87F-D0BD57068EB9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Application", "module\rbac\Yi.Framework.Rbac.Application\Yi.Framework.Rbac.Application.csproj", "{4F02B08D-5FE2-460D-BCA5-DA565151AE30}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Domain", "module\rbac\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj", "{C04D3F71-1557-46D0-B810-97B1FBB6AB73}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Domain.Shared", "module\rbac\Yi.Framework.Rbac.Domain.Shared\Yi.Framework.Rbac.Domain.Shared.csproj", "{A2BB899D-4F9A-4184-81BD-94B938E2AB03}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.SqlSugarCore", "module\rbac\Yi.Framework.Rbac.SqlSugarCore\Yi.Framework.Rbac.SqlSugarCore.csproj", "{4503A2F9-139D-4CBC-AF11-689C34F0D77B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bbs", "bbs", "{E902A945-4F41-4E96-A0DA-9F66CDA22261}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.Domain.Shared", "module\bbs\Yi.Framework.Bbs.Domain.Shared\Yi.Framework.Bbs.Domain.Shared.csproj", "{EB9349E2-256D-41EB-A345-21635A1361B3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.Domain", "module\bbs\Yi.Framework.Bbs.Domain\Yi.Framework.Bbs.Domain.csproj", "{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.Application.Contracts", "module\bbs\Yi.Framework.Bbs.Application.Contracts\Yi.Framework.Bbs.Application.Contracts.csproj", "{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.Application", "module\bbs\Yi.Framework.Bbs.Application\Yi.Framework.Bbs.Application.csproj", "{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Bbs.SqlSugarCore", "module\bbs\Yi.Framework.Bbs.SqlSugarCore\Yi.Framework.Bbs.SqlSugarCore.csproj", "{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "audit-logging", "audit-logging", "{73CCF2C4-B9FD-44AB-8D4B-0A421805B094}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AuditLogging.SqlSugarCore", "module\audit-logging\Yi.Framework.AuditLogging.SqlSugarCore\Yi.Framework.AuditLogging.SqlSugarCore.csproj", "{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore.Authentication.OAuth", "framework\Yi.Framework.AspNetCore.Authentication.OAuth\Yi.Framework.AspNetCore.Authentication.OAuth.csproj", "{791AC2FA-50D3-4408-8D68-31DA72F608BE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{01300F0F-686E-47B3-821D-12424177867B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Web", "sample\Acme.BookStore.Web\Acme.BookStore.Web.csproj", "{576DBC97-4E5D-4444-B65C-F41649A5F8E0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain.Shared", "sample\Acme.BookStore.Domain.Shared\Acme.BookStore.Domain.Shared.csproj", "{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Domain", "sample\Acme.BookStore.Domain\Acme.BookStore.Domain.csproj", "{B615847F-8568-41D1-8B7E-63D61AE69F3D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application.Contracts", "sample\Acme.BookStore.Application.Contracts\Acme.BookStore.Application.Contracts.csproj", "{20827DB5-5CDE-491A-82E8-3CAB82618C1E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.Application", "sample\Acme.BookStore.Application\Acme.BookStore.Application.csproj", "{320273B6-7AE3-42DA-9675-D9AD4928A289}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BookStore.SqlSugarCore", "sample\Acme.BookStore.SqlSugarCore\Acme.BookStore.SqlSugarCore.csproj", "{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Test", "test\Yi.Abp.Test\Yi.Abp.Test.csproj", "{68627BC2-F049-4C69-AD17-81DF9478E8CE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant-management", "{499A8C71-7892-42D0-A77E-48756E1EFF16}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.SqlSugarCore", "module\tenant-management\Yi.Framework.TenantManagement.SqlSugarCore\Yi.Framework.TenantManagement.SqlSugarCore.csproj", "{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.Domain", "module\tenant-management\Yi.Framework.TenantManagement.Domain\Yi.Framework.TenantManagement.Domain.csproj", "{54D8E2BC-591C-4344-A58E-874D49C00B41}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AuditLogging.Domain", "module\audit-logging\Yi.Framework.AuditLogging.Domain\Yi.Framework.AuditLogging.Domain.csproj", "{EFD13211-17B5-400A-B99A-9F6F4E520C1E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AuditLogging.Domain.Shared", "module\audit-logging\Yi.Framework.AuditLogging.Domain.Shared\Yi.Framework.AuditLogging.Domain.Shared.csproj", "{9C8C3C53-3DCE-4516-867E-228858E61B26}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.Application", "module\tenant-management\Yi.Framework.TenantManagement.Application\Yi.Framework.TenantManagement.Application.csproj", "{17816837-E53B-486B-B796-53C601FE6CD9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.Application.Contracts", "module\tenant-management\Yi.Framework.TenantManagement.Application.Contracts\Yi.Framework.TenantManagement.Application.Contracts.csproj", "{FA735055-CBDD-4EFD-B84B-85810DA1425E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code-gen", "code-gen", "{4FFE7212-21F2-476D-B628-3C65E6C5075E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application", "module\code-gen\Yi.Framework.CodeGen.Application\Yi.Framework.CodeGen.Application.csproj", "{97EC40D7-DBFA-467A-98CB-221AF27B14F2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application.Contracts", "module\code-gen\Yi.Framework.CodeGen.Application.Contracts\Yi.Framework.CodeGen.Application.Contracts.csproj", "{882BC563-2F75-4B95-AC96-F4BF23F5E69D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain", "module\code-gen\Yi.Framework.CodeGen.Domain\Yi.Framework.CodeGen.Domain.csproj", "{85CB8517-2B80-42D8-B954-081079AC9BA0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain.Shared", "module\code-gen\Yi.Framework.CodeGen.Domain.Shared\Yi.Framework.CodeGen.Domain.Shared.csproj", "{EEFF0F05-2709-4151-A8CE-667935CEAE0B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching.FreeRedis", "framework\Yi.Framework.Caching.FreeRedis\Yi.Framework.Caching.FreeRedis.csproj", "{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.SqlSugarCore", "module\code-gen\Yi.Framework.CodeGen.SqlSugarCore\Yi.Framework.CodeGen.SqlSugarCore.csproj", "{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client", "client", "{8B27846A-043D-4F2F-8140-5CEC9D1863B5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.HttpApi.Client", "client\Yi.Abp.HttpApi.Client\Yi.Abp.HttpApi.Client.csproj", "{6B554DCC-3A81-4624-9141-4E39365ADA35}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Client.Console", "client\Yi.Abp.Client.Console\Yi.Abp.Client.Console.csproj", "{2D23B44A-DFA3-4C36-8516-4F5AE442403C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Client.WebApi", "client\Yi.Abp.Client.WebApi\Yi.Abp.Client.WebApi.csproj", "{00E49781-C6A0-491C-86A1-46F685C90915}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "setting-management", "setting-management", "{8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SettingManagement.Domain", "module\setting-management\Yi.Framework.SettingManagement.Domain\Yi.Framework.SettingManagement.Domain.csproj", "{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.SettingManagement.SqlSugarCore", "module\setting-management\Yi.Framework.SettingManagement.SqlSugarCore\Yi.Framework.SettingManagement.SqlSugarCore.csproj", "{495C4643-39D4-46E7-BDC8-237589627BE4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "chat-hub", "chat-hub", "{D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.Application.Contracts", "module\chat-hub\Yi.Framework.ChatHub.Application.Contracts\Yi.Framework.ChatHub.Application.Contracts.csproj", "{65D4D033-5504-44B9-B152-0172ACD64CE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.Domain.Shared", "module\chat-hub\Yi.Framework.ChatHub.Domain.Shared\Yi.Framework.ChatHub.Domain.Shared.csproj", "{DEEC0B15-190C-4464-B469-C45C6563C592}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.SqlSugarCore", "module\chat-hub\Yi.Framework.ChatHub.SqlSugarCore\Yi.Framework.ChatHub.SqlSugarCore.csproj", "{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.Domain", "module\chat-hub\Yi.Framework.ChatHub.Domain\Yi.Framework.ChatHub.Domain.csproj", "{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ChatHub.Application", "module\chat-hub\Yi.Framework.ChatHub.Application\Yi.Framework.ChatHub.Application.csproj", "{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Rbac.Test", "test\Yi.Framework.Rbac.Test\Yi.Framework.Rbac.Test.csproj", "{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tool", "tool", "{084CBEEC-5D37-4716-B9C7-D80D6960DFF4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool", "tool\Yi.Abp.Tool\Yi.Abp.Tool.csproj", "{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Web", "tool\Yi.Abp.Tool.Web\Yi.Abp.Tool.Web.csproj", "{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Application", "tool\Yi.Abp.Tool.Application\Yi.Abp.Tool.Application.csproj", "{776590BA-B900-4C8B-986A-5B721FA4B306}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Application.Contracts", "tool\Yi.Abp.Tool.Application.Contracts\Yi.Abp.Tool.Application.Contracts.csproj", "{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Domain", "tool\Yi.Abp.Tool.Domain\Yi.Abp.Tool.Domain.csproj", "{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.Domain.Shared", "tool\Yi.Abp.Tool.Domain.Shared\Yi.Abp.Tool.Domain.Shared.csproj", "{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.HttpApi.Client", "tool\Yi.Abp.Tool.HttpApi.Client\Yi.Abp.Tool.HttpApi.Client.csproj", "{C8F97775-D903-4365-A4FF-3DA97E318CD2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.SettingManagement.Application", "module\setting-management\Yi.Framework.SettingManagement.Application\Yi.Framework.SettingManagement.Application.csproj", "{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15913E44-DA92-44B9-9AC5-E9457EA34BF5}.Release|Any CPU.Build.0 = Release|Any CPU
{DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC431ECC-C75D-4B01-8B79-4861948179BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC431ECC-C75D-4B01-8B79-4861948179BB}.Release|Any CPU.Build.0 = Release|Any CPU
{9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A7BBA40-28D6-4900-9E1D-D627A516EE72}.Release|Any CPU.Build.0 = Release|Any CPU
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD}.Release|Any CPU.Build.0 = Release|Any CPU
{51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{51EEBF59-3D37-4681-981D-56F8D8F8968D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51EEBF59-3D37-4681-981D-56F8D8F8968D}.Release|Any CPU.Build.0 = Release|Any CPU
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD}.Release|Any CPU.Build.0 = Release|Any CPU
{F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4D5A496-BFBE-470B-A05B-CB5823B47E72}.Release|Any CPU.Build.0 = Release|Any CPU
{FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD6D6860-3753-4747-8A26-977E4A3001F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD6D6860-3753-4747-8A26-977E4A3001F9}.Release|Any CPU.Build.0 = Release|Any CPU
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5}.Release|Any CPU.Build.0 = Release|Any CPU
{1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1995A019-C8AE-467E-B427-ED57D6CBF44F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1995A019-C8AE-467E-B427-ED57D6CBF44F}.Release|Any CPU.Build.0 = Release|Any CPU
{F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F5011C0D-209B-4A98-BBE3-68157503EEF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5011C0D-209B-4A98-BBE3-68157503EEF8}.Release|Any CPU.Build.0 = Release|Any CPU
{0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A8296A3-C11F-4F13-8E49-6BC8188D4804}.Release|Any CPU.Build.0 = Release|Any CPU
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE}.Release|Any CPU.Build.0 = Release|Any CPU
{1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C360956-8CD8-407E-B87F-D0BD57068EB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C360956-8CD8-407E-B87F-D0BD57068EB9}.Release|Any CPU.Build.0 = Release|Any CPU
{4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F02B08D-5FE2-460D-BCA5-DA565151AE30}.Release|Any CPU.Build.0 = Release|Any CPU
{C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C04D3F71-1557-46D0-B810-97B1FBB6AB73}.Release|Any CPU.Build.0 = Release|Any CPU
{A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2BB899D-4F9A-4184-81BD-94B938E2AB03}.Release|Any CPU.Build.0 = Release|Any CPU
{4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4503A2F9-139D-4CBC-AF11-689C34F0D77B}.Release|Any CPU.Build.0 = Release|Any CPU
{EB9349E2-256D-41EB-A345-21635A1361B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB9349E2-256D-41EB-A345-21635A1361B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB9349E2-256D-41EB-A345-21635A1361B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB9349E2-256D-41EB-A345-21635A1361B3}.Release|Any CPU.Build.0 = Release|Any CPU
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7}.Release|Any CPU.Build.0 = Release|Any CPU
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20}.Release|Any CPU.Build.0 = Release|Any CPU
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B}.Release|Any CPU.Build.0 = Release|Any CPU
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA}.Release|Any CPU.Build.0 = Release|Any CPU
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3}.Release|Any CPU.Build.0 = Release|Any CPU
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{791AC2FA-50D3-4408-8D68-31DA72F608BE}.Release|Any CPU.Build.0 = Release|Any CPU
{576DBC97-4E5D-4444-B65C-F41649A5F8E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{576DBC97-4E5D-4444-B65C-F41649A5F8E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{576DBC97-4E5D-4444-B65C-F41649A5F8E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{576DBC97-4E5D-4444-B65C-F41649A5F8E0}.Release|Any CPU.Build.0 = Release|Any CPU
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D}.Release|Any CPU.Build.0 = Release|Any CPU
{B615847F-8568-41D1-8B7E-63D61AE69F3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B615847F-8568-41D1-8B7E-63D61AE69F3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B615847F-8568-41D1-8B7E-63D61AE69F3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B615847F-8568-41D1-8B7E-63D61AE69F3D}.Release|Any CPU.Build.0 = Release|Any CPU
{20827DB5-5CDE-491A-82E8-3CAB82618C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20827DB5-5CDE-491A-82E8-3CAB82618C1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20827DB5-5CDE-491A-82E8-3CAB82618C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20827DB5-5CDE-491A-82E8-3CAB82618C1E}.Release|Any CPU.Build.0 = Release|Any CPU
{320273B6-7AE3-42DA-9675-D9AD4928A289}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{320273B6-7AE3-42DA-9675-D9AD4928A289}.Debug|Any CPU.Build.0 = Debug|Any CPU
{320273B6-7AE3-42DA-9675-D9AD4928A289}.Release|Any CPU.ActiveCfg = Release|Any CPU
{320273B6-7AE3-42DA-9675-D9AD4928A289}.Release|Any CPU.Build.0 = Release|Any CPU
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7}.Release|Any CPU.Build.0 = Release|Any CPU
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68627BC2-F049-4C69-AD17-81DF9478E8CE}.Release|Any CPU.Build.0 = Release|Any CPU
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}.Release|Any CPU.Build.0 = Release|Any CPU
{54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54D8E2BC-591C-4344-A58E-874D49C00B41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54D8E2BC-591C-4344-A58E-874D49C00B41}.Release|Any CPU.Build.0 = Release|Any CPU
{EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EFD13211-17B5-400A-B99A-9F6F4E520C1E}.Release|Any CPU.Build.0 = Release|Any CPU
{9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C8C3C53-3DCE-4516-867E-228858E61B26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C8C3C53-3DCE-4516-867E-228858E61B26}.Release|Any CPU.Build.0 = Release|Any CPU
{17816837-E53B-486B-B796-53C601FE6CD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17816837-E53B-486B-B796-53C601FE6CD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17816837-E53B-486B-B796-53C601FE6CD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17816837-E53B-486B-B796-53C601FE6CD9}.Release|Any CPU.Build.0 = Release|Any CPU
{FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA735055-CBDD-4EFD-B84B-85810DA1425E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA735055-CBDD-4EFD-B84B-85810DA1425E}.Release|Any CPU.Build.0 = Release|Any CPU
{97EC40D7-DBFA-467A-98CB-221AF27B14F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97EC40D7-DBFA-467A-98CB-221AF27B14F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97EC40D7-DBFA-467A-98CB-221AF27B14F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97EC40D7-DBFA-467A-98CB-221AF27B14F2}.Release|Any CPU.Build.0 = Release|Any CPU
{882BC563-2F75-4B95-AC96-F4BF23F5E69D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{882BC563-2F75-4B95-AC96-F4BF23F5E69D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{882BC563-2F75-4B95-AC96-F4BF23F5E69D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{882BC563-2F75-4B95-AC96-F4BF23F5E69D}.Release|Any CPU.Build.0 = Release|Any CPU
{85CB8517-2B80-42D8-B954-081079AC9BA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85CB8517-2B80-42D8-B954-081079AC9BA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85CB8517-2B80-42D8-B954-081079AC9BA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85CB8517-2B80-42D8-B954-081079AC9BA0}.Release|Any CPU.Build.0 = Release|Any CPU
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Release|Any CPU.Build.0 = Release|Any CPU
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.Build.0 = Release|Any CPU
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Release|Any CPU.Build.0 = Release|Any CPU
{6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B554DCC-3A81-4624-9141-4E39365ADA35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B554DCC-3A81-4624-9141-4E39365ADA35}.Release|Any CPU.Build.0 = Release|Any CPU
{2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D23B44A-DFA3-4C36-8516-4F5AE442403C}.Release|Any CPU.Build.0 = Release|Any CPU
{00E49781-C6A0-491C-86A1-46F685C90915}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00E49781-C6A0-491C-86A1-46F685C90915}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00E49781-C6A0-491C-86A1-46F685C90915}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00E49781-C6A0-491C-86A1-46F685C90915}.Release|Any CPU.Build.0 = Release|Any CPU
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF}.Release|Any CPU.Build.0 = Release|Any CPU
{495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{495C4643-39D4-46E7-BDC8-237589627BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{495C4643-39D4-46E7-BDC8-237589627BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{495C4643-39D4-46E7-BDC8-237589627BE4}.Release|Any CPU.Build.0 = Release|Any CPU
{65D4D033-5504-44B9-B152-0172ACD64CE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65D4D033-5504-44B9-B152-0172ACD64CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65D4D033-5504-44B9-B152-0172ACD64CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65D4D033-5504-44B9-B152-0172ACD64CE6}.Release|Any CPU.Build.0 = Release|Any CPU
{DEEC0B15-190C-4464-B469-C45C6563C592}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DEEC0B15-190C-4464-B469-C45C6563C592}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEEC0B15-190C-4464-B469-C45C6563C592}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEEC0B15-190C-4464-B469-C45C6563C592}.Release|Any CPU.Build.0 = Release|Any CPU
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E}.Release|Any CPU.Build.0 = Release|Any CPU
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47}.Release|Any CPU.Build.0 = Release|Any CPU
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D}.Release|Any CPU.Build.0 = Release|Any CPU
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07}.Release|Any CPU.Build.0 = Release|Any CPU
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F}.Release|Any CPU.Build.0 = Release|Any CPU
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1}.Release|Any CPU.Build.0 = Release|Any CPU
{776590BA-B900-4C8B-986A-5B721FA4B306}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{776590BA-B900-4C8B-986A-5B721FA4B306}.Debug|Any CPU.Build.0 = Debug|Any CPU
{776590BA-B900-4C8B-986A-5B721FA4B306}.Release|Any CPU.ActiveCfg = Release|Any CPU
{776590BA-B900-4C8B-986A-5B721FA4B306}.Release|Any CPU.Build.0 = Release|Any CPU
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675}.Release|Any CPU.Build.0 = Release|Any CPU
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8}.Release|Any CPU.Build.0 = Release|Any CPU
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8}.Release|Any CPU.Build.0 = Release|Any CPU
{C8F97775-D903-4365-A4FF-3DA97E318CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8F97775-D903-4365-A4FF-3DA97E318CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8F97775-D903-4365-A4FF-3DA97E318CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8F97775-D903-4365-A4FF-3DA97E318CD2}.Release|Any CPU.Build.0 = Release|Any CPU
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{15913E44-DA92-44B9-9AC5-E9457EA34BF5} = {B782C78B-6C17-49E6-A237-3383BA720766}
{DC431ECC-C75D-4B01-8B79-4861948179BB} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{9A7BBA40-28D6-4900-9E1D-D627A516EE72} = {B782C78B-6C17-49E6-A237-3383BA720766}
{746DBBD6-23E8-4D5D-9D23-E2902BE338BD} = {B782C78B-6C17-49E6-A237-3383BA720766}
{51EEBF59-3D37-4681-981D-56F8D8F8968D} = {B782C78B-6C17-49E6-A237-3383BA720766}
{7B15C198-538A-44ED-A6AA-3A0FEAA1D2BD} = {B782C78B-6C17-49E6-A237-3383BA720766}
{F4D5A496-BFBE-470B-A05B-CB5823B47E72} = {B782C78B-6C17-49E6-A237-3383BA720766}
{FD6D6860-3753-4747-8A26-977E4A3001F9} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{ECE874D4-F882-4EF4-84A6-A842D9B8FBC5} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{1995A019-C8AE-467E-B427-ED57D6CBF44F} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{F5011C0D-209B-4A98-BBE3-68157503EEF8} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{0A8296A3-C11F-4F13-8E49-6BC8188D4804} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{F0141C17-0EBD-4261-98D5-1C5B7BC1DFEE} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{9CC7A457-1236-40BA-B47B-E7B710A3F061} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
{1C360956-8CD8-407E-B87F-D0BD57068EB9} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
{4F02B08D-5FE2-460D-BCA5-DA565151AE30} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
{C04D3F71-1557-46D0-B810-97B1FBB6AB73} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
{A2BB899D-4F9A-4184-81BD-94B938E2AB03} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
{4503A2F9-139D-4CBC-AF11-689C34F0D77B} = {9CC7A457-1236-40BA-B47B-E7B710A3F061}
{E902A945-4F41-4E96-A0DA-9F66CDA22261} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
{EB9349E2-256D-41EB-A345-21635A1361B3} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
{4EABBC84-BCED-46C1-8CF1-62A7B8081ED7} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
{7E569FD9-B1AB-4848-8AB7-FD9EFA1DBA20} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
{AD4EE9E6-F4A3-4139-AF05-71388167DE5B} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
{6C86BA71-9F87-4E2C-B467-2950D77DCDFA} = {E902A945-4F41-4E96-A0DA-9F66CDA22261}
{73CCF2C4-B9FD-44AB-8D4B-0A421805B094} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
{48806510-8E18-4E1E-9BAF-5B97E88C5FC3} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094}
{791AC2FA-50D3-4408-8D68-31DA72F608BE} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{576DBC97-4E5D-4444-B65C-F41649A5F8E0} = {01300F0F-686E-47B3-821D-12424177867B}
{D7F8BD42-F6A2-4F0A-9212-391B5185A99D} = {01300F0F-686E-47B3-821D-12424177867B}
{B615847F-8568-41D1-8B7E-63D61AE69F3D} = {01300F0F-686E-47B3-821D-12424177867B}
{20827DB5-5CDE-491A-82E8-3CAB82618C1E} = {01300F0F-686E-47B3-821D-12424177867B}
{320273B6-7AE3-42DA-9675-D9AD4928A289} = {01300F0F-686E-47B3-821D-12424177867B}
{70CCBD89-C0A1-4AC8-9AFA-C86C356DFDD7} = {01300F0F-686E-47B3-821D-12424177867B}
{68627BC2-F049-4C69-AD17-81DF9478E8CE} = {0D10EEF2-FBAE-4C72-B816-A52823FC299B}
{499A8C71-7892-42D0-A77E-48756E1EFF16} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
{FA5BBAA1-08DC-472F-BB2C-5314E59D1556} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
{54D8E2BC-591C-4344-A58E-874D49C00B41} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
{EFD13211-17B5-400A-B99A-9F6F4E520C1E} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094}
{9C8C3C53-3DCE-4516-867E-228858E61B26} = {73CCF2C4-B9FD-44AB-8D4B-0A421805B094}
{17816837-E53B-486B-B796-53C601FE6CD9} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
{FA735055-CBDD-4EFD-B84B-85810DA1425E} = {499A8C71-7892-42D0-A77E-48756E1EFF16}
{4FFE7212-21F2-476D-B628-3C65E6C5075E} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
{97EC40D7-DBFA-467A-98CB-221AF27B14F2} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
{882BC563-2F75-4B95-AC96-F4BF23F5E69D} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
{85CB8517-2B80-42D8-B954-081079AC9BA0} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
{EEFF0F05-2709-4151-A8CE-667935CEAE0B} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{FB09ACC2-A27D-4D87-8D85-1435FDED4D04} = {4FFE7212-21F2-476D-B628-3C65E6C5075E}
{6B554DCC-3A81-4624-9141-4E39365ADA35} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5}
{2D23B44A-DFA3-4C36-8516-4F5AE442403C} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5}
{00E49781-C6A0-491C-86A1-46F685C90915} = {8B27846A-043D-4F2F-8140-5CEC9D1863B5}
{8C68059E-F3B1-4D28-A1C9-A5830F53E5D3} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
{6FEE0EB3-EAD2-47F8-B6FC-3D0FD3CCABFF} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
{495C4643-39D4-46E7-BDC8-237589627BE4} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
{D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB} = {2317227D-7796-4E7B-BEDB-7CD1CAE7B853}
{65D4D033-5504-44B9-B152-0172ACD64CE6} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
{DEEC0B15-190C-4464-B469-C45C6563C592} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
{E476D266-8FB2-4D6B-AE2B-F0D279D4264E} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
{C2DCA2FD-BFB4-4E76-967B-0AF8CC4F4D47} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
{B7A1A8F3-CFA6-4ECF-A707-0F33FE0A6F1D} = {D8CDDE99-3684-4EED-A5E5-87F2AF4C78AB}
{9ECF0841-53BE-4FD8-95D1-A7223C7F3A07} = {0D10EEF2-FBAE-4C72-B816-A52823FC299B}
{4FEBBDD9-E4F4-4BAF-8599-E2D57C08A74F} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{2CE51D4C-1EF9-462B-BA14-7EA01A7E4AF1} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{776590BA-B900-4C8B-986A-5B721FA4B306} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{3A3AF1ED-FC7F-48CF-8ACE-9D50426B4675} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{68F73B7B-0F8A-41C1-8092-6D6FFAED32F8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{C8F97775-D903-4365-A4FF-3DA97E318CD2} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18}
EndGlobalSection
EndGlobal

View File

@@ -1,33 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Yi.Abp.Client.Console;
using Yi.Framework.Rbac.Application.Contracts.IServices;
try
{
IHost host = Host.CreateDefaultBuilder()
.ConfigureServices(async (host, service) =>
{
await service.AddApplicationAsync<YiAbpClientConsoleModule>();
})
.UseAutofac()
.Build();
//控制台直接调用
var account = host.Services.GetRequiredService<IAccountService>();
//获取验证码
var data1 = await account.GetCaptchaImageAsync();
//登录
var data2 = await account.PostLoginAsync(new Yi.Framework.Rbac.Application.Contracts.Dtos.Account.LoginInputVo { UserName = "cc", Password = "123456", Code = string.Empty, Uuid = string.Empty });
host.Run();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}

View File

@@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Volo.Abp.Autofac" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Abp.HttpApi.Client\Yi.Abp.HttpApi.Client.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Modularity;
using Yi.Abp.HttpApi.Client;
namespace Yi.Abp.Client.Console
{
[DependsOn(typeof(YiAbpHttpApiClientModule))]
public class YiAbpClientConsoleModule:AbpModule
{
}
}

View File

@@ -1,37 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using Yi.Framework.Rbac.Application.Contracts.Dtos.Account;
using Yi.Framework.Rbac.Application.Contracts.IServices;
namespace Yi.Abp.Client.WebApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class AccountController : ControllerBase
{
private readonly ILogger<AccountController> _logger;
private IAccountService _accountService;
public AccountController(ILogger<AccountController> logger, IAccountService accountService)
{
_logger = logger;
_accountService = accountService;
}
[HttpPost("my-login")]
public async Task<IActionResult> Login(LoginInputVo input)
{
await _accountService.PostLoginAsync(input);
return Ok();
}
[HttpGet("my-captcha-image")]
public async Task<IActionResult> CaptchaImageAsync()
{
var output = await _accountService.GetCaptchaImageAsync();
return Ok(output);
}
}
}

View File

@@ -1,28 +0,0 @@
using Autofac.Core;
using Yi.Abp.Client.WebApi;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Host.UseAutofac();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
await builder.Services.AddApplicationAsync<YiAbpClientWebApiModule>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@@ -1,41 +0,0 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:35597",
"sslPort": 44322
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5002",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7108;http://localhost:5002",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Abp.HttpApi.Client\Yi.Abp.HttpApi.Client.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,6 +0,0 @@
@Yi.Abp.Client.WebApi_HostAddress = http://localhost:5002
GET {{Yi.Abp.Client.WebApi_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@@ -1,10 +0,0 @@
using Volo.Abp.Modularity;
using Yi.Abp.HttpApi.Client;
namespace Yi.Abp.Client.WebApi
{
[DependsOn(typeof(YiAbpHttpApiClientModule))]
public class YiAbpClientWebApiModule:AbpModule
{
}
}

View File

@@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Volo.Abp.Http.Client" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Autofac" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Yi.Abp.Application.Contracts\Yi.Abp.Application.Contracts.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,32 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Yi.Framework.Rbac.Application.Contracts;
namespace Yi.Abp.HttpApi.Client
{
[DependsOn(typeof(AbpHttpClientModule),
typeof(AbpAutofacModule),
typeof(YiFrameworkRbacApplicationContractsModule))]
public class YiAbpHttpApiClientModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//创建动态客户端代理
context.Services.AddHttpClientProxies(
typeof(YiFrameworkRbacApplicationContractsModule).Assembly
);
Configure<AbpRemoteServiceOptions>(options =>
{
options.RemoteServices.Default =
new RemoteServiceConfiguration("http://localhost:19001");
});
}
}
}

View File

@@ -1,39 +0,0 @@
<Project>
<Import Project="usings.props" />
<Import Project="version.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>1.0.0</Version>
<NoWarn>$(NoWarn);CS1591;CS8618;CS1998;CS8604;CS8620;CS8600;CS8602</NoWarn>
<AbpProjectType>app</AbpProjectType>
<PublishDocumentationFiles>true</PublishDocumentationFiles>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<Target Name="NoWarnOnRazorViewImportedTypeConflicts" BeforeTargets="RazorCoreCompile">
<PropertyGroup>
<NoWarn>$(NoWarn);0436</NoWarn>
</PropertyGroup>
</Target>
<ItemGroup>
<Content Remove="$(UserProfile)\.nuget\packages\*\*\contentFiles\any\*\*.abppkg*.json" />
</ItemGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>

View File

@@ -1,3 +0,0 @@
#!/bin/bash
kill -9 $(lsof -t -i:19001)
echo "Yi-进程已关闭"

View File

@@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.AspNetCore.Authentication.OAuth
{
public class AuthenticationConstants
{
public const string OpenId = "urn:openid";
public const string AccessToken = "urn:access_token";
public const string Name = "urn:name";
}
}

View File

@@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.OAuth;
namespace Yi.Framework.AspNetCore.Authentication.OAuth
{
public class AuthenticationOAuthOptions:OAuthOptions
{
public string RedirectUri { get; set; }
}
}

View File

@@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
namespace Yi.Framework.AspNetCore.Authentication.OAuth
{
public class AuthticationErrCodeModel
{
public string error { get; set; }
public string error_description { get; set; }
public static void VerifyErrResponse(string content)
{
var model = Newtonsoft.Json.JsonConvert.DeserializeObject<AuthticationErrCodeModel>(content);
if (model.error != null)
{
throw new Exception($"第三方授权返回错误,错误码:【{model.error}】,错误详情:【{model.error_description}】");
}
}
}
}

View File

@@ -1,19 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
/// <summary>
/// Contains constants specific to the <see cref="GiteeAuthenticationHandler"/>.
/// </summary>
public static class GiteeAuthenticationConstants
{
public static class Claims
{
public const string Url = "urn:gitee:url";
public const string AvatarUrl = "urn:gitee:avatarUrl";
}
}

View File

@@ -1,53 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
/// <summary>
/// Default values used by the Gitee authentication middleware.
/// </summary>
public static class GiteeAuthenticationDefaults
{
/// <summary>
/// Default value for <see cref="AuthenticationScheme.Name"/>.
/// </summary>
public const string AuthenticationScheme = "Gitee";
/// <summary>
/// Default value for <see cref="AuthenticationScheme.DisplayName"/>.
/// </summary>
public static readonly string DisplayName = "Gitee";
/// <summary>
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
/// </summary>
public static readonly string Issuer = "Gitee";
/// <summary>
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
/// </summary>
public static readonly string CallbackPath = "/signin-gitee";
/// <summary>
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
/// </summary>
public static readonly string AuthorizationEndpoint = "https://gitee.com/oauth/authorize";
/// <summary>
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
/// </summary>
public static readonly string TokenEndpoint = "https://gitee.com/oauth/token";
/// <summary>
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
/// </summary>
public static readonly string UserInformationEndpoint = "https://gitee.com/api/v5/user";
/// <summary>
/// Default value for <see cref="GiteeAuthenticationOptions.UserEmailsEndpoint"/>.
/// </summary>
public static readonly string UserEmailsEndpoint = "https://gitee.com/api/v5/emails";
}

View File

@@ -1,75 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
/// <summary>
/// Extension methods to add Gitee authentication capabilities to an HTTP application pipeline.
/// </summary>
public static class GiteeAuthenticationExtensions
{
/// <summary>
/// Adds <see cref="GiteeAuthenticationHandler"/> to the specified
/// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities.
/// </summary>
/// <param name="builder">The authentication builder.</param>
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
public static AuthenticationBuilder AddGitee([NotNull] this AuthenticationBuilder builder)
{
return builder.AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, options => { });
}
/// <summary>
/// Adds <see cref="GiteeAuthenticationHandler"/> to the specified
/// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities.
/// </summary>
/// <param name="builder">The authentication builder.</param>
/// <param name="configuration">The delegate used to configure the OpenID 2.0 options.</param>
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
public static AuthenticationBuilder AddGitee(
[NotNull] this AuthenticationBuilder builder,
[NotNull] Action<GiteeAuthenticationOptions> configuration)
{
return builder.AddGitee(GiteeAuthenticationDefaults.AuthenticationScheme, configuration);
}
/// <summary>
/// Adds <see cref="GiteeAuthenticationHandler"/> to the specified
/// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities.
/// </summary>
/// <param name="builder">The authentication builder.</param>
/// <param name="scheme">The authentication scheme associated with this instance.</param>
/// <param name="configuration">The delegate used to configure the Gitee options.</param>
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
public static AuthenticationBuilder AddGitee(
[NotNull] this AuthenticationBuilder builder,
[NotNull] string scheme,
[NotNull] Action<GiteeAuthenticationOptions> configuration)
{
return builder.AddGitee(scheme, GiteeAuthenticationDefaults.DisplayName, configuration);
}
/// <summary>
/// Adds <see cref="GiteeAuthenticationHandler"/> to the specified
/// <see cref="AuthenticationBuilder"/>, which enables Gitee authentication capabilities.
/// </summary>
/// <param name="builder">The authentication builder.</param>
/// <param name="scheme">The authentication scheme associated with this instance.</param>
/// <param name="caption">The optional display name associated with this instance.</param>
/// <param name="configuration">The delegate used to configure the Gitee options.</param>
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
public static AuthenticationBuilder AddGitee(
[NotNull] this AuthenticationBuilder builder,
[NotNull] string scheme,
[CanBeNull] string caption,
[NotNull] Action<GiteeAuthenticationOptions> configuration)
{
return builder.AddScheme<GiteeAuthenticationOptions, GiteeAuthenticationHandler>(scheme, caption, configuration);
}
}

View File

@@ -1,49 +0,0 @@
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using static Yi.Framework.AspNetCore.Authentication.OAuth.Gitee.GiteeAuthenticationConstants;
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee
{
public class GiteeAuthenticationHandler : OauthAuthenticationHandler<GiteeAuthenticationOptions>
{
public GiteeAuthenticationHandler(IOptionsMonitor<GiteeAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder, httpClientFactory)
{
}
public override string AuthenticationSchemeNmae => GiteeAuthenticationDefaults.AuthenticationScheme;
protected override async Task<List<Claim>> GetAuthTicketAsync(string code)
{
//获取 accessToken
var tokenQueryKv = new List<KeyValuePair<string, string?>>()
{
new KeyValuePair<string, string?>("grant_type","authorization_code"),
new KeyValuePair<string, string?>("client_id",Options.ClientId),
new KeyValuePair<string, string?>("client_secret",Options.ClientSecret),
new KeyValuePair<string, string?>("redirect_uri",Options.RedirectUri),
new KeyValuePair<string, string?>("code",code)
};
var tokenModel = await SendHttpRequestAsync<GiteeAuthticationcationTokenResponse>(GiteeAuthenticationDefaults.TokenEndpoint, tokenQueryKv,HttpMethod.Post);
//获取 userInfo
var userInfoQueryKv = new List<KeyValuePair<string, string?>>()
{
new KeyValuePair<string, string?>("access_token",tokenModel.access_token),
};
var userInfoMdoel = await SendHttpRequestAsync<GiteeAuthticationcationUserInfoResponse>(GiteeAuthenticationDefaults.UserInformationEndpoint, userInfoQueryKv);
List<Claim> claims = new List<Claim>()
{
new Claim(Claims.AvatarUrl, userInfoMdoel.avatar_url),
new Claim(Claims.Url, userInfoMdoel.url),
new Claim(AuthenticationConstants.OpenId,userInfoMdoel.id.ToString()),
new Claim(AuthenticationConstants.Name, userInfoMdoel.name),
new Claim(AuthenticationConstants.AccessToken, tokenModel.access_token)
};
return claims;
}
}
}

View File

@@ -1,44 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using static Yi.Framework.AspNetCore.Authentication.OAuth.Gitee.GiteeAuthenticationConstants;
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
/// <summary>
/// Defines a set of options used by <see cref="GiteeAuthenticationHandler"/>.
/// </summary>
public class GiteeAuthenticationOptions : AuthenticationOAuthOptions
{
public GiteeAuthenticationOptions()
{
ClaimsIssuer = GiteeAuthenticationDefaults.Issuer;
CallbackPath = GiteeAuthenticationDefaults.CallbackPath;
AuthorizationEndpoint = GiteeAuthenticationDefaults.AuthorizationEndpoint;
TokenEndpoint = GiteeAuthenticationDefaults.TokenEndpoint;
UserInformationEndpoint = GiteeAuthenticationDefaults.UserInformationEndpoint;
UserEmailsEndpoint = GiteeAuthenticationDefaults.UserEmailsEndpoint;
Scope.Add("user_info");
Scope.Add("emails");
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
ClaimActions.MapJsonKey(ClaimTypes.Name, "login");
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
ClaimActions.MapJsonKey(Claims.Url, "url");
}
/// <summary>
/// Gets or sets the address of the endpoint exposing
/// the email addresses associated with the logged in user.
/// </summary>
public string UserEmailsEndpoint { get; set; }
}

View File

@@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.AspNetCore.Authentication.OAuth.Gitee
{
public class GiteeAuthticationcationTokenResponse
{
public string access_token { get; set; }
public string token_type { get; set; }
public int expires_in { get; set; }
public string refresh_token { get; set; }
public string scope { get; set; }
public long created_at { get; set; }
}
public class GiteeAuthticationcationOpenIdResponse
{
public string client_id { get; set; }
public string openid { get; set; }
}
public class GiteeAuthticationcationUserInfoResponse
{
/// <summary>
/// 也可以等于openId
/// </summary>
public int id { get; set; }
public string login { get; set; }
public string name { get; set; }
public string avatar_url { get; set; }
public string url { get; set; }
public string html_url { get; set; }
public string remark { get; set; }
public string followers_url { get; set; }
public string following_url { get; set; }
public string gists_url { get; set; }
public string starred_url { get; set; }
public string subscriptions_url { get; set; }
public string organizations_url { get; set; }
public string repos_url { get; set; }
public string events_url { get; set; }
public string received_events_url { get; set; }
public string type { get; set; }
public string blog { get; set; }
public string weibo { get; set; }
public string bio { get; set; }
public int public_repos { get; set; }
public int public_gists { get; set; }
public int followers { get; set; }
public int following { get; set; }
public int stared { get; set; }
public int watched { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
public string email { get; set; }
}
}

View File

@@ -1,96 +0,0 @@
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Yi.Framework.AspNetCore.Authentication.OAuth
{
public abstract class OauthAuthenticationHandler<TOptions> : AuthenticationHandler<TOptions> where TOptions : AuthenticationSchemeOptions, new()
{
public abstract string AuthenticationSchemeNmae { get; }
private AuthenticationScheme _scheme;
public OauthAuthenticationHandler(IOptionsMonitor<TOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder)
{
HttpClientFactory = httpClientFactory;
HttpClient = HttpClientFactory.CreateClient();
}
protected IHttpClientFactory HttpClientFactory { get; }
protected HttpClient HttpClient { get; }
/// <summary>
/// 生成认证票据
/// </summary>
/// <returns></returns>
private AuthenticationTicket TicketConver(List<Claim> claims)
{
var claimsIdentity = new ClaimsIdentity(claims.ToArray(), AuthenticationSchemeNmae);
var principal = new ClaimsPrincipal(claimsIdentity);
return new AuthenticationTicket(principal, AuthenticationSchemeNmae);
}
protected async Task<HttpModel> SendHttpRequestAsync<HttpModel>(string url, IEnumerable<KeyValuePair<string, string?>> query, HttpMethod? httpMethod = null)
{
httpMethod = httpMethod ?? HttpMethod.Get;
var queryUrl = QueryHelpers.AddQueryString(url, query);
HttpResponseMessage response = null;
if (httpMethod == HttpMethod.Get)
{
response = await HttpClient.GetAsync(queryUrl);
}
else if (httpMethod == HttpMethod.Post)
{
response = await HttpClient.PostAsync(queryUrl, null);
}
var content = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
throw new Exception($"授权服务器请求错误,请求地址:{queryUrl},错误信息:{content}");
}
VerifyErrResponse(content);
var model = Newtonsoft.Json.JsonConvert.DeserializeObject<HttpModel>(content);
return model!;
}
protected virtual void VerifyErrResponse(string content)
{
AuthticationErrCodeModel.VerifyErrResponse(content);
}
protected abstract Task<List<Claim>> GetAuthTicketAsync(string code);
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Context.Request.Query.ContainsKey("code"))
{
return AuthenticateResult.Fail("回调未包含code参数");
}
var code = Context.Request.Query["code"].ToString();
List<Claim> authTicket = null;
try
{
authTicket = await GetAuthTicketAsync(code);
}
catch (Exception ex)
{
return AuthenticateResult.Fail(ex.Message ?? "未知错误");
}
//成功
var result = AuthenticateResult.Success(TicketConver(authTicket));
return result;
}
}
}

View File

@@ -1,23 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
/// <summary>
/// Contains constants specific to the <see cref="QQAuthenticationHandler"/>.
/// </summary>
public static class QQAuthenticationConstants
{
public static class Claims
{
public const string AvatarFullUrl = "urn:qq:avatar_full";
public const string AvatarUrl = "urn:qq:avatar";
public const string PictureFullUrl = "urn:qq:picture_full";
public const string PictureMediumUrl = "urn:qq:picture_medium";
public const string PictureUrl = "urn:qq:picture";
public const string UnionId = "urn:qq:unionid";
}
}

View File

@@ -1,53 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
/// <summary>
/// Default values for QQ authentication.
/// </summary>
public static class QQAuthenticationDefaults
{
/// <summary>
/// Default value for <see cref="AuthenticationScheme.Name"/>.
/// </summary>
public const string AuthenticationScheme = "QQ";
/// <summary>
/// Default value for <see cref="AuthenticationScheme.DisplayName"/>.
/// </summary>
public static readonly string DisplayName = "QQ";
/// <summary>
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
/// </summary>
public static readonly string Issuer = "QQ";
/// <summary>
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
/// </summary>
public static readonly string CallbackPath = "/signin-qq";
/// <summary>
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
/// </summary>
public static readonly string AuthorizationEndpoint = "https://graph.qq.com/oauth2.0/authorize";
/// <summary>
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
/// </summary>
public static readonly string TokenEndpoint = "https://graph.qq.com/oauth2.0/token";
/// <summary>
/// Default value for <see cref="QQAuthenticationOptions.UserIdentificationEndpoint"/>.
/// </summary>
public static readonly string UserIdentificationEndpoint = "https://graph.qq.com/oauth2.0/me";
/// <summary>
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
/// </summary>
public static readonly string UserInformationEndpoint = "https://graph.qq.com/user/get_user_info";
}

View File

@@ -1,77 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
/// <summary>
/// Extension methods to add QQ authentication capabilities to an HTTP application pipeline.
/// </summary>
public static class QQAuthenticationExtensions
{
/// <summary>
/// Adds <see cref="QQAuthenticationHandler"/> to the specified
/// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities.
/// </summary>
/// <param name="builder">The authentication builder.</param>
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
public static AuthenticationBuilder AddQQ([NotNull] this AuthenticationBuilder builder)
{
return builder.AddQQ(QQAuthenticationDefaults.AuthenticationScheme, options => { });
}
/// <summary>
/// Adds <see cref="QQAuthenticationHandler"/> to the specified
/// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities.
/// </summary>
/// <param name="builder">The authentication builder.</param>
/// <param name="configuration">The delegate used to configure the OpenID 2.0 options.</param>
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
public static AuthenticationBuilder AddQQ(
[NotNull] this AuthenticationBuilder builder,
[NotNull] Action<QQAuthenticationOptions> configuration)
{
return builder.AddQQ(QQAuthenticationDefaults.AuthenticationScheme, configuration);
}
/// <summary>
/// Adds <see cref="QQAuthenticationHandler"/> to the specified
/// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities.
/// </summary>
/// <param name="builder">The authentication builder.</param>
/// <param name="scheme">The authentication scheme associated with this instance.</param>
/// <param name="configuration">The delegate used to configure the QQ options.</param>
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
public static AuthenticationBuilder AddQQ(
[NotNull] this AuthenticationBuilder builder,
[NotNull] string scheme,
[NotNull] Action<QQAuthenticationOptions> configuration)
{
return builder.AddQQ(scheme, QQAuthenticationDefaults.DisplayName, configuration);
}
/// <summary>
/// Adds <see cref="QQAuthenticationHandler"/> to the specified
/// <see cref="AuthenticationBuilder"/>, which enables QQ authentication capabilities.
/// </summary>
/// <param name="builder">The authentication builder.</param>
/// <param name="scheme">The authentication scheme associated with this instance.</param>
/// <param name="caption">The optional display name associated with this instance.</param>
/// <param name="configuration">The delegate used to configure the QQ options.</param>
/// <returns>The <see cref="AuthenticationBuilder"/>.</returns>
public static AuthenticationBuilder AddQQ(
[NotNull] this AuthenticationBuilder builder,
[NotNull] string scheme,
[CanBeNull] string caption,
[NotNull] Action<QQAuthenticationOptions> configuration)
{
return builder.AddScheme<QQAuthenticationOptions, QQAuthenticationHandler>(scheme, caption, configuration);
}
}

View File

@@ -1,64 +0,0 @@
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using static Yi.Framework.AspNetCore.Authentication.OAuth.QQ.QQAuthenticationConstants;
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ
{
public class QQAuthenticationHandler : OauthAuthenticationHandler<QQAuthenticationOptions>
{
public QQAuthenticationHandler(IOptionsMonitor<QQAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder, httpClientFactory)
{
}
public override string AuthenticationSchemeNmae => QQAuthenticationDefaults.AuthenticationScheme;
protected override async Task<List<Claim>> GetAuthTicketAsync(string code)
{
//获取 accessToken
var tokenQueryKv = new List<KeyValuePair<string, string?>>()
{
new KeyValuePair<string, string?>("grant_type","authorization_code"),
new KeyValuePair<string, string?>("client_id",Options.ClientId),
new KeyValuePair<string, string?>("client_secret",Options.ClientSecret),
new KeyValuePair<string, string?>("redirect_uri",Options.RedirectUri),
new KeyValuePair<string, string?>("fmt","json"),
new KeyValuePair<string, string?>("need_openid","1"),
new KeyValuePair<string, string?>("code",code)
};
var tokenModel = await SendHttpRequestAsync<QQAuthticationcationTokenResponse>(QQAuthenticationDefaults.TokenEndpoint, tokenQueryKv);
//获取 userInfo
var userInfoQueryKv = new List<KeyValuePair<string, string?>>()
{
new KeyValuePair<string, string?>("access_token",tokenModel.access_token),
new KeyValuePair<string, string?>("oauth_consumer_key",Options.ClientId),
new KeyValuePair<string, string?>("openid",tokenModel.openid),
};
var userInfoMdoel = await SendHttpRequestAsync<QQAuthticationcationUserInfoResponse>(QQAuthenticationDefaults.UserInformationEndpoint, userInfoQueryKv);
List<Claim> claims = new List<Claim>()
{
new Claim(Claims.AvatarFullUrl, userInfoMdoel.figureurl_qq_2),
new Claim(Claims.AvatarUrl, userInfoMdoel.figureurl_qq_1),
new Claim(Claims.PictureFullUrl, userInfoMdoel.figureurl_2),
new Claim(Claims.PictureMediumUrl, userInfoMdoel.figureurl_qq_1),
new Claim(Claims.PictureUrl, userInfoMdoel.figureurl),
new Claim(AuthenticationConstants.OpenId, tokenModel.openid),
new Claim(AuthenticationConstants.Name, userInfoMdoel.nickname),
new Claim(AuthenticationConstants.AccessToken, tokenModel.access_token),
};
return claims;
}
}
}

View File

@@ -1,49 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using static Yi.Framework.AspNetCore.Authentication.OAuth.QQ.QQAuthenticationConstants;
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
/// <summary>
/// Defines a set of options used by <see cref="QQAuthenticationHandler"/>.
/// </summary>
public class QQAuthenticationOptions : AuthenticationOAuthOptions
{
public QQAuthenticationOptions()
{
ClaimsIssuer = QQAuthenticationDefaults.Issuer;
CallbackPath = QQAuthenticationDefaults.CallbackPath;
AuthorizationEndpoint = QQAuthenticationDefaults.AuthorizationEndpoint;
TokenEndpoint = QQAuthenticationDefaults.TokenEndpoint;
UserIdentificationEndpoint = QQAuthenticationDefaults.UserIdentificationEndpoint;
UserInformationEndpoint = QQAuthenticationDefaults.UserInformationEndpoint;
Scope.Add("get_user_info");
ClaimActions.MapJsonKey(ClaimTypes.Name, "nickname");
ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender");
ClaimActions.MapJsonKey(Claims.PictureUrl, "figureurl");
ClaimActions.MapJsonKey(Claims.PictureMediumUrl, "figureurl_1");
ClaimActions.MapJsonKey(Claims.PictureFullUrl, "figureurl_2");
ClaimActions.MapJsonKey(Claims.AvatarUrl, "figureurl_qq_1");
ClaimActions.MapJsonKey(Claims.AvatarFullUrl, "figureurl_qq_2");
}
/// <summary>
/// Gets or sets if the union Id (the primary key of an owner for different apps of the QQ platform) should be put into the user claims.
/// </summary>
public bool ApplyForUnionId { get; set; }
/// <summary>
/// Gets or sets the URL of the user identification endpoint (a.k.a. the "OpenID endpoint").
/// </summary>
public string UserIdentificationEndpoint { get; set; }
}

View File

@@ -1,89 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.AspNetCore.Authentication.OAuth.QQ
{
public class QQAuthticationcationTokenResponse
{
public string access_token { get; set; }
public string expires_in { get; set; }
public string refresh_token { get; set; }
public string openid { get; set; }
}
public class QQAuthticationcationOpenIdResponse
{
public string client_id { get; set; }
public string openid { get; set; }
}
public class QQAuthticationcationUserInfoResponse
{
// 返回码
public int ret { get; set; }
// 如果ret<0会有相应的错误信息提示
// 返回数据全部用UTF-8编码
public string msg { get; set; }
// 判断是否有数据丢失
// 0或者不返回没有数据丢失可以缓存
// 1有部分数据丢失或错误不要缓存
public int is_lost { get; set; }
// 用户在QQ空间的昵称
public string nickname { get; set; }
// 大小为30x30像素的QQ空间头像URL
public string figureurl { get; set; }
// 大小为50x50像素的QQ空间头像URL
public string figureurl_1 { get; set; }
// 大小为100x100像素的QQ空间头像URL
public string figureurl_2 { get; set; }
// 大小为40x40像素的QQ头像URL
public string figureurl_qq_1 { get; set; }
// 大小为100x100像素的QQ头像URL
// 需要注意不是所有的用户都拥有QQ的100x100的头像但40x40像素则是一定会有
public string figureurl_qq_2 { get; set; }
// 性别。如果获取不到则默认返回"男"
public string gender { get; set; }
// 性别类型。默认返回2
public int gender_type { get; set; }
// 省
public string province { get; set; }
// 市
public string city { get; set; }
// 年
public int year { get; set; }
// 星座
public string constellation { get; set; }
// 标识用户是否为黄钻用户
public int is_yellow_vip { get; set; }
// 黄钻等级
public int yellow_vip_level { get; set; }
// 是否为年费黄钻用户
public int is_yellow_year_vip { get; set; }
}
}

View File

@@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,20 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Yi.Framework.Core;
namespace Yi.Framework.AspNetCore.Authentication.OAuth
{
/// <summary>
/// 本模块轮子来自 AspNet.Security.OAuth.QQ;
/// </summary>
[DependsOn(typeof(YiFrameworkAspNetCoreModule))]
public class YiFrameworkAspNetCoreAuthenticationOAuthModule:AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var service = context.Services;
service.AddHttpClient();
}
}
}

View File

@@ -1,16 +0,0 @@
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares;
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder
{
public static class ApiInfoBuilderExtensions
{
public static IApplicationBuilder UseYiApiHandlinge([NotNull] this IApplicationBuilder app)
{
app.UseMiddleware<ApiInfoMiddleware>();
return app;
}
}
}

View File

@@ -1,53 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc;
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder
{
public static class SwaggerBuilderExtensons
{
public static IApplicationBuilder UseYiSwagger(this IApplicationBuilder app, params SwaggerModel[] swaggerModels)
{
var mvcOptions = app.ApplicationServices.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>().Value;
app.UseSwagger();
app.UseSwaggerUI(c =>
{
foreach (var setting in mvcOptions.ConventionalControllers.ConventionalControllerSettings)
{
c.SwaggerEndpoint($"/swagger/{setting.RemoteServiceName}/swagger.json", setting.RemoteServiceName);
}
if (mvcOptions.ConventionalControllers.ConventionalControllerSettings.Count==0&&swaggerModels.Length == 0)
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Yi.Framework");
}
else
{
foreach (var k in swaggerModels)
{
c.SwaggerEndpoint(k.Url, k.Name);
}
}
});
return app;
}
}
public class SwaggerModel
{
public SwaggerModel(string name)
{
this.Name = name;
this.Url = "/swagger/v1/swagger.json";
}
public SwaggerModel(string url, string name)
{
this.Url = url;
this.Name = name;
}
public string Url { get; set; }
public string Name { get; set; }
}
}

View File

@@ -1,39 +0,0 @@
using System.Diagnostics;
using System.Net.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
using Yi.Framework.Core.Extensions;
using static System.Net.WebRequestMethods;
namespace Yi.Framework.AspNetCore.Microsoft.AspNetCore.Middlewares
{
[DebuggerStepThrough]
public class ApiInfoMiddleware : IMiddleware, ITransientDependency
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
context.Response.OnStarting([DebuggerStepThrough] () =>
{
if (context.Response.StatusCode == StatusCodes.Status200OK
&& context.Response.Headers["Content-Type"].ToString() == "application/vnd.ms-excel")
{
context.FileAttachmentHandle($"{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.xlsx");
}
if (context.Response.StatusCode == StatusCodes.Status200OK &&
context.Response.Headers["Content-Type"].ToString() == "application/x-zip-compressed")
{
context.FileAttachmentHandle($"{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.zip");
}
return Task.CompletedTask;
});
await next(context);
}
}
}

View File

@@ -1,157 +0,0 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Volo.Abp.AspNetCore.Mvc;
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
{
public static class SwaggerAddExtensions
{
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services, Action<SwaggerGenOptions>? action=null)
{
var serviceProvider = services.BuildServiceProvider();
var mvcOptions = serviceProvider.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>();
var mvcSettings = mvcOptions.Value.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
services.AddAbpSwaggerGen(
options =>
{
if (action is not null)
{
action.Invoke(options);
}
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
{
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
{
options.SwaggerDoc(setting.RemoteServiceName, new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
}
}
// 根据分组名称过滤 API 文档
options.DocInclusionPredicate((docName, apiDesc) =>
{
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
var settingOrNull = mvcSettings.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly).FirstOrDefault();
if (settingOrNull is not null)
{
return docName == settingOrNull.RemoteServiceName;
}
}
return false;
});
options.CustomSchemaIds(type => type.FullName);
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
if (basePath is not null)
{
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
{
options.IncludeXmlComments(item, true);
}
}
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
{
Description = "直接输入Token即可",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer"
});
var scheme = new OpenApiSecurityScheme()
{
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
};
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
[scheme] = new string[0]
});
options.OperationFilter<AddRequiredHeaderParameter>();
options.SchemaFilter<EnumSchemaFilter>();
}
);
return services;
}
}
/// <summary>
/// Swagger文档枚举字段显示枚举属性和枚举值,以及枚举描述
/// </summary>
public class EnumSchemaFilter : ISchemaFilter
{
/// <summary>
/// 实现接口
/// </summary>
/// <param name="model"></param>
/// <param name="context"></param>
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type.IsEnum)
{
model.Enum.Clear();
model.Type = "string";
model.Format = null;
StringBuilder stringBuilder = new StringBuilder();
Enum.GetNames(context.Type)
.ToList()
.ForEach(name =>
{
Enum e = (Enum)Enum.Parse(context.Type, name);
var descrptionOrNull = GetEnumDescription(e);
model.Enum.Add(new OpenApiString(name));
stringBuilder.Append($"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
});
model.Description= stringBuilder.ToString();
}
}
private static string? GetEnumDescription(Enum value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : null;
}
}
public class AddRequiredHeaderParameter : IOperationFilter
{
public static string HeaderKey { get; set; } = "__tenant";
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (operation.Parameters == null)
operation.Parameters = new List<OpenApiParameter>();
operation.Parameters.Add(new OpenApiParameter
{
Name = HeaderKey,
In = ParameterLocation.Header,
Required = false,
AllowEmptyValue = true,
Description="租户id或者租户名称可空为默认租户"
});
}
}
}

View File

@@ -1,73 +0,0 @@
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Reflection;
namespace Yi.Framework.AspNetCore.Mvc
{
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IConventionalRouteBuilder))]
public class YiConventionalRouteBuilder : ConventionalRouteBuilder
{
public YiConventionalRouteBuilder(IOptions<AbpConventionalControllerOptions> options) : base(options)
{
}
public override string Build(
string rootPath,
string controllerName,
ActionModel action,
string httpMethod,
[CanBeNull] ConventionalControllerSetting configuration)
{
var apiRoutePrefix = GetApiRoutePrefix(action, configuration);
var controllerNameInUrl =
NormalizeUrlControllerName(rootPath, controllerName, action, httpMethod, configuration);
var url = $"{rootPath}/{NormalizeControllerNameCase(controllerNameInUrl, configuration)}";
//Add {id} path if needed
var idParameterModel = action.Parameters.FirstOrDefault(p => p.ParameterName == "id");
if (idParameterModel != null)
{
if (TypeHelper.IsPrimitiveExtended(idParameterModel.ParameterType, includeEnums: true))
{
url += "/{id}";
}
else
{
var properties = idParameterModel
.ParameterType
.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
url += "/{" + NormalizeIdPropertyNameCase(property, configuration) + "}";
}
}
}
//Add action name if needed
var actionNameInUrl = NormalizeUrlActionName(rootPath, controllerName, action, httpMethod, configuration);
if (!actionNameInUrl.IsNullOrEmpty())
{
url += $"/{NormalizeActionNameCase(actionNameInUrl, configuration)}";
//Add secondary Id
var secondaryIds = action.Parameters
.Where(p => p.ParameterName.EndsWith("Id", StringComparison.Ordinal)).ToList();
if (secondaryIds.Count == 1)
{
url += $"/{{{NormalizeSecondaryIdNameCase(secondaryIds[0], configuration)}}}";
}
}
return url;
}
}
}

View File

@@ -1,96 +0,0 @@
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.AspNetCore;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Reflection;
namespace Yi.Framework.AspNetCore.Mvc
{
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IAbpServiceConvention))]
public class YiServiceConvention : AbpServiceConvention
{
public YiServiceConvention(IOptions<AbpAspNetCoreMvcOptions> options, IConventionalRouteBuilder conventionalRouteBuilder) : base(options, conventionalRouteBuilder)
{
}
protected override void ConfigureSelector(string rootPath, string controllerName, ActionModel action, ConventionalControllerSetting? configuration)
{
RemoveEmptySelectors(action.Selectors);
var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault<RemoteServiceAttribute>(action.ActionMethod);
if (remoteServiceAtt != null && !remoteServiceAtt.IsEnabledFor(action.ActionMethod))
{
return;
}
if (!action.Selectors.Any())
{
AddAbpServiceSelector(rootPath, controllerName, action, configuration);
}
else
{
NormalizeSelectorRoutes(rootPath, controllerName, action, configuration);
}
}
protected override void AddAbpServiceSelector(string rootPath, string controllerName, ActionModel action, ConventionalControllerSetting? configuration)
{
base.AddAbpServiceSelector(rootPath, controllerName, action, configuration);
}
protected override void NormalizeSelectorRoutes(string rootPath, string controllerName, ActionModel action, ConventionalControllerSetting? configuration)
{
foreach (var selector in action.Selectors)
{
var httpMethod = selector.ActionConstraints
.OfType<HttpMethodActionConstraint>()
.FirstOrDefault()?
.HttpMethods?
.FirstOrDefault();
if (httpMethod == null)
{
httpMethod = SelectHttpMethod(action, configuration);
}
if (selector.AttributeRouteModel == null)
{
selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel(rootPath, controllerName, action, httpMethod, configuration);
}
else
{
var template = selector.AttributeRouteModel.Template;
if (!template.StartsWith("/"))
{
var route = $"{rootPath}/{template}";
selector.AttributeRouteModel.Template = route;
}
}
if (!selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Any())
{
selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod }));
}
}
}
}
}

View File

@@ -1,49 +0,0 @@
namespace Yi.Framework.AspNetCore
{
[Serializable]
public class RemoteServiceSuccessInfo
{
/// <summary>
/// Creates a new instance of <see cref="RemoteServiceSuccessInfo"/>.
/// </summary>
public RemoteServiceSuccessInfo()
{
}
/// <summary>
/// Creates a new instance of <see cref="RemoteServiceSuccessInfo"/>.
/// </summary>
/// <param name="code">Error code</param>
/// <param name="details">Error details</param>
/// <param name="message">Error message</param>
/// <param name="data">Error data</param>
public RemoteServiceSuccessInfo(string message, string? details = null, string? code = null, object? data = null)
{
Message = message;
Details = details;
Code = code;
Data = data;
}
/// <summary>
/// code.
/// </summary>
public string? Code { get; set; }
/// <summary>
/// message.
/// </summary>
public string? Message { get; set; }
/// <summary>
/// details.
/// </summary>
public string? Details { get; set; }
/// <summary>
/// data.
/// </summary>
public object? Data { get; set; }
}
}

View File

@@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<ItemGroup>
<Compile Remove="Cors\**" />
<EmbeddedResource Remove="Cors\**" />
<None Remove="Cors\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Json" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Swashbuckle" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,27 +0,0 @@
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Linq;
using Swashbuckle.AspNetCore.SwaggerGen;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity;
using Yi.Framework.AspNetCore.Mvc;
using Yi.Framework.Core;
namespace Yi.Framework.AspNetCore
{
[DependsOn(typeof(YiFrameworkCoreModule)
)]
public class YiFrameworkAspNetCoreModule : AbpModule
{
}
}

View File

@@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FreeRedis;
namespace Yi.Framework.Caching.FreeRedis
{
/// <summary>
/// 便于转到定义
/// </summary>
public class FreeSqlOptions: ConnectionStringBuilder
{
}
}

View File

@@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FreeRedis" Version="1.2.14" />
<PackageReference Include="FreeRedis.DistributedCache" Version="1.2.5" />
<PackageReference Include="Volo.Abp.Caching" Version="$(AbpVersion)" />
</ItemGroup>
</Project>

View File

@@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace Yi.Framework.Caching.FreeRedis
{
[Dependency(ReplaceServices =true)]
public class YiDistributedCacheKeyNormalizer : IDistributedCacheKeyNormalizer, ITransientDependency
{
protected ICurrentTenant CurrentTenant { get; }
protected AbpDistributedCacheOptions DistributedCacheOptions { get; }
public YiDistributedCacheKeyNormalizer(
ICurrentTenant currentTenant,
IOptions<AbpDistributedCacheOptions> distributedCacheOptions)
{
CurrentTenant = currentTenant;
DistributedCacheOptions = distributedCacheOptions.Value;
}
public virtual string NormalizeKey(DistributedCacheKeyNormalizeArgs args)
{
var normalizedKey = $"{DistributedCacheOptions.KeyPrefix}{args.Key}";
//if (!args.IgnoreMultiTenancy && CurrentTenant.Id.HasValue)
//{
// normalizedKey = $"t:{CurrentTenant.Id.Value},{normalizedKey}";
//}
return normalizedKey;
}
}
}

View File

@@ -1,32 +0,0 @@
using FreeRedis;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Caching;
namespace Yi.Framework.Caching.FreeRedis
{
/// <summary>
/// 此模块得益于FreeRedis作者支持IDistributedCache使用湿滑
/// </summary>
[DependsOn(typeof(AbpCachingModule))]
public class YiFrameworkCachingFreeRedisModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var redisEnabled = configuration["Redis:IsEnabled"];
if (redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled))
{
var redisConfiguration = configuration["Redis:Configuration"];
RedisClient redisClient = new RedisClient(redisConfiguration);
context.Services.AddSingleton<IRedisClient>(redisClient);
context.Services.Replace(ServiceDescriptor.Singleton<IDistributedCache>(new
DistributedCache(redisClient)));
}
}
}
}

View File

@@ -1,72 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Enums
{
public enum QueryOperatorEnum
{
/// <summary>
/// 相等
/// </summary>
Equal,
/// <summary>
/// 匹配
/// </summary>
Like,
/// <summary>
/// 大于
/// </summary>
GreaterThan,
/// <summary>
/// 大于或等于
/// </summary>
GreaterThanOrEqual,
/// <summary>
/// 小于
/// </summary>
LessThan,
/// <summary>
/// 小于或等于
/// </summary>
LessThanOrEqual,
/// <summary>
/// 等于集合
/// </summary>
In,
/// <summary>
/// 不等于集合
/// </summary>
NotIn,
/// <summary>
/// 左边匹配
/// </summary>
LikeLeft,
/// <summary>
/// 右边匹配
/// </summary>
LikeRight,
/// <summary>
/// 不相等
/// </summary>
NoEqual,
/// <summary>
/// 为空或空
/// </summary>
IsNullOrEmpty,
/// <summary>
/// 不为空
/// </summary>
IsNot,
/// <summary>
/// 不匹配
/// </summary>
NoLike,
/// <summary>
/// 时间段 值用 "|" 隔开
/// </summary>
DateRange
}
}

View File

@@ -1,100 +0,0 @@
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
namespace Yi.Framework.Core.Extensions
{
public static class HttpContextExtensions
{
/// <summary>
/// 设置文件下载名称
/// </summary>
/// <param name="httpContext"></param>
/// <param name="fileName"></param>
public static void FileInlineHandle(this HttpContext httpContext, string fileName)
{
string encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));
httpContext.Response.Headers.Add("Content-Disposition", "inline;filename=" + encodeFilename);
}
/// <summary>
/// 设置文件附件名称
/// </summary>
/// <param name="httpContext"></param>
/// <param name="fileName"></param>
public static void FileAttachmentHandle(this HttpContext httpContext, string fileName)
{
string encodeFilename = System.Web.HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));
httpContext.Response.Headers.Add("Content-Disposition", "attachment;filename=" + encodeFilename);
}
/// <summary>
/// 获取语言种类
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
public static string GetLanguage(this HttpContext httpContext)
{
string res = "zh-CN";
var str = httpContext.Request.Headers["Accept-Language"].FirstOrDefault();
if (str is not null)
{
res = str.Split(",")[0];
}
return res;
}
/// <summary>
/// 判断是否为异步请求
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static bool IsAjaxRequest(this HttpRequest request)
{
string header = request.Headers["X-Requested-With"];
return "XMLHttpRequest".Equals(header);
}
/// <summary>
/// 获取客户端IP
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static string GetClientIp(this HttpContext context)
{
if (context == null) return "";
var result = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
if (string.IsNullOrEmpty(result))
{
result = context.Connection.RemoteIpAddress?.ToString();
}
if (string.IsNullOrEmpty(result) || result.Contains("::1"))
result = "127.0.0.1";
result = result.Replace("::ffff:", "127.0.0.1");
//Ip规则校验
var regResult = Regex.IsMatch(result, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
result = regResult ? result : "127.0.0.1";
return result;
}
/// <summary>
/// 获取浏览器标识
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static string GetUserAgent(this HttpContext context)
{
return context.Request.Headers["User-Agent"];
}
public static string[]? GetUserPermissions(this HttpContext context, string permissionsName)
{
return context.User.Claims.Where(x => x.Type == permissionsName).Select(x => x.Value).ToArray();
}
}
}

View File

@@ -1,94 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public static class AssemblyHelper
{
/// <summary>
/// 此处统一获取程序集,排除微软内部相关
/// </summary>
/// <returns></returns>
public static Assembly[] GetAllLoadAssembly()
{
return AppDomain.CurrentDomain.GetAssemblies();
}
public static List<Assembly> GetReferanceAssemblies(this AppDomain domain)
{
var list = new List<Assembly>();
domain.GetAssemblies().ToList().ForEach(i =>
{
GetReferanceAssemblies(i, list);
});
return list;
}
private static void GetReferanceAssemblies(Assembly assembly, List<Assembly> list)
{
assembly.GetReferencedAssemblies().ToList().ForEach(i =>
{
var ass = Assembly.Load(i);
if (!list.Contains(ass))
{
list.Add(ass);
GetReferanceAssemblies(ass, list);
}
});
}
public static List<Type> GetClass(string assemblyFile, string? className = null, string? spaceName = null)
{
Assembly assembly = Assembly.Load(assemblyFile);
return assembly.GetTypes().Where(m => m.IsClass
&& className == null ? true : m.Name == className
&& spaceName == null ? true : m.Namespace == spaceName
&& !m.Name.StartsWith("<>")
).ToList();
}
public static List<Type> GetClassByParentClass(string assemblyFile, Type type)
{
Assembly assembly = Assembly.Load(assemblyFile);
List<Type> resList = new List<Type>();
List<Type> typeList = assembly.GetTypes().Where(m => m.IsClass).ToList();
foreach (var t in typeList)
{
var data = t.BaseType;
if (data == type)
{
resList.Add(t);
}
}
return resList;
}
public static List<Type> GetClassByInterfaces(string assemblyFile, Type type)
{
Assembly assembly = Assembly.Load(assemblyFile);
List<Type> resList = new List<Type>();
List<Type> typeList = assembly.GetTypes().Where(m => m.IsClass).ToList();
foreach (var t in typeList)
{
var data = t.GetInterfaces();
if (data.Contains(type))
{
resList.Add(t);
}
}
return resList;
}
}
}

View File

@@ -1,329 +0,0 @@
using System.Runtime.InteropServices;
using Newtonsoft.Json;
namespace Yi.Framework.Core.Helper
{
public class ComputerHelper
{
/// <summary>
/// 将object转换为long若转换失败则返回0。不抛出异常。
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private static long ParseToLong( object obj)
{
try
{
return long.Parse(obj.ToString());
}
catch
{
return 0L;
}
}
/// <summary>
/// 将string转换为DateTime若转换失败则返回日期最小值。不抛出异常。
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private static DateTime ParseToDateTime( string str)
{
try
{
if (string.IsNullOrWhiteSpace(str))
{
return DateTime.MinValue;
}
if (str.Contains("-") || str.Contains("/"))
{
return DateTime.Parse(str);
}
else
{
int length = str.Length;
switch (length)
{
case 4:
return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture);
case 6:
return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture);
case 8:
return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture);
case 10:
return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture);
case 12:
return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture);
case 14:
return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
default:
return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);
}
}
}
catch
{
return DateTime.MinValue;
}
}
private static double ParseToDouble(object obj)
{
try
{
return double.Parse(obj.ToString());
}
catch
{
return 0;
}
}
/// <summary>
/// 内存使用情况
/// </summary>
/// <returns></returns>
public static MemoryMetrics GetComputerInfo()
{
try
{
MemoryMetricsClient client = new();
MemoryMetrics memoryMetrics = IsUnix() ? client.GetUnixMetrics() : client.GetWindowsMetrics();
memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB";
memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB";
memoryMetrics.TotalRAM = Math.Round(memoryMetrics.Total / 1024, 2) + "GB";
memoryMetrics.RAMRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + "%";
memoryMetrics.CPURate = Math.Ceiling(ParseToDouble(GetCPURate())) + "%";
return memoryMetrics;
}
catch (Exception ex)
{
Console.WriteLine("获取内存使用出错msg=" + ex.Message + "," + ex.StackTrace);
}
return new MemoryMetrics();
}
/// <summary>
/// 获取内存大小
/// </summary>
/// <returns></returns>
public static List<DiskInfo> GetDiskInfos()
{
List<DiskInfo> diskInfos = new();
if (IsUnix())
{
try
{
string output = ShellHelper.Bash("df -m / | awk '{print $2,$3,$4,$5,$6}'");
var arr = output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
if (arr.Length == 0) return diskInfos;
var rootDisk = arr[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
if (rootDisk == null || rootDisk.Length == 0)
{
return diskInfos;
}
DiskInfo diskInfo = new()
{
DiskName = "/",
TotalSize = long.Parse(rootDisk[0]) / 1024,
Used = long.Parse(rootDisk[1]) / 1024,
AvailableFreeSpace = long.Parse(rootDisk[2]) / 1024,
AvailablePercent = decimal.Parse(rootDisk[3].Replace("%", ""))
};
diskInfos.Add(diskInfo);
}
catch (Exception ex)
{
Console.WriteLine("获取磁盘信息出错了" + ex.Message);
}
}
else
{
var driv = DriveInfo.GetDrives();
foreach (var item in driv)
{
try
{
var obj = new DiskInfo()
{
DiskName = item.Name,
TypeName = item.DriveType.ToString(),
TotalSize = item.TotalSize / 1024 / 1024 / 1024,
AvailableFreeSpace = item.AvailableFreeSpace / 1024 / 1024 / 1024,
};
obj.Used = obj.TotalSize - obj.AvailableFreeSpace;
obj.AvailablePercent = decimal.Ceiling(obj.Used / (decimal)obj.TotalSize * 100);
diskInfos.Add(obj);
}
catch (Exception ex)
{
Console.WriteLine("获取磁盘信息出错了" + ex.Message);
continue;
}
}
}
return diskInfos;
}
public static bool IsUnix()
{
var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
return isUnix;
}
public static string GetCPURate()
{
string cpuRate;
if (IsUnix())
{
string output = ShellHelper.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'");
cpuRate = output.Trim();
}
else
{
string output = ShellHelper.Cmd("wmic", "cpu get LoadPercentage");
cpuRate = output.Replace("LoadPercentage", string.Empty).Trim();
}
return cpuRate;
}
/// <summary>
/// 获取系统运行时间
/// </summary>
/// <returns></returns>
public static string GetRunTime()
{
string runTime = string.Empty;
try
{
if (IsUnix())
{
string output = ShellHelper.Bash("uptime -s").Trim();
runTime = DateTimeHelper.FormatTime(ParseToLong((DateTime.Now - ParseToDateTime(output)).TotalMilliseconds.ToString().Split('.')[0]));
}
else
{
string output = ShellHelper.Cmd("wmic", "OS get LastBootUpTime/Value");
string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
if (outputArr.Length == 2)
{
runTime = DateTimeHelper.FormatTime(ParseToLong((DateTime.Now - ParseToDateTime( outputArr[1].Split('.')[0])).TotalMilliseconds.ToString().Split('.')[0]));
}
}
}
catch (Exception ex)
{
Console.WriteLine("获取runTime出错" + ex.Message);
}
return runTime;
}
}
/// <summary>
/// 内存信息
/// </summary>
public class MemoryMetrics
{
[JsonIgnore]
public double Total { get; set; }
[JsonIgnore]
public double Used { get; set; }
[JsonIgnore]
public double Free { get; set; }
public string UsedRam { get; set; }
/// <summary>
/// CPU使用率%
/// </summary>
public string CPURate { get; set; }
/// <summary>
/// 总内存 GB
/// </summary>
public string TotalRAM { get; set; }
/// <summary>
/// 内存使用率 %
/// </summary>
public string RAMRate { get; set; }
/// <summary>
/// 空闲内存
/// </summary>
public string FreeRam { get; set; }
}
public class DiskInfo
{
/// <summary>
/// 磁盘名
/// </summary>
public string DiskName { get; set; }
public string TypeName { get; set; }
public long TotalFree { get; set; }
public long TotalSize { get; set; }
/// <summary>
/// 已使用
/// </summary>
public long Used { get; set; }
/// <summary>
/// 可使用
/// </summary>
public long AvailableFreeSpace { get; set; }
public decimal AvailablePercent { get; set; }
}
public class MemoryMetricsClient
{
#region
/// <summary>
/// windows系统获取内存信息
/// </summary>
/// <returns></returns>
public MemoryMetrics GetWindowsMetrics()
{
string output = ShellHelper.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value");
var metrics = new MemoryMetrics();
var lines = output.Trim().Split('\n', (char)StringSplitOptions.RemoveEmptyEntries);
if (lines.Length <= 0) return metrics;
var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries);
metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0);
metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);//m
metrics.Used = metrics.Total - metrics.Free;
return metrics;
}
/// <summary>
/// Unix系统获取
/// </summary>
/// <returns></returns>
public MemoryMetrics GetUnixMetrics()
{
string output = ShellHelper.Bash("free -m | awk '{print $2,$3,$4,$5,$6}'");
var metrics = new MemoryMetrics();
var lines = output.Split('\n', (char)StringSplitOptions.RemoveEmptyEntries);
if (lines.Length <= 0) return metrics;
if (lines != null && lines.Length > 0)
{
var memory = lines[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries);
if (memory.Length >= 3)
{
metrics.Total = double.Parse(memory[0]);
metrics.Used = double.Parse(memory[1]);
metrics.Free = double.Parse(memory[2]);//m
}
}
return metrics;
}
#endregion
}
}

View File

@@ -1,139 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Yi.Framework.Core.Helper
{
public class DateTimeHelper
{
/// <summary>
///
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime GetBeginTime(DateTime? dateTime, int days = 0)
{
if (dateTime == DateTime.MinValue || dateTime == null)
{
return DateTime.Now.AddDays(days);
}
return dateTime ?? DateTime.Now;
}
#region
/// <summary>
/// 时间戳转本地时间-时间戳精确到秒
/// </summary>
public static DateTime ToLocalTimeDateBySeconds(long unix)
{
var dto = DateTimeOffset.FromUnixTimeSeconds(unix);
return dto.ToLocalTime().DateTime;
}
/// <summary>
/// 时间转时间戳Unix-时间戳精确到秒
/// </summary>
public static long ToUnixTimestampBySeconds(DateTime dt)
{
DateTimeOffset dto = new DateTimeOffset(dt);
return dto.ToUnixTimeSeconds();
}
/// <summary>
/// 时间戳转本地时间-时间戳精确到毫秒
/// </summary>
public static DateTime ToLocalTimeDateByMilliseconds(long unix)
{
var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix);
return dto.ToLocalTime().DateTime;
}
/// <summary>
/// 时间转时间戳Unix-时间戳精确到毫秒
/// </summary>
public static long ToUnixTimestampByMilliseconds(DateTime dt)
{
DateTimeOffset dto = new DateTimeOffset(dt);
return dto.ToUnixTimeMilliseconds();
}
#endregion
#region
/// <summary>
/// 毫秒转天时分秒
/// </summary>
/// <param name="ms"></param>
/// <returns></returns>
public static string FormatTime(long ms)
{
int ss = 1000;
int mi = ss * 60;
int hh = mi * 60;
int dd = hh * 24;
long day = ms / dd;
long hour = (ms - day * dd) / hh;
long minute = (ms - day * dd - hour * hh) / mi;
long second = (ms - day * dd - hour * hh - minute * mi) / ss;
long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
string sDay = day < 10 ? "0" + day : "" + day; //天
string sHour = hour < 10 ? "0" + hour : "" + hour;//小时
string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟
string sSecond = second < 10 ? "0" + second : "" + second;//秒
string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒
sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond;
return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond);
}
#endregion
#region unix时间戳
/// <summary>
/// 获取unix时间戳
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static long GetUnixTimeStamp(DateTime dt)
{
long unixTime = ((DateTimeOffset)dt).ToUnixTimeMilliseconds();
return unixTime;
}
#endregion
#region
public static DateTime GetDayMinDate(DateTime dt)
{
DateTime min = new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0);
return min;
}
#endregion
#region
public static DateTime GetDayMaxDate(DateTime dt)
{
DateTime max = new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59);
return max;
}
#endregion
#region
public static string FormatDateTime(DateTime? dt)
{
if (dt != null)
{
if (dt.Value.Year == DateTime.Now.Year)
{
return dt.Value.ToString("MM-dd HH:mm");
}
else
{
return dt.Value.ToString("yyyy-MM-dd HH:mm");
}
}
return string.Empty;
}
#endregion
}
}

View File

@@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public static class EnumHelper
{
public static New EnumToEnum<New>(this object oldEnum)
{
if (oldEnum is null)
{
throw new ArgumentNullException(nameof(oldEnum));
}
return (New)Enum.ToObject(typeof(New), oldEnum.GetHashCode());
}
public static TEnum StringToEnum<TEnum>(this string str)
{
return (TEnum)Enum.Parse(typeof(TEnum), str);
}
}
}

View File

@@ -1,98 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public static class ExpressionHelper
{
/// <summary>
/// Expression表达式树lambda参数拼接组合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first"></param>
/// <param name="second"></param>
/// <param name="merge"></param>
/// <returns></returns>
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
var parameterMap = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
var secondBody = LambdaParameteRebinder.ReplaceParameter(parameterMap, second.Body);
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
/// <summary>
/// Expression表达式树lambda参数拼接--false
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Expression<Func<T, bool>> False<T>() => f => false;
/// <summary>
/// Expression表达式树lambda参数拼接-true
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Expression<Func<T, bool>> True<T>() => f => true;
/// <summary>
/// Expression表达式树lambda参数拼接--and
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) => first.Compose(second, Expression.And);
/// <summary>
/// Expression表达式树lambda参数拼接--or
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) => first.Compose(second, Expression.Or);
}
public class LambdaParameteRebinder : ExpressionVisitor
{
/// <summary>
/// 存放表达式树的参数的字典
/// </summary>
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="map"></param>
public LambdaParameteRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
/// <summary>
/// 重载参数访问的方法,访问表达式树参数,如果字典中包含,则取出
/// </summary>
/// <param name="node">表达式树参数</param>
/// <returns></returns>
protected override Expression VisitParameter(ParameterExpression node)
{
if (map.TryGetValue(node, out ParameterExpression expression))
{
node = expression;
}
return base.VisitParameter(node);
}
public static Expression ReplaceParameter(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new LambdaParameteRebinder(map).Visit(exp);
}
}
}

View File

@@ -1,122 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public static class HttpHelper
{
public static HttpClient Client { get; set; } = new HttpClient();
public static async Task<string> Get(string url)
{
return await Client.GetStringAsync(url);
}
public static async Task<Stream> GetIO(string url)
{
return await Client.GetStreamAsync(url);
}
public static async Task<string> Post(string url, object? item = null, Dictionary<string, string>? head = null)
{
using StringContent json = new(JsonSerializer.Serialize(item), Encoding.UTF8, MediaTypeNames.Application.Json);
if (head is not null)
{
foreach (var d in head)
{
json.Headers.Add(d.Key, d.Value);
}
}
var httpResponse = await Client.PostAsync(url, json);
httpResponse.EnsureSuccessStatusCode();
var content = httpResponse.Content;
return await content.ReadAsStringAsync();
}
// public static string HttpGet(string Url, string postDataStr="")
// {
//#pragma warning disable SYSLIB0014 // 类型或成员已过时
// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr);
//#pragma warning restore SYSLIB0014 // 类型或成员已过时
// request.Method = "GET";
// request.ContentType = "text/html;charset=UTF-8";
// HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// Stream myResponseStream = response.GetResponseStream();
// StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
// string retString = myStreamReader.ReadToEnd();
// myStreamReader.Close();
// myResponseStream.Close();
// return retString;
// }
// public static bool HttpIOGet(string Url, string file, string postDataStr="")
// {
// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr);
// request.Method = "GET";
// request.ContentType = "text/html;charset=UTF-8";
// HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// Stream myResponseStream = response.GetResponseStream();
// FileStream writer = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write);
// byte[] buffer = new byte[1024];
// int c;
// while ((c = myResponseStream.Read(buffer, 0, buffer.Length)) > 0)
// {
// writer.Write(buffer, 0, c);
// }
// writer.Close();
// myResponseStream.Close();
// return true;
// }
// public static string HttpPost(string Url, string postDataStr="")
// {
// CookieContainer cookie = new CookieContainer();
//#pragma warning disable SYSLIB0014 // 类型或成员已过时
// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
//#pragma warning restore SYSLIB0014 // 类型或成员已过时
// request.Method = "POST";
// request.ContentType = "application/x-www-form-urlencoded";
// request.ContentLength = Encoding.UTF8.GetByteCount(postDataStr);
// request.CookieContainer = cookie;
// Stream myRequestStream = request.GetRequestStream();
// StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312"));
// myStreamWriter.Write(postDataStr);
// myStreamWriter.Close();
// HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// response.Cookies = cookie.GetCookies(response.ResponseUri);
// Stream myResponseStream = response.GetResponseStream();
// StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
// string retString = myStreamReader.ReadToEnd();
// myStreamReader.Close();
// myResponseStream.Close();
// return retString;
// }
}
}

View File

@@ -1,132 +0,0 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Yi.Framework.Core.Helper
{
public class MD5Helper
{
/// <summary>
/// 生成PasswordSalt
/// </summary>
/// <returns>返回string</returns>
public static string GenerateSalt()
{
byte[] buf = new byte[16];
#pragma warning disable SYSLIB0023 // 类型或成员已过时
new RNGCryptoServiceProvider().GetBytes(buf);
#pragma warning restore SYSLIB0023 // 类型或成员已过时
return Convert.ToBase64String(buf);
}
/// <summary>
/// 加密密码
/// </summary>
/// <param name="pass">密码</param>
/// <param name="passwordFormat">加密类型</param>
/// <param name="salt">PasswordSalt</param>
/// <returns>加密后的密码</returns>
public static string SHA2Encode(string pass, string salt, int passwordFormat = 1)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bAll = new byte[bSalt.Length + bIn.Length];
byte[]? bRet = null;
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
#pragma warning disable SYSLIB0021 // 类型或成员已过时
var s = SHA512.Create();
#pragma warning restore SYSLIB0021 // 类型或成员已过时
bRet = s.ComputeHash(bAll);
return ConvertEx.ToUrlBase64String(bRet);
}
/// <summary>
/// 16位MD5加密
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string MD5Encrypt16(string password)
{
var md5 = MD5.Create();
string t2 = BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(password)), 4, 8);
t2 = t2.Replace("-", string.Empty);
return t2;
}
/// <summary>
/// 32位MD5加密
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string MD5Encrypt32(string password = "")
{
string pwd = string.Empty;
try
{
if (!string.IsNullOrEmpty(password) && !string.IsNullOrWhiteSpace(password))
{
MD5 md5 = MD5.Create(); //实例化一个md5对像
// 加密后是一个字节类型的数组这里要注意编码UTF8/Unicode等的选择 
byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
// 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
foreach (var item in s)
{
// 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母如果使用大写X则格式后的字符是大写字符
pwd = string.Concat(pwd, item.ToString("X2"));
}
}
}
catch
{
throw new Exception($"错误的 password 字符串:【{password}】");
}
return pwd;
}
/// <summary>
/// 64位MD5加密
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string MD5Encrypt64(string password)
{
// 实例化一个md5对像
// 加密后是一个字节类型的数组这里要注意编码UTF8/Unicode等的选择 
MD5 md5 = MD5.Create();
byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
return Convert.ToBase64String(s);
}
}
public class ConvertEx
{
static readonly char[] padding = { '=' };
public static string ToUrlBase64String(byte[] inArray)
{
var str = Convert.ToBase64String(inArray);
str = str.TrimEnd(padding).Replace('+', '-').Replace('/', '_');
return str;
}
public static byte[] FromUrlBase64String(string s)
{
string incoming = s.Replace('_', '/').Replace('-', '+');
switch (s.Length % 4)
{
case 2: incoming += "=="; break;
case 3: incoming += "="; break;
}
byte[] bytes = Convert.FromBase64String(incoming);
return bytes;
}
}
}

View File

@@ -1,260 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Enums;
namespace Yi.Framework.Core.Helper
{
public static class MimeHelper
{
// 通过自己定义一个静态类
// 将所有的Content Type都扔进去吧
// 调用的时候直接调用静态方法即可。
public static List<string> ImageType { get; set; } = new List<string>
{
".jpg",".png",".jpeg"
};
private static Hashtable _mimeMappingTable;
private static void AddMimeMapping(string extension, string MimeType)
{
_mimeMappingTable.Add(extension, MimeType);
}
public static string GetMimeMapping(string FileName)
{
string text = null!;
int num = FileName.LastIndexOf('.');
if (0 < num && num > FileName.LastIndexOf('\\'))
{
text = (string)_mimeMappingTable[FileName.Substring(num)]!;
}
if (text == null)
{
text = (string)_mimeMappingTable[".*"]!;
}
return text;
}
public static FileTypeEnum GetFileType(string fileName)
{
var extension = Path.GetExtension(fileName);
if (ImageType.Contains(extension.ToLower()))
return FileTypeEnum.Image;
return FileTypeEnum.File;
}
static MimeHelper()
{
_mimeMappingTable = new Hashtable(190, StringComparer.CurrentCultureIgnoreCase);
AddMimeMapping(".323", "text/h323");
AddMimeMapping(".asx", "video/x-ms-asf");
AddMimeMapping(".acx", "application/internet-property-stream");
AddMimeMapping(".ai", "application/postscript");
AddMimeMapping(".aif", "audio/x-aiff");
AddMimeMapping(".aiff", "audio/aiff");
AddMimeMapping(".axs", "application/olescript");
AddMimeMapping(".aifc", "audio/aiff");
AddMimeMapping(".asr", "video/x-ms-asf");
AddMimeMapping(".avi", "video/x-msvideo");
AddMimeMapping(".asf", "video/x-ms-asf");
AddMimeMapping(".au", "audio/basic");
AddMimeMapping(".application", "application/x-ms-application");
AddMimeMapping(".bin", "application/octet-stream");
AddMimeMapping(".bas", "text/plain");
AddMimeMapping(".bcpio", "application/x-bcpio");
AddMimeMapping(".bmp", "image/bmp");
AddMimeMapping(".cdf", "application/x-cdf");
AddMimeMapping(".cat", "application/vndms-pkiseccat");
AddMimeMapping(".crt", "application/x-x509-ca-cert");
AddMimeMapping(".c", "text/plain");
AddMimeMapping(".css", "text/css");
AddMimeMapping(".cer", "application/x-x509-ca-cert");
AddMimeMapping(".crl", "application/pkix-crl");
AddMimeMapping(".cmx", "image/x-cmx");
AddMimeMapping(".csh", "application/x-csh");
AddMimeMapping(".cod", "image/cis-cod");
AddMimeMapping(".cpio", "application/x-cpio");
AddMimeMapping(".clp", "application/x-msclip");
AddMimeMapping(".crd", "application/x-mscardfile");
AddMimeMapping(".deploy", "application/octet-stream");
AddMimeMapping(".dll", "application/x-msdownload");
AddMimeMapping(".dot", "application/msword");
AddMimeMapping(".doc", "application/msword");
AddMimeMapping(".dvi", "application/x-dvi");
AddMimeMapping(".dir", "application/x-director");
AddMimeMapping(".dxr", "application/x-director");
AddMimeMapping(".der", "application/x-x509-ca-cert");
AddMimeMapping(".dib", "image/bmp");
AddMimeMapping(".dcr", "application/x-director");
AddMimeMapping(".disco", "text/xml");
AddMimeMapping(".exe", "application/octet-stream");
AddMimeMapping(".etx", "text/x-setext");
AddMimeMapping(".evy", "application/envoy");
AddMimeMapping(".eml", "message/rfc822");
AddMimeMapping(".eps", "application/postscript");
AddMimeMapping(".flr", "x-world/x-vrml");
AddMimeMapping(".fif", "application/fractals");
AddMimeMapping(".gtar", "application/x-gtar");
AddMimeMapping(".gif", "image/gif");
AddMimeMapping(".gz", "application/x-gzip");
AddMimeMapping(".hta", "application/hta");
AddMimeMapping(".htc", "text/x-component");
AddMimeMapping(".htt", "text/webviewhtml");
AddMimeMapping(".h", "text/plain");
AddMimeMapping(".hdf", "application/x-hdf");
AddMimeMapping(".hlp", "application/winhlp");
AddMimeMapping(".html", "text/html");
AddMimeMapping(".htm", "text/html");
AddMimeMapping(".hqx", "application/mac-binhex40");
AddMimeMapping(".isp", "application/x-internet-signup");
AddMimeMapping(".iii", "application/x-iphone");
AddMimeMapping(".ief", "image/ief");
AddMimeMapping(".ivf", "video/x-ivf");
AddMimeMapping(".ins", "application/x-internet-signup");
AddMimeMapping(".ico", "image/x-icon");
AddMimeMapping(".jpg", "image/jpeg");
AddMimeMapping(".jfif", "image/pjpeg");
AddMimeMapping(".jpe", "image/jpeg");
AddMimeMapping(".jpeg", "image/jpeg");
AddMimeMapping(".js", "application/x-javascript");
AddMimeMapping(".lsx", "video/x-la-asf");
AddMimeMapping(".latex", "application/x-latex");
AddMimeMapping(".lsf", "video/x-la-asf");
AddMimeMapping(".manifest", "application/x-ms-manifest");
AddMimeMapping(".mhtml", "message/rfc822");
AddMimeMapping(".mny", "application/x-msmoney");
AddMimeMapping(".mht", "message/rfc822");
AddMimeMapping(".mid", "audio/mid");
AddMimeMapping(".mpv2", "video/mpeg");
AddMimeMapping(".man", "application/x-troff-man");
AddMimeMapping(".mvb", "application/x-msmediaview");
AddMimeMapping(".mpeg", "video/mpeg");
AddMimeMapping(".m3u", "audio/x-mpegurl");
AddMimeMapping(".mdb", "application/x-msaccess");
AddMimeMapping(".mpp", "application/vnd.ms-project");
AddMimeMapping(".m1v", "video/mpeg");
AddMimeMapping(".mpa", "video/mpeg");
AddMimeMapping(".me", "application/x-troff-me");
AddMimeMapping(".m13", "application/x-msmediaview");
AddMimeMapping(".movie", "video/x-sgi-movie");
AddMimeMapping(".m14", "application/x-msmediaview");
AddMimeMapping(".mpe", "video/mpeg");
AddMimeMapping(".mp2", "video/mpeg");
AddMimeMapping(".mov", "video/quicktime");
AddMimeMapping(".mp3", "audio/mpeg");
AddMimeMapping(".mpg", "video/mpeg");
AddMimeMapping(".ms", "application/x-troff-ms");
AddMimeMapping(".nc", "application/x-netcdf");
AddMimeMapping(".nws", "message/rfc822");
AddMimeMapping(".oda", "application/oda");
AddMimeMapping(".ods", "application/oleobject");
AddMimeMapping(".pmc", "application/x-perfmon");
AddMimeMapping(".p7r", "application/x-pkcs7-certreqresp");
AddMimeMapping(".p7b", "application/x-pkcs7-certificates");
AddMimeMapping(".p7s", "application/pkcs7-signature");
AddMimeMapping(".pmw", "application/x-perfmon");
AddMimeMapping(".ps", "application/postscript");
AddMimeMapping(".p7c", "application/pkcs7-mime");
AddMimeMapping(".pbm", "image/x-portable-bitmap");
AddMimeMapping(".ppm", "image/x-portable-pixmap");
AddMimeMapping(".pub", "application/x-mspublisher");
AddMimeMapping(".pnm", "image/x-portable-anymap");
AddMimeMapping(".png", "image/png");
AddMimeMapping(".pml", "application/x-perfmon");
AddMimeMapping(".p10", "application/pkcs10");
AddMimeMapping(".pfx", "application/x-pkcs12");
AddMimeMapping(".p12", "application/x-pkcs12");
AddMimeMapping(".pdf", "application/pdf");
AddMimeMapping(".pps", "application/vnd.ms-powerpoint");
AddMimeMapping(".p7m", "application/pkcs7-mime");
AddMimeMapping(".pko", "application/vndms-pkipko");
AddMimeMapping(".ppt", "application/vnd.ms-powerpoint");
AddMimeMapping(".pmr", "application/x-perfmon");
AddMimeMapping(".pma", "application/x-perfmon");
AddMimeMapping(".pot", "application/vnd.ms-powerpoint");
AddMimeMapping(".prf", "application/pics-rules");
AddMimeMapping(".pgm", "image/x-portable-graymap");
AddMimeMapping(".qt", "video/quicktime");
AddMimeMapping(".ra", "audio/x-pn-realaudio");
AddMimeMapping(".rgb", "image/x-rgb");
AddMimeMapping(".ram", "audio/x-pn-realaudio");
AddMimeMapping(".rmi", "audio/mid");
AddMimeMapping(".ras", "image/x-cmu-raster");
AddMimeMapping(".roff", "application/x-troff");
AddMimeMapping(".rtf", "application/rtf");
AddMimeMapping(".rtx", "text/richtext");
AddMimeMapping(".sv4crc", "application/x-sv4crc");
AddMimeMapping(".spc", "application/x-pkcs7-certificates");
AddMimeMapping(".setreg", "application/set-registration-initiation");
AddMimeMapping(".snd", "audio/basic");
AddMimeMapping(".stl", "application/vndms-pkistl");
AddMimeMapping(".setpay", "application/set-payment-initiation");
AddMimeMapping(".stm", "text/html");
AddMimeMapping(".shar", "application/x-shar");
AddMimeMapping(".sh", "application/x-sh");
AddMimeMapping(".sit", "application/x-stuffit");
AddMimeMapping(".spl", "application/futuresplash");
AddMimeMapping(".sct", "text/scriptlet");
AddMimeMapping(".scd", "application/x-msschedule");
AddMimeMapping(".sst", "application/vndms-pkicertstore");
AddMimeMapping(".src", "application/x-wais-source");
AddMimeMapping(".sv4cpio", "application/x-sv4cpio");
AddMimeMapping(".tex", "application/x-tex");
AddMimeMapping(".tgz", "application/x-compressed");
AddMimeMapping(".t", "application/x-troff");
AddMimeMapping(".tar", "application/x-tar");
AddMimeMapping(".tr", "application/x-troff");
AddMimeMapping(".tif", "image/tiff");
AddMimeMapping(".txt", "text/plain");
AddMimeMapping(".texinfo", "application/x-texinfo");
AddMimeMapping(".trm", "application/x-msterminal");
AddMimeMapping(".tiff", "image/tiff");
AddMimeMapping(".tcl", "application/x-tcl");
AddMimeMapping(".texi", "application/x-texinfo");
AddMimeMapping(".tsv", "text/tab-separated-values");
AddMimeMapping(".ustar", "application/x-ustar");
AddMimeMapping(".uls", "text/iuls");
AddMimeMapping(".vcf", "text/x-vcard");
AddMimeMapping(".wps", "application/vnd.ms-works");
AddMimeMapping(".wav", "audio/wav");
AddMimeMapping(".wrz", "x-world/x-vrml");
AddMimeMapping(".wri", "application/x-mswrite");
AddMimeMapping(".wks", "application/vnd.ms-works");
AddMimeMapping(".wmf", "application/x-msmetafile");
AddMimeMapping(".wcm", "application/vnd.ms-works");
AddMimeMapping(".wrl", "x-world/x-vrml");
AddMimeMapping(".wdb", "application/vnd.ms-works");
AddMimeMapping(".wsdl", "text/xml");
AddMimeMapping(".xap", "application/x-silverlight-app");
AddMimeMapping(".xml", "text/xml");
AddMimeMapping(".xlm", "application/vnd.ms-excel");
AddMimeMapping(".xaf", "x-world/x-vrml");
AddMimeMapping(".xla", "application/vnd.ms-excel");
AddMimeMapping(".xls", "application/vnd.ms-excel");
AddMimeMapping(".xlsx", "application/vnd.ms-excel");
AddMimeMapping(".xof", "x-world/x-vrml");
AddMimeMapping(".xlt", "application/vnd.ms-excel");
AddMimeMapping(".xlc", "application/vnd.ms-excel");
AddMimeMapping(".xsl", "text/xml");
AddMimeMapping(".xbm", "image/x-xbitmap");
AddMimeMapping(".xlw", "application/vnd.ms-excel");
AddMimeMapping(".xpm", "image/x-xpixmap");
AddMimeMapping(".xwd", "image/x-xwindowdump");
AddMimeMapping(".xsd", "text/xml");
AddMimeMapping(".z", "application/x-compress");
AddMimeMapping(".zip", "application/x-zip-compressed");
AddMimeMapping(".*", "application/octet-stream");
}
}
}

View File

@@ -1,390 +0,0 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Yi.Framework.Core.Helper
{
/// <summary>
/// RSA加解密 使用OpenSSL的公钥加密/私钥解密
/// 公私钥请使用openssl生成
/// </summary>
public class RSAHelper
{
public readonly RSA? _privateKeyRsaProvider;
public readonly RSA? _publicKeyRsaProvider;
private readonly HashAlgorithmName _hashAlgorithmName;
private readonly Encoding _encoding;
/// <summary>
/// 实例化RSAHelper
/// </summary>
/// <param name="rsaType">加密算法类型 RSA SHA1;RSA2 SHA256 密钥长度至少为2048</param>
/// <param name="encoding">编码类型</param>
/// <param name="privateKey">私钥</param>
/// <param name="publicKey">公钥</param>
public RSAHelper(RSAType rsaType, Encoding encoding, string privateKey, string? publicKey = null)
{
_encoding = encoding;
if (!string.IsNullOrEmpty(privateKey))
{
_privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey);
}
if (!string.IsNullOrEmpty(publicKey))
{
_publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey);
}
_hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256;
}
#region 使
/// <summary>
/// 使用私钥签名
/// </summary>
/// <param name="data">原始数据</param>
/// <returns></returns>
public string Sign(string data)
{
byte[] dataBytes = _encoding.GetBytes(data);
var signatureBytes = _privateKeyRsaProvider!.SignData(dataBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signatureBytes);
}
#endregion
#region 使
/// <summary>
/// 使用公钥验签
/// </summary>
/// <param name="data">原始数据</param>
/// <param name="sign">签名</param>
/// <returns></returns>
public bool Verify(string data, string sign)
{
byte[] dataBytes = _encoding.GetBytes(data);
byte[] signBytes = Convert.FromBase64String(sign);
var verify = _publicKeyRsaProvider!.VerifyData(dataBytes, signBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);
return verify;
}
#endregion
#region
/// <summary>
/// 私钥解密(原)
/// </summary>
/// <param name="cipherText">解密字符串(base64)</param>
/// <returns></returns>
//public string Decrypt(string cipherText)
//{
// if (_privateKeyRsaProvider == null)
// {
// throw new Exception("_privateKeyRsaProvider is null");
// }
// return _encoding.GetString(_privateKeyRsaProvider.Decrypt(Convert.FromBase64String(cipherText), RSAEncryptionPadding.Pkcs1));
//}
/// <summary>
/// 私钥解密(支持大量数据)
/// </summary>
/// <param name="cipherText"></param>
/// <returns></returns>
public string Decrypt(string cipherText)
{
if (_privateKeyRsaProvider == null)
{
throw new Exception("_privateKeyRsaProvider is null");
}
var bufferSize = _privateKeyRsaProvider.KeySize / 8;
byte[] buffer = new byte[bufferSize];//待解密块
using (MemoryStream msInput = new MemoryStream(Convert.FromBase64String(cipherText)))
{
using (MemoryStream msOutput = new MemoryStream())
{
int readLen; while ((readLen = msInput.Read(buffer, 0, bufferSize)) > 0)
{
byte[] dataToEnc = new byte[readLen];
Array.Copy(buffer, 0, dataToEnc, 0, readLen); byte[] encData = _privateKeyRsaProvider.Decrypt(dataToEnc, RSAEncryptionPadding.Pkcs1);
msOutput.Write(encData, 0, encData.Length);
}
byte[] result = msOutput.ToArray();
return _encoding.GetString(result);
}
}
}
#endregion
#region
/// <summary>
/// 公钥加密(原)
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
//public string Encrypt(string text)
//{
// if (_publicKeyRsaProvider == null)
// {
// throw new Exception("_publicKeyRsaProvider is null");
// }
// return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.Pkcs1));
//}
/// <summary>
/// 公钥加密(支持大量数据)
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public string Encrypt(string text)
{
if (_publicKeyRsaProvider == null)
{
throw new Exception("_publicKeyRsaProvider is null");
}
var bufferSize = _publicKeyRsaProvider.KeySize / 8 - 11;
byte[] buffer = new byte[bufferSize];//待加密块
using (MemoryStream msInput = new MemoryStream(_encoding.GetBytes(text)))
{
using (MemoryStream msOutput = new MemoryStream())
{
int readLen; while ((readLen = msInput.Read(buffer, 0, bufferSize)) > 0)
{
byte[] dataToEnc = new byte[readLen];
Array.Copy(buffer, 0, dataToEnc, 0, readLen); byte[] encData = _publicKeyRsaProvider.Encrypt(dataToEnc, RSAEncryptionPadding.Pkcs1);
msOutput.Write(encData, 0, encData.Length);
}
byte[] result = msOutput.ToArray();
return Convert.ToBase64String(result);
}
}
}
#endregion
#region 使RSA实例
/// <summary>
/// 使用私钥创建RSA实例
/// </summary>
/// <param name="privateKey"></param>
/// <returns></returns>
private RSA CreateRsaProviderFromPrivateKey(string privateKey)
{
var privateKeyBits = Convert.FromBase64String(privateKey);
var rsa = RSA.Create();
var rsaParameters = new RSAParameters();
using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits)))
{
byte bt = 0;
ushort twobytes = 0;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130)
binr.ReadByte();
else if (twobytes == 0x8230)
binr.ReadInt16();
else
throw new Exception("Unexpected value read binr.ReadUInt16()");
twobytes = binr.ReadUInt16();
if (twobytes != 0x0102)
throw new Exception("Unexpected version");
bt = binr.ReadByte();
if (bt != 0x00)
throw new Exception("Unexpected value read binr.ReadByte()");
rsaParameters.Modulus = binr.ReadBytes(GetIntegerSize(binr));
rsaParameters.Exponent = binr.ReadBytes(GetIntegerSize(binr));
rsaParameters.D = binr.ReadBytes(GetIntegerSize(binr));
rsaParameters.P = binr.ReadBytes(GetIntegerSize(binr));
rsaParameters.Q = binr.ReadBytes(GetIntegerSize(binr));
rsaParameters.DP = binr.ReadBytes(GetIntegerSize(binr));
rsaParameters.DQ = binr.ReadBytes(GetIntegerSize(binr));
rsaParameters.InverseQ = binr.ReadBytes(GetIntegerSize(binr));
}
rsa.ImportParameters(rsaParameters);
return rsa;
}
#endregion
#region 使RSA实例
/// <summary>
/// 使用公钥创建RSA实例
/// </summary>
/// <param name="publicKeyString"></param>
/// <returns></returns>
public RSA? CreateRsaProviderFromPublicKey(string publicKeyString)
{
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
byte[] seq = new byte[15];
var x509Key = Convert.FromBase64String(publicKeyString);
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------
using (MemoryStream mem = new MemoryStream(x509Key))
{
using (BinaryReader binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading
{
byte bt = 0;
ushort twobytes = 0;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
seq = binr.ReadBytes(15); //read the Sequence OID
if (!CompareBytearrays(seq, seqOid)) //make sure Sequence for OID is correct
return null;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8203)
binr.ReadInt16(); //advance 2 bytes
else
return null;
bt = binr.ReadByte();
if (bt != 0x00) //expect null byte next
return null;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
twobytes = binr.ReadUInt16();
byte lowbyte = 0x00;
byte highbyte = 0x00;
if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus
else if (twobytes == 0x8202)
{
highbyte = binr.ReadByte(); //advance 2 bytes
lowbyte = binr.ReadByte();
}
else
return null;
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order
int modsize = BitConverter.ToInt32(modint, 0);
int firstbyte = binr.PeekChar();
if (firstbyte == 0x00)
{ //if first byte (highest order) of modulus is zero, don't include it
binr.ReadByte(); //skip this null byte
modsize -= 1; //reduce modulus buffer size by 1
}
byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes
if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data
return null;
int expbytes = binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values)
byte[] exponent = binr.ReadBytes(expbytes);
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
var rsa = RSA.Create();
RSAParameters rsaKeyInfo = new RSAParameters
{
Modulus = modulus,
Exponent = exponent
};
rsa.ImportParameters(rsaKeyInfo);
return rsa;
}
}
}
#endregion
#region
private int GetIntegerSize(BinaryReader binr)
{
byte bt = 0;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02)
return 0;
bt = binr.ReadByte();
if (bt == 0x81)
count = binr.ReadByte();
else
if (bt == 0x82)
{
var highbyte = binr.ReadByte();
var lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt;
}
while (binr.ReadByte() == 0x00)
{
count -= 1;
}
binr.BaseStream.Seek(-1, SeekOrigin.Current);
return count;
}
private bool CompareBytearrays(byte[] a, byte[] b)
{
if (a.Length != b.Length)
return false;
int i = 0;
foreach (byte c in a)
{
if (c != b[i])
return false;
i++;
}
return true;
}
#endregion
}
/// <summary>
/// RSA算法类型
/// </summary>
public enum RSAType
{
/// <summary>
/// SHA1
/// </summary>
RSA = 0,
/// <summary>
/// RSA2 密钥长度至少为2048
/// SHA256
/// </summary>
RSA2
}
}

View File

@@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public static class ReflexHelper
{
#region
/// <summary>
/// 取对象属性值
/// </summary>
/// <param name="FieldName"></param>
/// <param name="obj"></param>
/// <returns></returns>
public static string GetModelValue(string FieldName, object obj)
{
try
{
Type Ts = obj.GetType();
object o = Ts.GetProperty(FieldName).GetValue(obj, null);
if (null == o)
return null;
string Value = Convert.ToString(o);
if (string.IsNullOrEmpty(Value))
return null;
return Value;
}
catch (Exception ex)
{
throw ex;
}
return null;
}
/// <summary>
/// 设置对象属性值
/// </summary>
/// <param name="FieldName"></param>
/// <param name="Value"></param>
/// <param name="obj"></param>
/// <returns></returns>
public static bool SetModelValue(string FieldName, object Value, object obj)
{
try
{
Type Ts = obj.GetType();
Ts.GetProperty(FieldName).SetValue(obj, Value, null);
return true;
}
catch (Exception ex)
{
throw ex;
}
return false;
}
#endregion
}
}

View File

@@ -1,58 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace Yi.Framework.Core.Helper
{
public class ShellHelper
{
/// <summary>
/// linux 系统命令
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
public static string Bash(string command)
{
var escapedArgs = command.Replace("\"", "\\\"");
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"-c \"{escapedArgs}\"",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
process.Dispose();
return result;
}
/// <summary>
/// windows系统命令
/// </summary>
/// <param name="fileName"></param>
/// <param name="args"></param>
/// <returns></returns>
public static string Cmd(string fileName, string args)
{
string output = string.Empty;
var info = new ProcessStartInfo();
info.FileName = fileName;
info.Arguments = args;
info.RedirectStandardOutput = true;
using (var process = Process.Start(info))
{
output = process.StandardOutput.ReadToEnd();
}
return output;
}
}
}

View File

@@ -1,59 +0,0 @@
using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity;
namespace Yi.Framework.Core.Modularity;
[Dependency(ReplaceServices =true)]
public class YiModuleManager : ModuleManager, IModuleManager, ISingletonDependency
{
private readonly IModuleContainer _moduleContainer;
private readonly IEnumerable<IModuleLifecycleContributor> _lifecycleContributors;
private readonly ILogger<YiModuleManager> _logger;
public YiModuleManager(IModuleContainer moduleContainer, ILogger<YiModuleManager> logger, IOptions<AbpModuleLifecycleOptions> options, IServiceProvider serviceProvider) : base(moduleContainer, logger, options, serviceProvider)
{
_moduleContainer = moduleContainer;
_logger = logger;
_lifecycleContributors = options.Value.Contributors.Select(serviceProvider.GetRequiredService).Cast<IModuleLifecycleContributor>().ToArray();
}
public override async Task InitializeModulesAsync(ApplicationInitializationContext context)
{
_logger.LogDebug("==========模块Initialize初始化统计-跳过0ms模块==========");
var total = 0;
var watch =new Stopwatch();
long totalTime = 0;
foreach (var contributor in _lifecycleContributors)
{
foreach (var module in _moduleContainer.Modules)
{
try
{
watch.Restart();
await contributor.InitializeAsync(context, module.Instance);
watch.Stop();
totalTime += watch.ElapsedMilliseconds;
total++;
if (watch.ElapsedMilliseconds > 1)
{
_logger.LogDebug($"耗时-{watch.ElapsedMilliseconds}ms,已加载模块-{module.Assembly.GetName().Name}");
}
}
catch (Exception ex)
{
throw new AbpInitializationException($"An error occurred during the initialize {contributor.GetType().FullName} phase of the module {module.Type.AssemblyQualifiedName}: {ex.Message}. See the inner exception for details.", ex);
}
}
}
_logger.LogInformation($"==========【{total}】个模块初始化执行完毕,总耗时【{totalTime}ms】==========");
}
}

View File

@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Volo.Abp.Core" Version="$(AbpVersion)" />
</ItemGroup>
</Project>

View File

@@ -1,9 +0,0 @@
using Volo.Abp.Modularity;
namespace Yi.Framework.Core
{
public class YiFrameworkCoreModule:AbpModule
{
}
}

View File

@@ -1,10 +0,0 @@
using Volo.Abp;
using Volo.Abp.Application.Services;
namespace Yi.Framework.Ddd.Application.Contracts
{
public interface IDeletesAppService<in TKey> : IDeleteAppService< TKey> , IApplicationService, IRemoteService
{
Task DeleteAsync(IEnumerable<TKey> ids);
}
}

View File

@@ -1,10 +0,0 @@
using Volo.Abp.Application.Dtos;
namespace Yi.Framework.Ddd.Application.Contracts
{
public interface IPageTimeResultRequestDto : IPagedAndSortedResultRequest
{
DateTime? StartTime { get; set; }
DateTime? EndTime { get; set; }
}
}

View File

@@ -1,8 +0,0 @@
using Volo.Abp.Application.Dtos;
namespace Yi.Framework.Ddd.Application.Contracts
{
public interface IPagedAllResultRequestDto : IPageTimeResultRequestDto, IPagedAndSortedResultRequest
{
}
}

View File

@@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace Yi.Framework.Ddd.Application.Contracts
{
public interface IYiCrudAppService<TEntityDto, in TKey> : ICrudAppService<TEntityDto, TKey>
{
}
public interface IYiCrudAppService<TEntityDto, in TKey, in TGetListInput> : ICrudAppService<TEntityDto, TKey, TGetListInput>
{
}
public interface IYiCrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput> : ICrudAppService<TEntityDto, TKey, TGetListInput, TCreateInput>
{
}
public interface IYiCrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput> : ICrudAppService<TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
{
}
public interface IYiCrudAppService<TGetOutputDto, TGetListOutputDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput> : ICrudAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>, IDeletesAppService<TKey>
{
}
}

View File

@@ -1,17 +0,0 @@
using Volo.Abp.Application.Dtos;
namespace Yi.Framework.Ddd.Application.Contracts
{
public class PagedAllResultRequestDto : PagedAndSortedResultRequestDto, IPagedAllResultRequestDto
{
/// <summary>
/// 查询开始时间条件
/// </summary>
public DateTime? StartTime { get; set; }
/// <summary>
/// 查询结束时间条件
/// </summary>
public DateTime? EndTime { get; set; }
}
}

View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,10 +0,0 @@
using Volo.Abp.Application;
using Volo.Abp.Modularity;
namespace Yi.Framework.Ddd.Application.Contracts
{
[DependsOn(typeof(AbpDddApplicationContractsModule))]
public class YiFrameworkDddApplicationContractsModule : AbpModule
{
}
}

View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<ItemGroup>
<PackageReference Include="MiniExcel" Version="1.31.3" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Ddd.Application.Contracts\Yi.Framework.Ddd.Application.Contracts.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,119 +0,0 @@
using Volo.Abp.Application.Dtos;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
namespace Yi.Framework.Ddd.Application
{
public abstract class YiCacheCrudAppService<TEntity, TEntityDto, TKey> : YiCrudAppService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected YiCacheCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
}
public abstract class YiCacheCrudAppService<TEntity, TEntityDto, TKey, TGetListInput>
: YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TEntityDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected YiCacheCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
}
public abstract class YiCacheCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>
: YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected YiCacheCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
}
public abstract class YiCacheCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: YiCrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected YiCacheCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
}
public abstract class YiCacheCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: YiCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{
protected IDistributedCache<TEntity> Cache => LazyServiceProvider.LazyGetRequiredService<IDistributedCache<TEntity>>();
protected string GetCacheKey(TKey id) => typeof(TEntity).Name + ":" + CurrentTenant.Id ?? Guid.Empty + ":" + id.ToString();
protected YiCacheCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
public override async Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input)
{
var output = await base.UpdateAsync(id, input);
await Cache.RemoveAsync(GetCacheKey(id));
return output;
}
public override async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
{
//两种方式:
//1全表缓存使用缓存直接查询
//2非全部缓存查询到的数据直接添加到缓存
//判断是否该实体为全表缓存
throw new NotImplementedException();
//IDistributedCache 有局限性,条件查询无法进行缓存了
//if (true)
//{
// return await GetListByCacheAsync(input);
//}
//else
//{
// return await GetListByDbAsync(input);
//}
}
protected virtual async Task<PagedResultDto<TGetListOutputDto>> GetListByDbAsync(TGetListInput input)
{
//如果不是全表缓存,可以走这个啦
throw new NotImplementedException();
}
protected virtual async Task<PagedResultDto<TGetListOutputDto>> GetListByCacheAsync(TGetListInput input)
{
//如果是全表缓存,可以走这个啦
throw new NotImplementedException();
}
protected override async Task<TEntity> GetEntityByIdAsync(TKey id)
{
var output = await Cache.GetOrAddAsync(GetCacheKey(id), async () => await base.GetEntityByIdAsync(id));
return output!;
}
public override async Task DeleteAsync(IEnumerable<TKey> id)
{
await base.DeleteAsync(id);
foreach (var itemId in id)
{
await Cache.RemoveAsync(GetCacheKey(itemId));
}
}
}
}

View File

@@ -1,149 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
namespace Yi.Framework.Ddd.Application
{
public abstract class YiCrudAppService<TEntity, TEntityDto, TKey> : YiCrudAppService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected YiCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
}
public abstract class YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput>
: YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TEntityDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected YiCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
}
public abstract class YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>
: YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected YiCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
}
public abstract class YiCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: YiCrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected YiCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
}
public abstract class YiCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: CrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{
protected YiCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
{
}
/// <summary>
/// 多查
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public override async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
{
List<TEntity>? entites = null;
//区分多查还是批量查
if (input is IPagedResultRequest pagedInput)
{
entites = await Repository.GetPagedListAsync(pagedInput.SkipCount, pagedInput.MaxResultCount, string.Empty);
}
else
{
entites = await Repository.GetListAsync();
}
var total = await Repository.GetCountAsync();
var output = await MapToGetListOutputDtosAsync(entites);
return new PagedResultDto<TGetListOutputDto>(total, output);
//throw new NotImplementedException($"【{typeof(TEntity)}】实体的CrudAppService查询为具体业务通用查询几乎无实际场景请重写实现");
}
/// <summary>
/// 多删
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[RemoteService(isEnabled: true)]
public virtual async Task DeleteAsync(IEnumerable<TKey> id)
{
await Repository.DeleteManyAsync(id);
}
/// <summary>
/// 偷梁换柱
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[RemoteService(isEnabled: false)]
public override Task DeleteAsync(TKey id)
{
return base.DeleteAsync(id);
}
/// <summary>
/// 导出excel
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public virtual async Task<IActionResult> GetExportExcelAsync(TGetListInput input)
{
if (input is IPagedResultRequest paged)
{
paged.SkipCount = 0;
paged.MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount;
}
var output = await this.GetListAsync(input);
var dirPath = $"/wwwroot/temp";
var fileName = $"{typeof(TEntity).Name}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}_{Guid.NewGuid()}";
var filePath = $"{dirPath}/{fileName}.xlsx";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
MiniExcel.SaveAs(filePath, output.Items);
return new PhysicalFileResult(filePath, "application/vnd.ms-excel");
}
/// <summary>
/// 导入excle
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public virtual async Task PostImportExcelAsync(List<TCreateInput> input)
{
var entities = input.Select(x => MapToEntity(x)).ToList();
//安全起见,该接口需要自己实现
throw new NotImplementedException();
//await Repository.DeleteManyAsync(entities.Select(x => x.Id));
//await Repository.InsertManyAsync(entities);
}
}
}

View File

@@ -1,20 +0,0 @@
using Volo.Abp;
using Volo.Abp.Application;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Modularity;
using Yi.Framework.Ddd.Application.Contracts;
namespace Yi.Framework.Ddd.Application
{
[DependsOn(typeof(AbpDddApplicationModule),
typeof(YiFrameworkDddApplicationContractsModule))]
public class YiFrameworkDddApplicationModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
//分页限制
LimitedResultRequestDto.DefaultMaxResultCount = 10;
LimitedResultRequestDto.MaxMaxResultCount = 10000;
}
}
}

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Mapster;
using Volo.Abp.ObjectMapping;
namespace Yi.Framework.Mapster
{
public class MapsterAutoObjectMappingProvider : IAutoObjectMappingProvider
{
public TDestination Map<TSource, TDestination>(object source)
{
var sss = typeof(TDestination).Name;
return source.Adapt<TDestination>();
}
public TDestination Map<TSource, TDestination>(TSource source, TDestination destination)
{
return source.Adapt<TSource, TDestination>(destination);
}
}
}

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.ObjectMapping;
namespace Yi.Framework.Mapster
{
public class MapsterObjectMapper : IObjectMapper
{
public IAutoObjectMappingProvider AutoObjectMappingProvider => throw new NotImplementedException();
public TDestination Map<TSource, TDestination>(TSource source)
{
throw new NotImplementedException();
}
public TDestination Map<TSource, TDestination>(TSource source, TDestination destination)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<ItemGroup>
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Volo.Abp.ObjectMapping" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,21 +0,0 @@
using MapsterMapper;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectMapping;
using Yi.Framework.Core;
namespace Yi.Framework.Mapster
{
[DependsOn(typeof(YiFrameworkCoreModule),
typeof(AbpObjectMappingModule)
)]
public class YiFrameworkMapsterModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTransient<IAutoObjectMappingProvider, MapsterAutoObjectMappingProvider>();
}
}
}

View File

@@ -1,55 +0,0 @@
using SqlSugar;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
public class DbConnOptions
{
/// <summary>
/// 连接字符串(如果开启多租户,也就是默认库了),必填
/// </summary>
public string? Url { get; set; }
/// <summary>
/// 数据库类型
/// </summary>
public DbType? DbType { get; set; }
/// <summary>
/// 开启种子数据
/// </summary>
public bool EnabledDbSeed { get; set; } = false;
/// <summary>
/// 开启codefirst
/// </summary>
public bool EnabledCodeFirst { get; set; } = false;
/// <summary>
/// 开启sql日志
/// </summary>
public bool EnabledSqlLog { get; set; } = true;
/// <summary>
/// 实体程序集
/// </summary>
public List<string>? EntityAssembly { get; set; }
/// <summary>
/// 开启读写分离
/// </summary>
public bool EnabledReadWrite { get; set; } = false;
/// <summary>
/// 读写分离
/// </summary>
public List<string>? ReadUrl { get; set; }
/// <summary>
/// 开启Saas多租户
/// </summary>
public bool EnabledSaasMultiTenancy { get; set; } = false;
}
}

View File

@@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
[AttributeUsage(AttributeTargets.Class)]
public class DefaultTenantTableAttribute : Attribute
{
}
}

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
public interface ISqlSugarDbConnectionCreator
{
DbConnOptions Options { get; }
Action<ISqlSugarClient> OnSqlSugarClientConfig { get; set; }
Action<object, DataAfterModel> DataExecuted { get; set; }
Action<object, DataFilterModel> DataExecuting { get; set; }
Action<string, SugarParameter[]> OnLogExecuting { get; set; }
Action<string, SugarParameter[]> OnLogExecuted { get; set; }
Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; }
ConnectionConfig Build(Action<ConnectionConfig>? action = null);
void SetDbAop(ISqlSugarClient currentDb);
}
}

View File

@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using Volo.Abp.DependencyInjection;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
public interface ISqlSugarDbContext
{
// IAbpLazyServiceProvider LazyServiceProvider { get; set; }
ISqlSugarClient SqlSugarClient { get; }
DbConnOptions Options { get; }
/// <summary>
/// 数据库备份
/// </summary>
void BackupDataBase();
void SetSqlSugarClient(ISqlSugarClient sqlSugarClient);
}
}

View File

@@ -1,88 +0,0 @@
using System.Linq.Expressions;
using SqlSugar;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
public interface ISqlSugarRepository<TEntity>:IRepository<TEntity> where TEntity : class, IEntity,new ()
{
ISqlSugarClient _Db { get; }
ISugarQueryable<TEntity> _DbQueryable { get; }
Task<ISqlSugarClient> GetDbContextAsync();
Task<IDeleteable<TEntity>> AsDeleteable();
Task<IInsertable<TEntity>> AsInsertable(List<TEntity> insertObjs);
Task<IInsertable<TEntity>> AsInsertable(TEntity insertObj);
Task<IInsertable<TEntity>> AsInsertable(TEntity[] insertObjs);
Task<ISugarQueryable<TEntity>> AsQueryable();
Task<ISqlSugarClient> AsSugarClient();
Task<ITenant> AsTenant();
Task<IUpdateable<TEntity>> AsUpdateable(List<TEntity> updateObjs);
Task<IUpdateable<TEntity>> AsUpdateable(TEntity updateObj);
Task<IUpdateable<TEntity>> AsUpdateable();
Task<IUpdateable<TEntity>> AsUpdateable(TEntity[] updateObjs);
#region
//单查
Task<TEntity> GetByIdAsync(dynamic id);
Task<TEntity> GetSingleAsync(Expression<Func<TEntity, bool>> whereExpression);
Task<TEntity> GetFirstAsync(Expression<Func<TEntity, bool>> whereExpression);
Task<bool> IsAnyAsync(Expression<Func<TEntity, bool>> whereExpression);
Task<int> CountAsync(Expression<Func<TEntity, bool>> whereExpression);
#endregion
#region
//多查
Task<List<TEntity>> GetListAsync();
Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> whereExpression);
#endregion
#region
//分页查
Task<List<TEntity>> GetPageListAsync(Expression<Func<TEntity, bool>> whereExpression, int pageNum, int pageSize);
Task<List<TEntity>> GetPageListAsync(Expression<Func<TEntity, bool>> whereExpression, int pageNum, int pageSize, Expression<Func<TEntity, object>>? orderByExpression = null, OrderByType orderByType = OrderByType.Asc);
#endregion
#region
//插入
Task<bool> InsertAsync(TEntity insertObj);
Task<bool> InsertOrUpdateAsync(TEntity data);
Task<bool> InsertOrUpdateAsync(List<TEntity> datas);
Task<int> InsertReturnIdentityAsync(TEntity insertObj);
Task<long> InsertReturnBigIdentityAsync(TEntity insertObj);
Task<long> InsertReturnSnowflakeIdAsync(TEntity insertObj);
Task<TEntity> InsertReturnEntityAsync(TEntity insertObj);
Task<bool> InsertRangeAsync(List<TEntity> insertObjs);
#endregion
#region
//更新
Task<bool> UpdateAsync(TEntity updateObj);
Task<bool> UpdateRangeAsync(List<TEntity> updateObjs);
Task<bool> UpdateAsync(Expression<Func<TEntity, TEntity>> columns, Expression<Func<TEntity, bool>> whereExpression);
#endregion
#region
//删除
Task<bool> DeleteAsync(TEntity deleteObj);
Task<bool> DeleteAsync(List<TEntity> deleteObjs);
Task<bool> DeleteAsync(Expression<Func<TEntity, bool>> whereExpression);
Task<bool> DeleteByIdAsync(dynamic id);
Task<bool> DeleteByIdsAsync(dynamic[] ids);
#endregion
}
public interface ISqlSugarRepository<TEntity, TKey> : ISqlSugarRepository<TEntity>,IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey>, new()
{
}
}

View File

@@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
public interface ISugarDbContextProvider<TDbContext>
where TDbContext : ISqlSugarDbContext
{
Task<TDbContext> GetDbContextAsync();
}
}

View File

@@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
[AttributeUsage(AttributeTargets.Class)]
public class IgnoreCodeFirstAttribute : Attribute
{
}
}

View File

@@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<ItemGroup>
<PackageReference Include="SqlSugarCoreNoDrive" Version="$(SqlSugarVersion)" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,11 +0,0 @@
using Volo.Abp.Modularity;
using Yi.Framework.Core;
namespace Yi.Framework.SqlSugarCore.Abstractions
{
[DependsOn(typeof(YiFrameworkCoreModule))]
public class YiFrameworkSqlSugarCoreAbstractionsModule : AbpModule
{
}
}

View File

@@ -1,19 +0,0 @@
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore
{
public class AsyncLocalDbContextAccessor
{
public static AsyncLocalDbContextAccessor Instance { get; } = new();
public ISqlSugarDbContext? Current
{
get => _currentScope.Value;
set => _currentScope.Value = value;
}
public AsyncLocalDbContextAccessor()
{
_currentScope = new AsyncLocal<ISqlSugarDbContext?>();
}
private readonly AsyncLocal<ISqlSugarDbContext> _currentScope;
}
}

View File

@@ -1,154 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore.Repositories
{
public class SqlSugarObjectRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
public ISqlSugarClient _Db => GetDbContextAsync().Result;
private ISugarDbContextProvider<ISqlSugarDbContext> _sugarDbContextProvider;
/// <summary>
/// 获取DB
/// </summary>
/// <returns></returns>
public virtual async Task<ISqlSugarClient> GetDbContextAsync()
{
var db = (await _sugarDbContextProvider.GetDbContextAsync()).SqlSugarClient;
//await Console.Out.WriteLineAsync("获取的id" + db.ContextID);
return db;
}
public IAsyncQueryableExecuter AsyncExecuter => throw new NotImplementedException();
public bool? IsChangeTrackingEnabled => throw new NotImplementedException();
public Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity?> FindAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<long> GetCountAsync(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<List<TEntity>> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<List<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> GetQueryableAsync()
{
throw new NotImplementedException();
}
public async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
await (await GetDbContextAsync()).InsertableByObject(entity).ExecuteCommandAsync();
return entity;
}
public Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public IQueryable<TEntity> WithDetails()
{
throw new NotImplementedException();
}
public IQueryable<TEntity> WithDetails(params Expression<Func<TEntity, object>>[] propertySelectors)
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> WithDetailsAsync()
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> WithDetailsAsync(params Expression<Func<TEntity, object>>[] propertySelectors)
{
throw new NotImplementedException();
}
}
public class SqlSugarObjectRepository<TEntity, TKey> : SqlSugarObjectRepository<TEntity>, IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey>
{
public Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task DeleteManyAsync(IEnumerable<TKey> ids, bool autoSave = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity?> FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TEntity> GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,419 +0,0 @@
using System.Linq;
using System.Linq.Expressions;
using SqlSugar;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using Yi.Framework.Core.Helper;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore.Repositories
{
public class SqlSugarRepository<TEntity> : ISqlSugarRepository<TEntity>, IRepository<TEntity> where TEntity : class, IEntity, new()
{
public ISqlSugarClient _Db => GetDbContextAsync().Result;
public ISugarQueryable<TEntity> _DbQueryable => GetDbContextAsync().Result.Queryable<TEntity>();
private ISugarDbContextProvider<ISqlSugarDbContext> _sugarDbContextProvider;
public IAsyncQueryableExecuter AsyncExecuter { get; }
public bool? IsChangeTrackingEnabled => false;
public SqlSugarRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider)
{
_sugarDbContextProvider = sugarDbContextProvider;
}
/// <summary>
/// 获取DB
/// </summary>
/// <returns></returns>
public virtual async Task<ISqlSugarClient> GetDbContextAsync()
{
var db = (await _sugarDbContextProvider.GetDbContextAsync()).SqlSugarClient;
//await Console.Out.WriteLineAsync("获取的id" + db.ContextID);
return db;
}
/// <summary>
/// 获取简单Db
/// </summary>
/// <returns></returns>
public virtual async Task<SimpleClient<TEntity>> GetDbSimpleClientAsync()
{
var db = await GetDbContextAsync();
return new SimpleClient<TEntity>(db);
}
#region Abp模块
public virtual async Task<TEntity?> FindAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await GetFirstAsync(predicate);
}
public virtual async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await GetFirstAsync(predicate);
}
public virtual async Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
{
await this.DeleteAsync(predicate);
}
public virtual async Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
{
await this.DeleteAsync(predicate);
}
public IQueryable<TEntity> WithDetails()
{
throw new NotImplementedException();
}
public IQueryable<TEntity> WithDetails(params Expression<Func<TEntity, object>>[] propertySelectors)
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> WithDetailsAsync()
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> WithDetailsAsync(params Expression<Func<TEntity, object>>[] propertySelectors)
{
throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> GetQueryableAsync()
{
throw new NotImplementedException();
}
public virtual async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = false, CancellationToken cancellationToken = default)
{
return await GetListAsync(predicate);
}
public virtual async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
return await InsertReturnEntityAsync(entity);
}
public virtual async Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
await InsertRangeAsync(entities.ToList());
}
public virtual async Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
await UpdateAsync(entity);
return entity;
}
public virtual async Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
await UpdateRangeAsync(entities.ToList());
}
public virtual async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
await DeleteAsync(entity);
}
public virtual async Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
await DeleteAsync(entities.ToList());
}
public virtual async Task<List<TEntity>> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default)
{
return await GetListAsync();
}
public virtual async Task<long> GetCountAsync(CancellationToken cancellationToken = default)
{
return await this.CountAsync(_=>true);
}
public virtual async Task<List<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default)
{
return await GetPageListAsync(_ => true, skipCount, maxResultCount);
}
#endregion
#region DB快捷操作
public virtual async Task<IDeleteable<TEntity>> AsDeleteable()
{
return (await GetDbSimpleClientAsync()).AsDeleteable();
}
public virtual async Task<IInsertable<TEntity>> AsInsertable(List<TEntity> insertObjs)
{
return (await GetDbSimpleClientAsync()).AsInsertable(insertObjs);
}
public virtual async Task<IInsertable<TEntity>> AsInsertable(TEntity insertObj)
{
return (await GetDbSimpleClientAsync()).AsInsertable(insertObj);
}
public virtual async Task<IInsertable<TEntity>> AsInsertable(TEntity[] insertObjs)
{
return (await GetDbSimpleClientAsync()).AsInsertable(insertObjs);
}
public virtual async Task<ISugarQueryable<TEntity>> AsQueryable()
{
return (await GetDbSimpleClientAsync()).AsQueryable();
}
public virtual async Task<ISqlSugarClient> AsSugarClient()
{
return (await GetDbSimpleClientAsync()).AsSugarClient();
}
public virtual async Task<ITenant> AsTenant()
{
return (await GetDbSimpleClientAsync()).AsTenant();
}
public virtual async Task<IUpdateable<TEntity>> AsUpdateable(List<TEntity> updateObjs)
{
return (await GetDbSimpleClientAsync()).AsUpdateable(updateObjs);
}
public virtual async Task<IUpdateable<TEntity>> AsUpdateable(TEntity updateObj)
{
return (await GetDbSimpleClientAsync()).AsUpdateable(updateObj);
}
public virtual async Task<IUpdateable<TEntity>> AsUpdateable()
{
return (await GetDbSimpleClientAsync()).AsUpdateable();
}
public virtual async Task<IUpdateable<TEntity>> AsUpdateable(TEntity[] updateObjs)
{
return (await GetDbSimpleClientAsync()).AsUpdateable(updateObjs);
}
#endregion
#region SimpleClient模块
public virtual async Task<int> CountAsync(Expression<Func<TEntity, bool>> whereExpression)
{
return await (await GetDbSimpleClientAsync()).CountAsync(whereExpression);
}
public virtual async Task<bool> DeleteAsync(TEntity deleteObj)
{
if (deleteObj is ISoftDelete)
{
ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, deleteObj);
return await (await GetDbSimpleClientAsync()).UpdateAsync(deleteObj);
}
else
{
return await (await GetDbSimpleClientAsync()).DeleteAsync(deleteObj);
}
}
public virtual async Task<bool> DeleteAsync(List<TEntity> deleteObjs)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
deleteObjs.ForEach(e => ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e));
return await (await GetDbSimpleClientAsync()).UpdateRangeAsync(deleteObjs);
}
else
{
return await (await GetDbSimpleClientAsync()).DeleteAsync(deleteObjs);
}
}
public virtual async Task<bool> DeleteAsync(Expression<Func<TEntity, bool>> whereExpression)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
return await (await GetDbSimpleClientAsync()).AsUpdateable().SetColumns(nameof(ISoftDelete), true).Where(whereExpression).ExecuteCommandAsync() > 0;
}
else
{
return await (await GetDbSimpleClientAsync()).DeleteAsync(whereExpression);
}
}
public virtual async Task<bool> DeleteByIdAsync(dynamic id)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
var entity = await GetByIdAsync(id);
//反射赋值
ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, entity);
return await UpdateAsync(entity);
}
else
{
return await (await GetDbSimpleClientAsync()).DeleteByIdAsync(id);
}
}
public virtual async Task<bool> DeleteByIdsAsync(dynamic[] ids)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
var simpleClient = (await GetDbSimpleClientAsync());
var entities = await simpleClient.AsQueryable().In(ids).ToListAsync();
if (entities.Count == 0)
{
return false;
}
//反射赋值
entities.ForEach(e => ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e));
return await UpdateRangeAsync(entities);
}
else
{
return await (await GetDbSimpleClientAsync()).DeleteByIdAsync(ids);
}
}
public virtual async Task<TEntity> GetByIdAsync(dynamic id)
{
return await (await GetDbSimpleClientAsync()).GetByIdAsync(id);
}
public virtual async Task<TEntity> GetFirstAsync(Expression<Func<TEntity, bool>> whereExpression)
{
return await (await GetDbSimpleClientAsync()).GetFirstAsync(whereExpression);
}
public virtual async Task<List<TEntity>> GetListAsync()
{
return await (await GetDbSimpleClientAsync()).GetListAsync();
}
public virtual async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> whereExpression)
{
return await (await GetDbSimpleClientAsync()).GetListAsync(whereExpression);
}
public virtual async Task<List<TEntity>> GetPageListAsync(Expression<Func<TEntity, bool>> whereExpression, int pageNum, int pageSize)
{
return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression, new PageModel() { PageIndex = pageNum, PageSize = pageSize });
}
public virtual async Task<List<TEntity>> GetPageListAsync(Expression<Func<TEntity, bool>> whereExpression, int pageNum, int pageSize, Expression<Func<TEntity, object>>? orderByExpression = null, OrderByType orderByType = OrderByType.Asc)
{
return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression, new PageModel { PageIndex = pageNum, PageSize = pageSize }, orderByExpression, orderByType);
}
public virtual async Task<TEntity> GetSingleAsync(Expression<Func<TEntity, bool>> whereExpression)
{
return await (await GetDbSimpleClientAsync()).GetSingleAsync(whereExpression);
}
public virtual async Task<bool> InsertAsync(TEntity insertObj)
{
return await (await GetDbSimpleClientAsync()).InsertAsync(insertObj);
}
public virtual async Task<bool> InsertOrUpdateAsync(TEntity data)
{
return await (await GetDbSimpleClientAsync()).InsertOrUpdateAsync(data);
}
public virtual async Task<bool> InsertOrUpdateAsync(List<TEntity> datas)
{
return await (await GetDbSimpleClientAsync()).InsertOrUpdateAsync(datas);
}
public virtual async Task<bool> InsertRangeAsync(List<TEntity> insertObjs)
{
return await (await GetDbSimpleClientAsync()).InsertRangeAsync(insertObjs);
}
public virtual async Task<long> InsertReturnBigIdentityAsync(TEntity insertObj)
{
return await (await GetDbSimpleClientAsync()).InsertReturnBigIdentityAsync(insertObj);
}
public virtual async Task<TEntity> InsertReturnEntityAsync(TEntity insertObj)
{
return await (await GetDbSimpleClientAsync()).InsertReturnEntityAsync(insertObj);
}
public virtual async Task<int> InsertReturnIdentityAsync(TEntity insertObj)
{
return await (await GetDbSimpleClientAsync()).InsertReturnIdentityAsync(insertObj);
}
public virtual async Task<long> InsertReturnSnowflakeIdAsync(TEntity insertObj)
{
return await (await GetDbSimpleClientAsync()).InsertReturnSnowflakeIdAsync(insertObj);
}
public virtual async Task<bool> IsAnyAsync(Expression<Func<TEntity, bool>> whereExpression)
{
return await (await GetDbSimpleClientAsync()).IsAnyAsync(whereExpression);
}
public virtual async Task<bool> UpdateAsync(TEntity updateObj)
{
return await (await GetDbSimpleClientAsync()).UpdateAsync(updateObj);
}
public virtual async Task<bool> UpdateAsync(Expression<Func<TEntity, TEntity>> columns, Expression<Func<TEntity, bool>> whereExpression)
{
return await (await GetDbSimpleClientAsync()).UpdateAsync(columns, whereExpression);
}
public virtual async Task<bool> UpdateRangeAsync(List<TEntity> updateObjs)
{
return await (await GetDbSimpleClientAsync()).UpdateRangeAsync(updateObjs);
}
#endregion
}
public class SqlSugarRepository<TEntity, TKey> : SqlSugarRepository<TEntity>, ISqlSugarRepository<TEntity, TKey>, IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey>, new()
{
public SqlSugarRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) : base(sugarDbContextProvider)
{
}
public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
{
await DeleteByIdAsync(id);
}
public virtual async Task DeleteManyAsync(IEnumerable<TKey> ids, bool autoSave = false, CancellationToken cancellationToken = default)
{
await DeleteByIdsAsync(ids.Select(x => (object)x).ToArray());
}
public virtual async Task<TEntity?> FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await GetByIdAsync(id);
}
public virtual async Task<TEntity> GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
{
return await GetByIdAsync(id);
}
}
}

View File

@@ -1,114 +0,0 @@
using System.Reflection;
using Microsoft.Extensions.Options;
using SqlSugar;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore
{
public class SqlSugarDbConnectionCreator: ISqlSugarDbConnectionCreator,ITransientDependency
{
public SqlSugarDbConnectionCreator(IOptions<DbConnOptions> options)
{
Options = options.Value;
}
public DbConnOptions Options { get; }
public void SetDbAop(ISqlSugarClient currentDb)
{
currentDb.Aop.OnLogExecuting = this.OnLogExecuting;
currentDb.Aop.OnLogExecuted = this.OnLogExecuted;
currentDb.Aop.DataExecuting = this.DataExecuting;
currentDb.Aop.DataExecuted = this.DataExecuted;
OnSqlSugarClientConfig(currentDb);
}
public ConnectionConfig Build(Action<ConnectionConfig>? action=null)
{
var dbConnOptions = Options;
#region options
if (dbConnOptions.DbType is null)
{
throw new ArgumentException("DbType配置为空");
}
var slavaConFig = new List<SlaveConnectionConfig>();
if (dbConnOptions.EnabledReadWrite)
{
if (dbConnOptions.ReadUrl is null)
{
throw new ArgumentException("读写分离为空");
}
var readCon = dbConnOptions.ReadUrl;
readCon.ForEach(s =>
{
//如果是动态saas分库这里的连接串都不能写死需要动态添加这里只配置共享库的连接
slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s });
});
}
#endregion
#region config
var connectionConfig = new ConnectionConfig()
{
ConfigId= ConnectionStrings.DefaultConnectionStringName,
DbType = dbConnOptions.DbType ?? DbType.Sqlite,
ConnectionString = dbConnOptions.Url,
IsAutoCloseConnection = true,
SlaveConnectionConfigs = slavaConFig,
//设置codefirst非空值判断
ConfigureExternalServices = new ConfigureExternalServices
{
EntityService = (c, p) =>
{
if (new NullabilityInfoContext()
.Create(c).WriteState is NullabilityState.Nullable)
{
p.IsNullable = true;
}
EntityService(c, p);
}
},
//这里多租户有个坑,无效的
AopEvents = new AopEvents
{
DataExecuted = DataExecuted,
DataExecuting = DataExecuting,
OnLogExecuted = OnLogExecuted,
OnLogExecuting = OnLogExecuting
}
};
if (action is not null)
{
action.Invoke(connectionConfig);
}
#endregion
return connectionConfig;
}
[DisablePropertyInjection]
public Action<ISqlSugarClient> OnSqlSugarClientConfig { get; set; }
[DisablePropertyInjection]
public Action<object, DataAfterModel> DataExecuted { get; set; }
[DisablePropertyInjection]
public Action<object, DataFilterModel> DataExecuting { get; set; }
[DisablePropertyInjection]
public Action<string, SugarParameter[]> OnLogExecuting { get; set; }
[DisablePropertyInjection]
public Action<string, SugarParameter[]> OnLogExecuted { get; set; }
[DisablePropertyInjection]
public Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; }
}
}

View File

@@ -1,371 +0,0 @@
using System;
using System.Collections;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using SqlSugar;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Users;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore
{
public class SqlSugarDbContext : ISqlSugarDbContext
{
/// <summary>
/// SqlSugar 客户端
/// </summary>
public ISqlSugarClient SqlSugarClient { get; private set; }
public ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
private IAbpLazyServiceProvider LazyServiceProvider { get; }
private IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
protected ILoggerFactory Logger => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
private ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false;
protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;
public IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
public AbpDbConnectionOptions ConnectionOptions => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpDbConnectionOptions>>().Value;
private ISqlSugarDbConnectionCreator _dbConnectionCreator;
public void SetSqlSugarClient(ISqlSugarClient sqlSugarClient)
{
SqlSugarClient = sqlSugarClient;
}
public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
{
LazyServiceProvider = lazyServiceProvider;
var connectionCreator = LazyServiceProvider.LazyGetRequiredService<ISqlSugarDbConnectionCreator>();
_dbConnectionCreator = connectionCreator;
connectionCreator.OnSqlSugarClientConfig = OnSqlSugarClientConfig;
connectionCreator.EntityService = EntityService;
connectionCreator.DataExecuting = DataExecuting;
connectionCreator.DataExecuted = DataExecuted;
connectionCreator.OnLogExecuting = OnLogExecuting;
connectionCreator.OnLogExecuted = OnLogExecuted;
SqlSugarClient = new SqlSugarClient(connectionCreator.Build(action: options =>
{
options.ConnectionString = GetCurrentConnectionString();
options.DbType = GetCurrentDbType();
}));
connectionCreator.SetDbAop(SqlSugarClient);
}
/// <summary>
/// db切换多库支持
/// </summary>
/// <returns></returns>
protected virtual string GetCurrentConnectionString()
{
var defautlUrl = Options.Url ?? ConnectionOptions.GetConnectionStringOrNull(ConnectionStrings.DefaultConnectionStringName);
//如果未开启多租户返回db url 或者 默认连接字符串
if (!Options.EnabledSaasMultiTenancy)
{
return defautlUrl;
}
//开启了多租户
var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService<IConnectionStringResolver>();
var connectionString = connectionStringResolver.ResolveAsync().GetAwaiter().GetResult();
//没有检测到使用多租户功能,默认使用默认库即可
if (string.IsNullOrWhiteSpace(connectionString))
{
Volo.Abp.Check.NotNull(Options.Url, "租户默认库Defalut未找到");
connectionString = defautlUrl;
}
return connectionString!;
}
protected virtual DbType GetCurrentDbType()
{
if (CurrentTenant.Name is not null)
{
var dbTypeFromTenantName = GetDbTypeFromTenantName(CurrentTenant.Name);
if (dbTypeFromTenantName is not null)
{
return dbTypeFromTenantName.Value;
}
}
Volo.Abp.Check.NotNull(Options.DbType, "默认DbType未配置");
return Options.DbType!.Value;
}
//根据租户name进行匹配db类型: Test_Sqlite[来自AI]
private DbType? GetDbTypeFromTenantName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return null;
}
// 查找下划线的位置
int underscoreIndex = name.LastIndexOf('_');
if (underscoreIndex == -1 || underscoreIndex == name.Length - 1)
{
return null;
}
// 提取 枚举 部分
string enumString = name.Substring(underscoreIndex + 1);
// 尝试将 尾缀 转换为枚举
if (Enum.TryParse<DbType>(enumString, out DbType result))
{
return result;
}
// 条件不满足时返回 null
return null;
}
/// <summary>
/// 上下文对象扩展
/// </summary>
/// <param name="sqlSugarClient"></param>
protected virtual void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
{
//需自定义扩展
if (IsSoftDeleteFilterEnabled)
{
sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(u => u.IsDeleted == false);
}
if (IsMultiTenantFilterEnabled)
{
//表达式不能放方法
Guid? tenantId = CurrentTenant?.Id;
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == tenantId);
}
CustomDataFilter(sqlSugarClient);
}
protected virtual void CustomDataFilter(ISqlSugarClient sqlSugarClient)
{
}
protected virtual void DataExecuted(object oldValue, DataAfterModel entityInfo)
{
}
/// <summary>
/// 数据
/// </summary>
/// <param name="oldValue"></param>
/// <param name="entityInfo"></param>
protected virtual void DataExecuting(object oldValue, DataFilterModel entityInfo)
{
//审计日志
switch (entityInfo.OperationType)
{
case DataFilterType.UpdateByObject:
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime)))
{
if (!DateTime.MinValue.Equals(oldValue))
{
entityInfo.SetValue(DateTime.Now);
}
}
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
{
if (CurrentUser.Id != null)
{
entityInfo.SetValue(CurrentUser.Id);
}
}
break;
case DataFilterType.InsertByObject:
if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id)))
{
//主键为空或者为默认最小值
if (Guid.Empty.Equals(oldValue))
{
entityInfo.SetValue(GuidGenerator.Create());
}
}
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
{
//为空或者为默认最小值
if (oldValue is null || DateTime.MinValue.Equals(oldValue))
{
entityInfo.SetValue(DateTime.Now);
}
}
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
{
if (CurrentUser.Id != null)
{
entityInfo.SetValue(CurrentUser.Id);
}
}
//插入时需要租户id,先预留
if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
{
if (CurrentTenant is not null)
{
entityInfo.SetValue(CurrentTenant.Id);
}
}
break;
}
//领域事件
switch (entityInfo.OperationType)
{
case DataFilterType.InsertByObject:
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
{
EntityChangeEventHelper.PublishEntityCreatedEvent(entityInfo.EntityValue);
}
break;
case DataFilterType.UpdateByObject:
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
{
//软删除,发布的是删除事件
if (entityInfo.EntityValue is ISoftDelete softDelete)
{
if (softDelete.IsDeleted == true)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entityInfo.EntityValue);
}
}
else
{
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityInfo.EntityValue);
}
}
break;
case DataFilterType.DeleteByObject:
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
{
//这里sqlsugar有个特殊删除会返回批量的结果
if (entityInfo.EntityValue is IEnumerable entityValues)
{
foreach (var entityValue in entityValues)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entityValue);
}
}
}
break;
}
}
/// <summary>
/// 日志
/// </summary>
/// <param name="sql"></param>
/// <param name="pars"></param>
protected virtual void OnLogExecuting(string sql, SugarParameter[] pars)
{
if (Options.EnabledSqlLog)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("==========Yi-SQL执行:==========");
sb.AppendLine(UtilMethods.GetSqlString(DbType.SqlServer, sql, pars));
sb.AppendLine("===============================");
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sb.ToString());
}
}
/// <summary>
/// 日志
/// </summary>
/// <param name="sql"></param>
/// <param name="pars"></param>
protected virtual void OnLogExecuted(string sql, SugarParameter[] pars)
{
if (Options.EnabledSqlLog)
{
var sqllog = $"=========Yi-SQL耗时{SqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}毫秒=====";
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sqllog.ToString());
}
}
/// <summary>
/// 实体配置
/// </summary>
/// <param name="property"></param>
/// <param name="column"></param>
protected virtual void EntityService(PropertyInfo property, EntityColumnInfo column)
{
if (property.Name == "ConcurrencyStamp")
{
column.IsIgnore = true;
}
if (property.PropertyType == typeof(ExtraPropertyDictionary))
{
column.IsIgnore = true;
}
if (property.Name == nameof(Entity<object>.Id))
{
column.IsPrimarykey = true;
}
}
public void BackupDataBase()
{
string directoryName = "database_backup";
string fileName = DateTime.Now.ToString($"yyyyMMdd_HHmmss") + $"_{SqlSugarClient.Ado.Connection.Database}";
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
switch (Options.DbType)
{
case DbType.MySql:
//MySql
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database, $"{Path.Combine(directoryName, fileName)}.sql");//mysql 只支持.net core
break;
case DbType.Sqlite:
//Sqlite
SqlSugarClient.DbMaintenance.BackupDataBase(null, $"{fileName}.db"); //sqlite 只支持.net core
break;
case DbType.SqlServer:
//SqlServer
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database, $"{Path.Combine(directoryName, fileName)}.bak"/*服务器路径*/);//第一个参数库名
break;
default:
throw new NotImplementedException("其他数据库备份未实现");
}
}
}
}

View File

@@ -1,29 +0,0 @@
using System.Data.Common;
using Volo.Abp;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore;
public class SqlSugarDbContextCreationContext
{
public static SqlSugarDbContextCreationContext Current => _current.Value;
private static readonly AsyncLocal<SqlSugarDbContextCreationContext> _current = new AsyncLocal<SqlSugarDbContextCreationContext>();
public string ConnectionStringName { get; }
public string ConnectionString { get; }
public DbConnection ExistingConnection { get; internal set; }
public SqlSugarDbContextCreationContext(string connectionStringName, string connectionString)
{
ConnectionStringName = connectionStringName;
ConnectionString = connectionString;
}
public static IDisposable Use(SqlSugarDbContextCreationContext context)
{
var previousValue = Current;
_current.Value = context;
return new DisposeAction(() => _current.Value = previousValue);
}
}

View File

@@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore
{
public static class SqlsugarCoreExtensions
{
public static IServiceCollection AddYiDbContext<DbContext>(this IServiceCollection service, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) where DbContext : class, ISqlSugarDbContext
{
service.Replace(new ServiceDescriptor(typeof(ISqlSugarDbContext), typeof(DbContext), serviceLifetime));
return service;
}
public static IServiceCollection TryAddYiDbContext<DbContext>(this IServiceCollection service, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) where DbContext : class, ISqlSugarDbContext
{
service.TryAdd(new ServiceDescriptor(typeof(ISqlSugarDbContext), typeof(DbContext), serviceLifetime));
return service;
}
public static IServiceCollection AddYiDbContext<DbContext>(this IServiceCollection service, Action<DbConnOptions> options) where DbContext : class, ISqlSugarDbContext
{
service.Configure<DbConnOptions>(ops =>
{
options.Invoke(ops);
});
service.AddYiDbContext<DbContext>();
return service;
}
}
}

View File

@@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Uow;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.SqlSugarCore.Uow
{
public class SqlSugarDatabaseApi : IDatabaseApi
{
public ISqlSugarDbContext DbContext { get; }
public SqlSugarDatabaseApi(ISqlSugarDbContext dbContext)
{
DbContext = dbContext;
}
}
}

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