feat:框架基础设施搭建

This commit is contained in:
橙子
2023-04-12 22:52:09 +08:00
parent 5efdffcda8
commit 18696ec542
572 changed files with 26077 additions and 25 deletions

View File

@@ -0,0 +1,3 @@
<Project>
</Project>

View File

@@ -0,0 +1,90 @@

using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyCompany("YiFramework")]
[assembly: AssemblyFileVersion(VersionInfo.FullVersion)]
[assembly: AssemblyInformationalVersion(VersionInfo.FullVersion)]
[assembly: AssemblyVersion(VersionInfo.FullVersion)]
[assembly: ComVisible(false)]
#pragma warning disable IDE1006 // 命名样式
internal static class VersionInfo
{
/// <summary>
/// 主版本: 项目进行了重大修改导致不再向下兼容主版本号加1其它版本号清0
/// </summary>
public const string Major = "1";
/// <summary>
/// 次版本项目进行了重构增加了功能但向下兼容子版本号加1主版本号不变 修正版本号清0
/// </summary>
public const string Minor = "1";
/// <summary>
/// 生成号
/// </summary>
public const string Build = "0";
/// <summary>
/// 修订号项目进行了Bug修复向下兼容修正版本号加1主版本号、子版本号不 变;
/// </summary>
public const string Revision = "0";
/// <summary>
/// 版本名称
/// </summary>
public const string VersionName = null;
/// <summary>
/// 版本
/// </summary>
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;
#pragma warning disable CS1570 // XML 注释出现 XML 格式错误
/// <summary>
/// 比较 a,b两个版本
/// 当 a > b 时,返回 1
/// 当 a = b 时,返回 0
/// 当 a < b 时,返回 -1
/// </summary>
#pragma warning restore CS1570 // XML 注释出现 XML 格式错误
public static int Compare(this Version a, Version b)
{
// 比较主版本
if (a.Major != b.Major)
{
return a.Major > b.Major ? 1 : -1;
}
// 比较次版本
if (a.Minor != b.Minor)
{
return a.Minor > b.Minor ? 1 : -1;
}
// 比较生成号
if (a.Build < 0 || b.Build < 0)
{
return 0;
}
if (a.Build != b.Build)
{
return a.Build > b.Build ? 1 : -1;
}
// 比较修订号
if (a.Revision < 0 || b.Revision < 0)
{
return 0;
}
if (a.Revision != b.Revision)
{
return a.Revision > b.Revision ? 1 : -1;
}
return 0;
}
#pragma warning restore IDE1006 // 命名样式
}

View File

@@ -0,0 +1,332 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33103.184
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{EEF5F221-0E32-4A3D-B647-B4B5E7305806}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{32A813F5-13B2-4DCA-8B59-F27F1B0D5678}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "framework", "framework", "{5F2B846D-96CE-400A-878E-220498F4EE31}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core", "src\framework\Yi.Framework.Core\Yi.Framework.Core.csproj", "{83B2D7AD-ED8E-4392-B0AE-4227498CD75F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Application", "src\project\template\Yi.Template.Application\Yi.Template.Application.csproj", "{456835D1-4968-4195-9993-B2A580E85056}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Application.Contracts", "src\project\template\Yi.Template.Application.Contracts\Yi.Template.Application.Contracts.csproj", "{D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Domain", "src\project\template\Yi.Template.Domain\Yi.Template.Domain.csproj", "{C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Domain.Shared", "src\project\template\Yi.Template.Domain.Shared\Yi.Template.Domain.Shared.csproj", "{26171153-1784-455B-9582-0558AEEC03CF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Sqlsugar", "src\project\template\Yi.Template.Sqlsugar\Yi.Template.Sqlsugar.csproj", "{3C3A7BAC-F27F-433E-BF91-289FA42E4995}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Template.Web", "src\project\template\Yi.Template.Web\Yi.Template.Web.csproj", "{01CC7B62-F42C-45CE-BACA-F450593A1AF2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.BackgroundJobs.Quartz", "src\module\Yi.Framework.BackgroundJobs.Quartz\Yi.Framework.BackgroundJobs.Quartz.csproj", "{1879A863-9864-4E16-8492-504055807684}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Ddd", "src\framework\Yi.Framework.Ddd\Yi.Framework.Ddd.csproj", "{949F35A7-36E4-4080-9940-24BE52532078}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core.Autofac", "src\framework\Yi.Framework.Core.Autofac\Yi.Framework.Core.Autofac.csproj", "{63BA134E-9D23-4EB8-87E4-B45B33D954F5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.AspNetCore", "src\framework\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj", "{2F5E5843-14FB-48F1-AEB0-B9FFE103B972}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching", "src\module\Yi.Framework.Caching\Yi.Framework.Caching.csproj", "{8767C5B7-3A17-4729-BCAA-B391B6A215AA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching.Redis", "src\module\Yi.Framework.Caching.Redis\Yi.Framework.Caching.Redis.csproj", "{F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching.MemoryCache", "src\module\Yi.Framework.Caching.MemoryCache\Yi.Framework.Caching.MemoryCache.csproj", "{67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Uow", "src\framework\Yi.Framework.Uow\Yi.Framework.Uow.csproj", "{3D83BE69-71BB-43BE-B3F1-A532215561CD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core.Sqlsugar", "src\framework\Yi.Framework.Core.Sqlsugar\Yi.Framework.Core.Sqlsugar.csproj", "{58F4071D-66B7-4839-A247-79AF0E4E1C8E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Core.Mapster", "src\framework\Yi.Framework.Core.AutoMapper\Yi.Framework.Core.Mapster.csproj", "{DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Office.Excel", "src\module\Yi.Framework.Office.Excel\Yi.Framework.Office.Excel.csproj", "{4EEC6607-F0D8-4277-9463-104DA7E184B6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.WeChatPay", "src\module\Yi.Framework.WeChatPay\Yi.Framework.WeChatPay.csproj", "{588D0DA9-303A-4FF0-A2D1-83037E2B269F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Data", "src\framework\Yi.Framework.Data\Yi.Framework.Data.csproj", "{DEE07142-32CE-4B5F-A5A3-452064EBF4A2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Auth.JwtBearer", "src\framework\Yi.Framework.Auth.JwtBearer\Yi.Framework.Auth.JwtBearer.csproj", "{D40C583D-58BE-422D-9A57-94DECB751EB4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Template", "src\module\Yi.Framework.Template\Yi.Framework.Template.csproj", "{134C4AB9-2AFE-4383-84DE-825DF9499CB4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "template", "template", "{A3707874-7890-42AF-A686-E3AACD6F108C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bbs", "bbs", "{B758A87D-0BFA-44A5-BA33-FBA44151CEB4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Domain.Shared", "src\project\bbs\Yi.BBS.Domain.Shared\Yi.BBS.Domain.Shared.csproj", "{DEA3342F-1954-4EE9-9A59-CAF1D7832F33}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Domain", "src\project\bbs\Yi.BBS.Domain\Yi.BBS.Domain.csproj", "{86C82BB6-E333-40E8-8DDE-20C3A538433C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Application.Contracts", "src\project\bbs\Yi.BBS.Application.Contracts\Yi.BBS.Application.Contracts.csproj", "{679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Sqlsugar", "src\project\bbs\Yi.BBS.Sqlsugar\Yi.BBS.Sqlsugar.csproj", "{A8043204-9DAC-4F08-8C73-423CB72927EF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Web", "src\project\bbs\Yi.BBS.Web\Yi.BBS.Web.csproj", "{83BE964D-D53C-4D1B-B8C6-5306C393C07F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.BBS.Application", "src\project\bbs\Yi.BBS.Application\Yi.BBS.Application.csproj", "{959A33C5-7826-4AE7-AC51-40BDC2B767B2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rbac", "rbac", "{07C9E949-DB5E-4315-A497-FF73746667D8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Domain.Shared", "src\project\rbac\Yi.RBAC.Domain.Shared\Yi.RBAC.Domain.Shared.csproj", "{5467178B-3731-4346-A0A3-3CB1AC0953AB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Domain", "src\project\rbac\Yi.RBAC.Domain\Yi.RBAC.Domain.csproj", "{2E082104-D3A6-40DE-A4E5-DE326B75A62D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Sqlsugar", "src\project\rbac\Yi.RBAC.Sqlsugar\Yi.RBAC.Sqlsugar.csproj", "{ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Application.Contracts", "src\project\rbac\Yi.RBAC.Application.Contracts\Yi.RBAC.Application.Contracts.csproj", "{478DA36E-F547-49CD-8B48-41DC5551C5C2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Application", "src\project\rbac\Yi.RBAC.Application\Yi.RBAC.Application.csproj", "{2074EA00-59A4-49CE-97A6-735F4B77443B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.RBAC.Web", "src\project\rbac\Yi.RBAC.Web\Yi.RBAC.Web.csproj", "{0C031C7D-6F80-4559-977C-AC001036EC44}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.ImageSharp", "src\module\Yi.Framework.ImageSharp\Yi.Framework.ImageSharp.csproj", "{60E54034-792C-4A90-BCDF-4D5FFB45089E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.EventBus", "src\module\Yi.Framework.EventBus\Yi.Framework.EventBus.csproj", "{FC559052-36EC-4379-B447-298FAD6045F4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{12EA3BCF-8991-4010-B41E-67C476CBA690}"
ProjectSection(SolutionItems) = preProject
..\.gitignore = ..\.gitignore
Build.props = Build.props
..\readme\git提交规范.txt = ..\readme\git提交规范.txt
src\project\rbac\GlobalUsings.cs = src\project\rbac\GlobalUsings.cs
Version.cs = Version.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.OperLogManager", "src\module\Yi.Framework.OperLogManager\Yi.Framework.OperLogManager.csproj", "{8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.FileManager", "src\module\Yi.Framework.FileManager\Yi.Framework.FileManager.csproj", "{1BF3115D-B027-4805-AF7B-41B3AE9CB355}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.MultiTenancy", "src\framework\Yi.Framework.MultiTenancy\Yi.Framework.MultiTenancy.csproj", "{590B1EC0-CDA9-4937-BE07-FBB04437D21F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.DictionaryManager", "src\module\Yi.Framework.DictionaryManager\Yi.Framework.DictionaryManager.csproj", "{8941B30D-698B-477A-8737-43E7B4A8695A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Sms.Aliyun", "src\module\Yi.Framework.Sms.Aliyun\Yi.Framework.Sms.Aliyun.csproj", "{063178CF-C5B9-463C-A8A4-F32B743818E2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{83B2D7AD-ED8E-4392-B0AE-4227498CD75F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{83B2D7AD-ED8E-4392-B0AE-4227498CD75F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83B2D7AD-ED8E-4392-B0AE-4227498CD75F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83B2D7AD-ED8E-4392-B0AE-4227498CD75F}.Release|Any CPU.Build.0 = Release|Any CPU
{456835D1-4968-4195-9993-B2A580E85056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{456835D1-4968-4195-9993-B2A580E85056}.Debug|Any CPU.Build.0 = Debug|Any CPU
{456835D1-4968-4195-9993-B2A580E85056}.Release|Any CPU.ActiveCfg = Release|Any CPU
{456835D1-4968-4195-9993-B2A580E85056}.Release|Any CPU.Build.0 = Release|Any CPU
{D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2378C23-2CFE-468A-924A-B8C9D4A3A8ED}.Release|Any CPU.Build.0 = Release|Any CPU
{C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828}.Release|Any CPU.Build.0 = Release|Any CPU
{26171153-1784-455B-9582-0558AEEC03CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26171153-1784-455B-9582-0558AEEC03CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26171153-1784-455B-9582-0558AEEC03CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26171153-1784-455B-9582-0558AEEC03CF}.Release|Any CPU.Build.0 = Release|Any CPU
{3C3A7BAC-F27F-433E-BF91-289FA42E4995}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C3A7BAC-F27F-433E-BF91-289FA42E4995}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C3A7BAC-F27F-433E-BF91-289FA42E4995}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C3A7BAC-F27F-433E-BF91-289FA42E4995}.Release|Any CPU.Build.0 = Release|Any CPU
{01CC7B62-F42C-45CE-BACA-F450593A1AF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01CC7B62-F42C-45CE-BACA-F450593A1AF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01CC7B62-F42C-45CE-BACA-F450593A1AF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01CC7B62-F42C-45CE-BACA-F450593A1AF2}.Release|Any CPU.Build.0 = Release|Any CPU
{1879A863-9864-4E16-8492-504055807684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1879A863-9864-4E16-8492-504055807684}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1879A863-9864-4E16-8492-504055807684}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1879A863-9864-4E16-8492-504055807684}.Release|Any CPU.Build.0 = Release|Any CPU
{949F35A7-36E4-4080-9940-24BE52532078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{949F35A7-36E4-4080-9940-24BE52532078}.Debug|Any CPU.Build.0 = Debug|Any CPU
{949F35A7-36E4-4080-9940-24BE52532078}.Release|Any CPU.ActiveCfg = Release|Any CPU
{949F35A7-36E4-4080-9940-24BE52532078}.Release|Any CPU.Build.0 = Release|Any CPU
{63BA134E-9D23-4EB8-87E4-B45B33D954F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63BA134E-9D23-4EB8-87E4-B45B33D954F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{63BA134E-9D23-4EB8-87E4-B45B33D954F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63BA134E-9D23-4EB8-87E4-B45B33D954F5}.Release|Any CPU.Build.0 = Release|Any CPU
{2F5E5843-14FB-48F1-AEB0-B9FFE103B972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F5E5843-14FB-48F1-AEB0-B9FFE103B972}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F5E5843-14FB-48F1-AEB0-B9FFE103B972}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F5E5843-14FB-48F1-AEB0-B9FFE103B972}.Release|Any CPU.Build.0 = Release|Any CPU
{8767C5B7-3A17-4729-BCAA-B391B6A215AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8767C5B7-3A17-4729-BCAA-B391B6A215AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8767C5B7-3A17-4729-BCAA-B391B6A215AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8767C5B7-3A17-4729-BCAA-B391B6A215AA}.Release|Any CPU.Build.0 = Release|Any CPU
{F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41}.Release|Any CPU.Build.0 = Release|Any CPU
{67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C}.Release|Any CPU.Build.0 = Release|Any CPU
{3D83BE69-71BB-43BE-B3F1-A532215561CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D83BE69-71BB-43BE-B3F1-A532215561CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D83BE69-71BB-43BE-B3F1-A532215561CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D83BE69-71BB-43BE-B3F1-A532215561CD}.Release|Any CPU.Build.0 = Release|Any CPU
{58F4071D-66B7-4839-A247-79AF0E4E1C8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58F4071D-66B7-4839-A247-79AF0E4E1C8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58F4071D-66B7-4839-A247-79AF0E4E1C8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58F4071D-66B7-4839-A247-79AF0E4E1C8E}.Release|Any CPU.Build.0 = Release|Any CPU
{DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26}.Release|Any CPU.Build.0 = Release|Any CPU
{4EEC6607-F0D8-4277-9463-104DA7E184B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EEC6607-F0D8-4277-9463-104DA7E184B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EEC6607-F0D8-4277-9463-104DA7E184B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EEC6607-F0D8-4277-9463-104DA7E184B6}.Release|Any CPU.Build.0 = Release|Any CPU
{588D0DA9-303A-4FF0-A2D1-83037E2B269F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{588D0DA9-303A-4FF0-A2D1-83037E2B269F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{588D0DA9-303A-4FF0-A2D1-83037E2B269F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{588D0DA9-303A-4FF0-A2D1-83037E2B269F}.Release|Any CPU.Build.0 = Release|Any CPU
{DEE07142-32CE-4B5F-A5A3-452064EBF4A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DEE07142-32CE-4B5F-A5A3-452064EBF4A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEE07142-32CE-4B5F-A5A3-452064EBF4A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEE07142-32CE-4B5F-A5A3-452064EBF4A2}.Release|Any CPU.Build.0 = Release|Any CPU
{D40C583D-58BE-422D-9A57-94DECB751EB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D40C583D-58BE-422D-9A57-94DECB751EB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D40C583D-58BE-422D-9A57-94DECB751EB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D40C583D-58BE-422D-9A57-94DECB751EB4}.Release|Any CPU.Build.0 = Release|Any CPU
{134C4AB9-2AFE-4383-84DE-825DF9499CB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{134C4AB9-2AFE-4383-84DE-825DF9499CB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{134C4AB9-2AFE-4383-84DE-825DF9499CB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{134C4AB9-2AFE-4383-84DE-825DF9499CB4}.Release|Any CPU.Build.0 = Release|Any CPU
{DEA3342F-1954-4EE9-9A59-CAF1D7832F33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DEA3342F-1954-4EE9-9A59-CAF1D7832F33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEA3342F-1954-4EE9-9A59-CAF1D7832F33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEA3342F-1954-4EE9-9A59-CAF1D7832F33}.Release|Any CPU.Build.0 = Release|Any CPU
{86C82BB6-E333-40E8-8DDE-20C3A538433C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86C82BB6-E333-40E8-8DDE-20C3A538433C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86C82BB6-E333-40E8-8DDE-20C3A538433C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86C82BB6-E333-40E8-8DDE-20C3A538433C}.Release|Any CPU.Build.0 = Release|Any CPU
{679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1}.Release|Any CPU.Build.0 = Release|Any CPU
{A8043204-9DAC-4F08-8C73-423CB72927EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8043204-9DAC-4F08-8C73-423CB72927EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8043204-9DAC-4F08-8C73-423CB72927EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8043204-9DAC-4F08-8C73-423CB72927EF}.Release|Any CPU.Build.0 = Release|Any CPU
{83BE964D-D53C-4D1B-B8C6-5306C393C07F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{83BE964D-D53C-4D1B-B8C6-5306C393C07F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83BE964D-D53C-4D1B-B8C6-5306C393C07F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83BE964D-D53C-4D1B-B8C6-5306C393C07F}.Release|Any CPU.Build.0 = Release|Any CPU
{959A33C5-7826-4AE7-AC51-40BDC2B767B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{959A33C5-7826-4AE7-AC51-40BDC2B767B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{959A33C5-7826-4AE7-AC51-40BDC2B767B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{959A33C5-7826-4AE7-AC51-40BDC2B767B2}.Release|Any CPU.Build.0 = Release|Any CPU
{5467178B-3731-4346-A0A3-3CB1AC0953AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5467178B-3731-4346-A0A3-3CB1AC0953AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5467178B-3731-4346-A0A3-3CB1AC0953AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5467178B-3731-4346-A0A3-3CB1AC0953AB}.Release|Any CPU.Build.0 = Release|Any CPU
{2E082104-D3A6-40DE-A4E5-DE326B75A62D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E082104-D3A6-40DE-A4E5-DE326B75A62D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E082104-D3A6-40DE-A4E5-DE326B75A62D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E082104-D3A6-40DE-A4E5-DE326B75A62D}.Release|Any CPU.Build.0 = Release|Any CPU
{ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ECF1AA6F-8FCD-428F-9648-2DAE3C345C96}.Release|Any CPU.Build.0 = Release|Any CPU
{478DA36E-F547-49CD-8B48-41DC5551C5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{478DA36E-F547-49CD-8B48-41DC5551C5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{478DA36E-F547-49CD-8B48-41DC5551C5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{478DA36E-F547-49CD-8B48-41DC5551C5C2}.Release|Any CPU.Build.0 = Release|Any CPU
{2074EA00-59A4-49CE-97A6-735F4B77443B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2074EA00-59A4-49CE-97A6-735F4B77443B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2074EA00-59A4-49CE-97A6-735F4B77443B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2074EA00-59A4-49CE-97A6-735F4B77443B}.Release|Any CPU.Build.0 = Release|Any CPU
{0C031C7D-6F80-4559-977C-AC001036EC44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C031C7D-6F80-4559-977C-AC001036EC44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C031C7D-6F80-4559-977C-AC001036EC44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C031C7D-6F80-4559-977C-AC001036EC44}.Release|Any CPU.Build.0 = Release|Any CPU
{60E54034-792C-4A90-BCDF-4D5FFB45089E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60E54034-792C-4A90-BCDF-4D5FFB45089E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60E54034-792C-4A90-BCDF-4D5FFB45089E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60E54034-792C-4A90-BCDF-4D5FFB45089E}.Release|Any CPU.Build.0 = Release|Any CPU
{FC559052-36EC-4379-B447-298FAD6045F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC559052-36EC-4379-B447-298FAD6045F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC559052-36EC-4379-B447-298FAD6045F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC559052-36EC-4379-B447-298FAD6045F4}.Release|Any CPU.Build.0 = Release|Any CPU
{8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A604A6B-D1FA-4CFF-BCF5-557519B10FCB}.Release|Any CPU.Build.0 = Release|Any CPU
{1BF3115D-B027-4805-AF7B-41B3AE9CB355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BF3115D-B027-4805-AF7B-41B3AE9CB355}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BF3115D-B027-4805-AF7B-41B3AE9CB355}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BF3115D-B027-4805-AF7B-41B3AE9CB355}.Release|Any CPU.Build.0 = Release|Any CPU
{590B1EC0-CDA9-4937-BE07-FBB04437D21F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{590B1EC0-CDA9-4937-BE07-FBB04437D21F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{590B1EC0-CDA9-4937-BE07-FBB04437D21F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{590B1EC0-CDA9-4937-BE07-FBB04437D21F}.Release|Any CPU.Build.0 = Release|Any CPU
{8941B30D-698B-477A-8737-43E7B4A8695A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8941B30D-698B-477A-8737-43E7B4A8695A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8941B30D-698B-477A-8737-43E7B4A8695A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8941B30D-698B-477A-8737-43E7B4A8695A}.Release|Any CPU.Build.0 = Release|Any CPU
{063178CF-C5B9-463C-A8A4-F32B743818E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{063178CF-C5B9-463C-A8A4-F32B743818E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{063178CF-C5B9-463C-A8A4-F32B743818E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{063178CF-C5B9-463C-A8A4-F32B743818E2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{83B2D7AD-ED8E-4392-B0AE-4227498CD75F} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{456835D1-4968-4195-9993-B2A580E85056} = {A3707874-7890-42AF-A686-E3AACD6F108C}
{D2378C23-2CFE-468A-924A-B8C9D4A3A8ED} = {A3707874-7890-42AF-A686-E3AACD6F108C}
{C02A954D-CCCB-41BD-ADAD-9D7ECBF1A828} = {A3707874-7890-42AF-A686-E3AACD6F108C}
{26171153-1784-455B-9582-0558AEEC03CF} = {A3707874-7890-42AF-A686-E3AACD6F108C}
{3C3A7BAC-F27F-433E-BF91-289FA42E4995} = {A3707874-7890-42AF-A686-E3AACD6F108C}
{01CC7B62-F42C-45CE-BACA-F450593A1AF2} = {A3707874-7890-42AF-A686-E3AACD6F108C}
{1879A863-9864-4E16-8492-504055807684} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{949F35A7-36E4-4080-9940-24BE52532078} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{63BA134E-9D23-4EB8-87E4-B45B33D954F5} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{2F5E5843-14FB-48F1-AEB0-B9FFE103B972} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{8767C5B7-3A17-4729-BCAA-B391B6A215AA} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{F13D4F03-3FA0-43E9-BBAA-F618E1A3CF41} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{67CF07AB-2A72-4B36-A3A5-4CEB82B7C43C} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{3D83BE69-71BB-43BE-B3F1-A532215561CD} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{58F4071D-66B7-4839-A247-79AF0E4E1C8E} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{DFD34702-2EF6-4ECC-AE6E-9A1A3885BD26} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{4EEC6607-F0D8-4277-9463-104DA7E184B6} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{588D0DA9-303A-4FF0-A2D1-83037E2B269F} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{DEE07142-32CE-4B5F-A5A3-452064EBF4A2} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{D40C583D-58BE-422D-9A57-94DECB751EB4} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{134C4AB9-2AFE-4383-84DE-825DF9499CB4} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{A3707874-7890-42AF-A686-E3AACD6F108C} = {32A813F5-13B2-4DCA-8B59-F27F1B0D5678}
{B758A87D-0BFA-44A5-BA33-FBA44151CEB4} = {32A813F5-13B2-4DCA-8B59-F27F1B0D5678}
{DEA3342F-1954-4EE9-9A59-CAF1D7832F33} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4}
{86C82BB6-E333-40E8-8DDE-20C3A538433C} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4}
{679625DD-4BF6-4CD6-99FD-7A3E6D9B04A1} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4}
{A8043204-9DAC-4F08-8C73-423CB72927EF} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4}
{83BE964D-D53C-4D1B-B8C6-5306C393C07F} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4}
{959A33C5-7826-4AE7-AC51-40BDC2B767B2} = {B758A87D-0BFA-44A5-BA33-FBA44151CEB4}
{07C9E949-DB5E-4315-A497-FF73746667D8} = {32A813F5-13B2-4DCA-8B59-F27F1B0D5678}
{5467178B-3731-4346-A0A3-3CB1AC0953AB} = {07C9E949-DB5E-4315-A497-FF73746667D8}
{2E082104-D3A6-40DE-A4E5-DE326B75A62D} = {07C9E949-DB5E-4315-A497-FF73746667D8}
{ECF1AA6F-8FCD-428F-9648-2DAE3C345C96} = {07C9E949-DB5E-4315-A497-FF73746667D8}
{478DA36E-F547-49CD-8B48-41DC5551C5C2} = {07C9E949-DB5E-4315-A497-FF73746667D8}
{2074EA00-59A4-49CE-97A6-735F4B77443B} = {07C9E949-DB5E-4315-A497-FF73746667D8}
{0C031C7D-6F80-4559-977C-AC001036EC44} = {07C9E949-DB5E-4315-A497-FF73746667D8}
{60E54034-792C-4A90-BCDF-4D5FFB45089E} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{FC559052-36EC-4379-B447-298FAD6045F4} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{8A604A6B-D1FA-4CFF-BCF5-557519B10FCB} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{1BF3115D-B027-4805-AF7B-41B3AE9CB355} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{590B1EC0-CDA9-4937-BE07-FBB04437D21F} = {5F2B846D-96CE-400A-878E-220498F4EE31}
{8941B30D-698B-477A-8737-43E7B4A8695A} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
{063178CF-C5B9-463C-A8A4-F32B743818E2} = {EEF5F221-0E32-4A3D-B647-B4B5E7305806}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6C1A3808-0F4F-43FB-A9FE-5F27A3BB2ECF}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,99 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Yi.Framework.AspNetCore.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"];
}
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AspNetCore.Microsoft.AspNetCore.Builder
{
public static class CorsUseExtensions
{
public static void UseCorsServer(this IApplicationBuilder app)
{
app.UseCors("CorsPolicy");
}
}
}

View File

@@ -0,0 +1,109 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Enums;
using Yi.Framework.Core.Exceptions;
namespace Microsoft.AspNetCore.Builder
{
internal class ExceptionModle
{
public int Code { get; set; }
public string? Message { get; set; }
public string? Details { get; set; }
}
public class ErrorHandMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ErrorHandMiddleware> _logger;
//private readonly IErrorHandle _errorHandle;
public ErrorHandMiddleware(RequestDelegate next, ILoggerFactory loggerFactory /*, IErrorHandle errorHandle*/)
{
this._next = next;
this._logger = loggerFactory.CreateLogger<ErrorHandMiddleware>();
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (BusinessException businessEx)
{
context.Response.ContentType = "application/json;charset=utf-8";
context.Response.StatusCode = (int)ResultCodeEnum.Denied;
var result = new ExceptionModle
{
Code = businessEx.Code.GetHashCode(),
Message = businessEx.Message,
Details = businessEx.Details,
};
//业务错误,不记录日志
await context.Response.WriteAsync(JsonConvert.SerializeObject(result, new JsonSerializerSettings()
{
//设置首字母小写
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
}));
}
catch (AuthException ex)
{
context.Response.ContentType = "application/json;charset=utf-8";
//系统错误,记录日志
_logger.LogError(ex, $"授权失败:{ex.Message}");
//await _errorHandle.Invoer(context, ex);
context.Response.StatusCode = (int)ResultCodeEnum.NoPermission;
//系统错误,需要记录
var result = new ExceptionModle
{
Code = ex.Code.GetHashCode(),
Message = ex.Message,
Details = "授权失败",
};
await context.Response.WriteAsync(JsonConvert.SerializeObject(result, new JsonSerializerSettings()
{
//设置首字母小写
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
}));
}
catch (Exception ex)
{
context.Response.ContentType = "application/json;charset=utf-8";
//系统错误,记录日志
_logger.LogError(ex, $"系统错误:{ex.Message}");
//await _errorHandle.Invoer(context, ex);
context.Response.StatusCode = (int)ResultCodeEnum.NotSuccess;
//系统错误,需要记录
var result = new ExceptionModle
{
Code = 500,
Message = ex.Message,
Details = "系统错误",
};
await context.Response.WriteAsync(JsonConvert.SerializeObject(result, new JsonSerializerSettings()
{
//设置首字母小写
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
}));
}
}
}
public static class ErrorHandExtensions
{
public static IApplicationBuilder UseErrorHandlingServer(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ErrorHandMiddleware>();
}
}
}

View File

@@ -0,0 +1,55 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Swashbuckle.AspNetCore.SwaggerUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AspNetCore.Microsoft.AspNetCore.Builder
{
public static class SwaggerUseExtensons
{
public static IApplicationBuilder UseSwaggerServer(this IApplicationBuilder app, params SwaggerModel[] swaggerModels)
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
if (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

@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AspNetCore.Microsoft.AspNetCore.Hosting
{
public static class StratUrlsExtensions
{
public static IWebHostBuilder UseStartUrlsServer(this IWebHostBuilder hostBuilder, IConfiguration configuration, string option = "StartUrl")
{
return hostBuilder.UseUrls(configuration.GetValue<string>(option));
}
}
}

View File

@@ -0,0 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
{
public static class ControllerAddExtension
{
public static IMvcBuilder AddNewtonsoftJsonServer(this IMvcBuilder mvcBuilder)
{
return mvcBuilder.AddNewtonsoftJson(opt =>
{
//忽略循环引用
opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
//不改变字段大小
//opt.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
}
}
}

View File

@@ -0,0 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.Extensions.DependencyInjection
{
public static class CorsAddExtensions
{
public static IServiceCollection AddCorsServer(this IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod()
.SetIsOriginAllowed(_ => true)
.AllowAnyHeader()
.AllowCredentials();
}));
return services;
}
}
}

View File

@@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Const;
using Yi.Framework.Core.CurrentUsers;
using Yi.Framework.Core.CurrentUsers.Accessor;
namespace Microsoft.Extensions.DependencyInjection
{
public static class CurrentUserAddExtensions
{
public static IServiceCollection AddCurrentUserServer(this IServiceCollection services)
{
services.AddSingleton<ICurrentPrincipalAccessor, HttpContextCurrentPrincipalAccessor>();
return services.AddTransient<ICurrentUser, CurrentUser>();
}
}
}

View File

@@ -0,0 +1,61 @@
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Microsoft.Extensions.DependencyInjection
{
public static class SwaggerAddExtensions
{
public static IServiceCollection AddSwaggerServer<Program>(this IServiceCollection services, string title = "Yi意框架-API接口")
{
var apiInfo = new OpenApiInfo
{
Title = title,
Version = "v1",
Contact = new OpenApiContact { Name = "橙子", Email = "454313500@qq.com", Url = new Uri("https://ccnetcore.com") }
};
#region Swagger服务
services.AddSwaggerGen(c =>
{
c.DocInclusionPredicate((docName, description) => true);
c.SwaggerDoc("v1", apiInfo);
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
if (basePath is not null)
{
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
{
c.IncludeXmlComments(item, true);
}
}
c.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" }
};
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
[scheme] = new string[0]
});
});
#endregion
return services;
}
}
}

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Cike.AutoApi" Version="1.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.13" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Microsoft\Extensions\Hosting\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using StartupModules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.CurrentUsers.Accessor;
using Yi.Framework.Core.CurrentUsers;
namespace Yi.Framework.AspNetCore
{
public class YiFrameworkAspNetCoreModule : IStartupModule
{
public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context)
{
}
public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context)
{
services.AddHttpContextAccessor();
services.AddCurrentUserServer();
}
}
}

View File

@@ -0,0 +1,100 @@
using JWT;
using JWT.Algorithms;
using JWT.Builder;
using JWT.Exceptions;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Auth.JwtBearer.Authentication.Options;
using Yi.Framework.Core.Helper;
namespace Yi.Framework.Auth.JwtBearer.Authentication
{
public class JwtTokenManager
{
private JwtTokenOptions _jwtTokenOptions;
public JwtTokenManager(IOptions<JwtTokenOptions> options)
{
_jwtTokenOptions = options.Value;
}
public string CreateToken(Dictionary<string, object>? claimDic)
{
var token = JwtBuilder.Create()
.WithAlgorithm(new RS256Algorithm(RSAFileHelper.GetKey(), RSAFileHelper.GetKey()))
.AddClaim(ClaimName.Issuer, _jwtTokenOptions.Issuer)
.AddClaim(ClaimName.Audience, _jwtTokenOptions.Audience)
.AddClaim(ClaimName.Subject, _jwtTokenOptions.Subject)
.AddClaim(ClaimName.IssuedAt, UnixEpoch.GetSecondsSince(new DateTimeOffset(DateTime.UtcNow)))
.ExpirationTime(DateTime.Now.AddSeconds(_jwtTokenOptions.ExpSecond));
if (claimDic is not null)
{
foreach (var d in claimDic)
{
token.AddClaim(d.Key, d.Value);
};
}
return token.Encode();
}
public IDictionary<string, object>? VerifyToken(string token, TokenVerifyErrorAction tokenVerifyErrorAction)
{
IDictionary<string, object>? claimDic = null;
try
{
claimDic = JwtBuilder.Create()
.WithAlgorithm(new RS256Algorithm(RSAFileHelper.GetPublicKey()))
.WithValidationParameters(ValidationParameters.Default)
.Decode<IDictionary<string, object>>(token);
}
catch (TokenNotYetValidException ex)
{
if (tokenVerifyErrorAction.TokenNotYetValidAction is not null)
{
tokenVerifyErrorAction.TokenNotYetValidAction(ex);
}
//Console.WriteLine("Token错误");
}
catch (TokenExpiredException ex)
{
if (tokenVerifyErrorAction.TokenExpiredAction is not null)
{
tokenVerifyErrorAction.TokenExpiredAction(ex);
}
//Console.WriteLine("Token过期");
}
catch (SignatureVerificationException ex)
{
if (tokenVerifyErrorAction.SignatureVerificationAction is not null)
{
tokenVerifyErrorAction.SignatureVerificationAction(ex);
}
//Console.WriteLine("Token无效");
}
catch (Exception ex)
{
if (tokenVerifyErrorAction.ErrorAction is not null)
{
tokenVerifyErrorAction.ErrorAction(ex);
}
//Console.WriteLine("Token内部错误json序列化");
}
return claimDic;
}
public class TokenVerifyErrorAction
{
public Action<TokenNotYetValidException>? TokenNotYetValidAction { get; set; }
public Action<TokenExpiredException>? TokenExpiredAction { get; set; }
public Action<SignatureVerificationException>? SignatureVerificationAction { get; set; }
public Action<Exception>? ErrorAction { get; set; }
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Auth.JwtBearer.Authentication.Options
{
public class JwtTokenOptions
{
/// <summary>
/// 听众
/// </summary>
public string Audience { get; set; } = string.Empty;
/// <summary>
/// 发行者
/// </summary>
public string Issuer { get; set; } = string.Empty;
/// <summary>
/// 主题
/// </summary>
public string Subject { get; set; } = string.Empty;
/// <summary>
/// 过期时间,单位秒
/// </summary>
public long ExpSecond { get; set; }
}
}

View File

@@ -0,0 +1,132 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using System.Net;
using System.Security.Claims;
using System.Text.Json;
using Yi.Framework.Core.Helper;
namespace Yi.Framework.Auth.JwtBearer.Authentication
{
public class YiJwtAuthenticationHandler : IAuthenticationHandler
{
private JwtTokenManager _jwtTokenManager;
public YiJwtAuthenticationHandler(JwtTokenManager jwtTokenManager)
{
_jwtTokenManager = jwtTokenManager;
}
public const string YiJwtSchemeName = "YiJwtAuth";
private AuthenticationScheme _scheme;
private HttpContext _context;
/// <summary>
/// 初始化数据
/// </summary>
/// <param name="scheme"></param>
/// <param name="context"></param>
/// <returns></returns>
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
_scheme = scheme;
_context = context;
return Task.CompletedTask;
}
/// <summary>
/// 生成认证票据
/// </summary>
/// <param name="name"></param>
/// <param name="role"></param>
/// <returns></returns>
private AuthenticationTicket GetAuthTicket(IDictionary<string, object> dicClaims)
{
List<Claim> claims = new List<Claim>();
foreach (var claim in dicClaims)
{
var p = (JsonElement)claim.Value;
string? resp=null;
switch (p.ValueKind)
{
case JsonValueKind.String:
resp = p.GetString();
break;
case JsonValueKind.Number:
resp = p.GetInt64().ToString();
break;
}
claims.Add(new Claim(claim.Key, resp ?? ""));
}
var claimsIdentity = new ClaimsIdentity(claims.ToArray(), YiJwtSchemeName);
var principal = new ClaimsPrincipal(claimsIdentity);
return new AuthenticationTicket(principal, _scheme.Name);
}
/// <summary>
/// 处理操作
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public Task<AuthenticateResult> AuthenticateAsync()
{
AuthenticateResult result = AuthenticateResult.Fail("未发现授权令牌");
_context.Request.Headers.TryGetValue("Authorization", out StringValues values);
string valStr = values.ToString();
if (!string.IsNullOrWhiteSpace(valStr) && valStr.Length>10)
{
var tokenHeader = valStr.Substring(0, 6);
if (tokenHeader == "Bearer")
{
var token = valStr.Substring(7);
var claimDic = _jwtTokenManager.VerifyToken(token, new JwtTokenManager.TokenVerifyErrorAction()
{
TokenExpiredAction = (ex) => { result = AuthenticateResult.Fail("Token过期"); },
SignatureVerificationAction = (ex) => { result = AuthenticateResult.Fail("Token效验失效"); },
TokenNotYetValidAction = (ex) => { result = AuthenticateResult.Fail("Token完全错误"); },
ErrorAction = (ex) => { result = AuthenticateResult.Fail("Token内部错误"); }
});
if (claimDic is not null)
{
//成功
result = AuthenticateResult.Success(GetAuthTicket(claimDic));
}
}
else
{
result = AuthenticateResult.Fail("授权令牌格式错误");
}
}
return Task.FromResult(result);
}
/// <summary>
/// 未登录时的处理
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public Task ChallengeAsync(AuthenticationProperties? properties)
{
_context.Request.Headers.TryGetValue("Authorization", out StringValues values);
_context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return Task.CompletedTask;
}
/// <summary>
/// 权限不足的处理
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public Task ForbidAsync(AuthenticationProperties? properties)
{
_context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.CurrentUsers;
namespace Yi.Framework.Auth.JwtBearer.Authorization
{
public class DefaultPermissionHandler : IPermissionHandler
{
private ICurrentUser _currentUser { get; set; }
public DefaultPermissionHandler(ICurrentUser currentUser)
{
_currentUser = currentUser;
}
public bool IsPass(string permission)
{
if (_currentUser.Permission is not null)
{
return _currentUser.Permission.Contains(permission);
}
return false;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.CurrentUsers;
namespace Yi.Framework.Auth.JwtBearer.Authorization
{
public interface IPermissionHandler
{
bool IsPass(string permission );
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.CurrentUsers;
using Yi.Framework.Core.Exceptions;
using Yi.Framework.Core.Model;
namespace Yi.Framework.Auth.JwtBearer.Authorization
{
[AttributeUsage(AttributeTargets.Method)]
public class PermissionAttribute : ActionFilterAttribute
{
internal string Code { get; set; }
public PermissionAttribute(string code)
{
this.Code = code;
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Yi.Framework.Auth.JwtBearer.Authorization;
using Yi.Framework.Core.Exceptions;
namespace SF.AspNetCore.Auth.Authorization;
public class PermissionGlobalAttribute : ActionFilterAttribute
{
private readonly IPermissionHandler _permissionHandler;
public PermissionGlobalAttribute(IPermissionHandler permissionHandler)
{
_permissionHandler=permissionHandler;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) return;
PermissionAttribute? perAttribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
.FirstOrDefault(a => a.GetType().Equals(typeof(PermissionAttribute))) as PermissionAttribute;
//空对象直接返回
if (perAttribute is null) return;
var result = _permissionHandler.IsPass(perAttribute.Code);
if (!result)
{
throw new AuthException(message: $"您无权限访问该接口-{context.HttpContext.Request.Path.Value}");
}
}
}

View File

@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JWT" Version="10.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj" />
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,47 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using SF.AspNetCore.Auth.Authorization;
using StartupModules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Auth.JwtBearer.Authentication;
using Yi.Framework.Auth.JwtBearer.Authentication.Options;
using Yi.Framework.Auth.JwtBearer.Authorization;
using Yi.Framework.Core;
using Yi.Framework.Core.Attributes;
using Yi.Framework.Core.Configuration;
namespace Yi.Framework.Auth.JwtBearer
{
[DependsOn(typeof(YiFrameworkCoreModule))]
public class YiFrameworkAuthJwtBearerModule : IStartupModule
{
public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context)
{
}
public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context)
{
services.Configure<JwtTokenOptions>(Appsettings.appConfiguration("JwtTokenOptions"));
services.AddAuthentication(YiJwtAuthenticationHandler.YiJwtSchemeName);
services.AddTransient<JwtTokenManager>();
services.AddSingleton<IPermissionHandler, DefaultPermissionHandler>();
services.AddAuthentication(option =>
{
option.AddScheme<YiJwtAuthenticationHandler>(YiJwtAuthenticationHandler.YiJwtSchemeName, YiJwtAuthenticationHandler.YiJwtSchemeName);
});
services.AddSingleton<PermissionGlobalAttribute>();
services.AddControllers(options => {
options.Filters.Add<PermissionGlobalAttribute>();
});
//services.AddSingleton<PermissionAttribute>();
//services.AddControllers(options => {
// options.Filters.Add<PermissionAttribute>();
//});
}
}
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Extensions\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Mapster" Version="7.3.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,26 @@
using MapsterMapper;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using StartupModules;
using Yi.Framework.Core.Attributes;
namespace Yi.Framework.Core.AutoMapper
{
[DependsOn(
typeof(YiFrameworkCoreModule)
)]
public class YiFrameworkCoreMapsterModule : IStartupModule
{
public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context)
{
}
public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context)
{
//添加全局自动mapper
services.AddSingleton<IMapper, Mapper>();
}
}
}

View File

@@ -0,0 +1,27 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Autofac.Extensions
{
public static class AutoFacExtensions
{
public static IHostBuilder UseAutoFacServerProviderFactory(this IHostBuilder hostBuilder)
{
hostBuilder.UseServiceProviderFactory(new AutofacServiceProviderFactory());
return hostBuilder;
}
public static IHostBuilder ConfigureAutoFacContainer(this IHostBuilder hostBuilder, Action<ContainerBuilder> configureDelegate)
{
hostBuilder.UseAutoFacServerProviderFactory();
return hostBuilder.ConfigureContainer(configureDelegate);
}
}
}

View File

@@ -0,0 +1,35 @@
using Autofac;
using Autofac.Core.Registration;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Autofac.Modules;
namespace Yi.Framework.Core.Autofac.Extensions
{
public static class AutoFacModuleExtensions
{
public static void RegisterYiModule<TModule>(this ContainerBuilder builder, params Assembly[] assemblies) where TModule : YiAutoFacModule, new()
{
new TModule().Load(builder, assemblies);
}
public static void RegisterYiModule(this ContainerBuilder builder, AutoFacModuleEnum autoFacModuleEnum, params Assembly[] assemblies)
{
Logger? _logger = LogManager.Setup().LoadConfigurationFromAssemblyResource(typeof(AutoFacModuleExtensions).Assembly).GetCurrentClassLogger();
switch (autoFacModuleEnum)
{
case AutoFacModuleEnum.PropertiesAutowiredModule:
_logger.Info($"意框架添加AutoFac模块{nameof(PropertiesAutowiredModule)}-属性注入模块");
new PropertiesAutowiredModule().Load(builder, assemblies);
break;
}
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Autofac.Modules
{
public enum AutoFacModuleEnum
{
PropertiesAutowiredModule
}
}

View File

@@ -0,0 +1,32 @@
using Autofac;
using Autofac.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Attributes;
namespace Yi.Framework.Core.Autofac.Modules
{
internal class PropertiesAutowiredModule : YiAutoFacModule
{
internal override void Load(ContainerBuilder containerBuilder, params Assembly[] assemblies)
{
containerBuilder.RegisterAssemblyTypes(assemblies)
.PropertiesAutowired(new AutowiredPropertySelector());
}
}
public class AutowiredPropertySelector : IPropertySelector
{
public bool InjectProperty(PropertyInfo propertyInfo, object instance)
{
return propertyInfo.CustomAttributes.Any(it => it.AttributeType == typeof(AutowiredAttribute));
}
}
}

View File

@@ -0,0 +1,15 @@
using Autofac;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Autofac.Modules
{
public abstract class YiAutoFacModule
{
internal abstract void Load(ContainerBuilder containerBuilder,params Assembly[] assemblies);
}
}

View File

@@ -0,0 +1,12 @@
{
"profiles": {
"Yi.Framework.Autofac": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:53043;http://localhost:53044"
}
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.AspNetCore\Yi.Framework.AspNetCore.csproj" />
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,27 @@
using Autofac.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using StartupModules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Autofac
{
public class YiFrameworkCoreAutofacModule : IStartupModule
{
public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context)
{
}
public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context)
{
//将控制器交由autofac注册
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Sqlsugar.Const
{
public class SqlsugarConst
{
public const string = "开启读写分离后,读库连接不能为空";
public const string DbType配置为空 = "DbType配置为空必须选择一个数据库类型";
}
}

View File

@@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Sqlsugar.Options;
namespace Yi.Framework.Core.Sqlsugar.Extensions
{
public static class SqlsugarCodeFirstExtensions
{
public static void UseSqlsugarCodeFirstServer(this IApplicationBuilder app)
{
var db = app.ApplicationServices.GetRequiredService<ISqlSugarClient>();
var options = app.ApplicationServices.GetRequiredService<IOptions<DbConnOptions>>();
if (options.Value.EnabledCodeFirst == false) return;
db.DbMaintenance.CreateDatabase();
var assemblys = new List<Assembly>();
//全盘加载
if (options.Value.EntityAssembly is null)
{
assemblys.AddRange(AppDomain.CurrentDomain.GetAssemblies().ToList());
}
//按需加载
else
{
options.Value.EntityAssembly.ForEach(a =>
{
assemblys.Add(Assembly.Load(a));
});
}
foreach (var assembly in assemblys)
{
TableInvoer(db, assembly.GetTypes().ToList());
}
}
private static void TableInvoer(ISqlSugarClient _Db, List<Type> typeList)
{
foreach (var t in typeList)
{
//扫描如果存在SugarTable特性 并且 不是分表模型直接codefirst
if (t.GetCustomAttributes(false).Any(a => a.GetType().Equals(typeof(SugarTable))
&& !t.GetCustomAttributes(false).Any(a => a.GetType().Equals(typeof(SplitTableAttribute)))))
{
_Db.CodeFirst.SetStringDefaultLength(200).InitTables(t);//这样一个表就能成功创建了
}
}
}
}
}

View File

@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Sqlsugar.Extensions
{
public static class SqlsugarDataFilterExtensions
{
public static IApplicationBuilder UseSqlsugarDataFiterServer(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SqlsugarDataFilterMiddleware>();
}
}
public class SqlsugarDataFilterMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<SqlsugarDataFilterMiddleware> _logger;
public SqlsugarDataFilterMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
this._next = next;
this._logger = loggerFactory.CreateLogger<SqlsugarDataFilterMiddleware>();
}
public async Task InvokeAsync(HttpContext context)
{
await _next(context);
}
}
}

View File

@@ -0,0 +1,159 @@
using Autofac.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Configuration;
using Yi.Framework.Core.Model;
using Yi.Framework.Core.Sqlsugar.Const;
using Yi.Framework.Core.Sqlsugar.Options;
using Yi.Framework.Data.Auditing;
using Yi.Framework.Data.Entities;
using DbType = SqlSugar.DbType;
namespace Yi.Framework.Core.Sqlsugar.Extensions
{
/// <summary>
/// 这一块,需要做成上下文对象,会进行重构
/// </summary>
public static class SqlsugarExtensions
{
//使用上下文对象
public static void AddDbSqlsugarContextServer(this IServiceCollection services)
{
services.AddSingleton<ISqlSugarClient>(x => x.GetRequiredService<SqlSugarDbContext>().SqlSugarClient);
services.AddSingleton<SqlSugarDbContext>();
}
//直接使用sqlsugar
public static void AddSqlsugarServer(this IServiceCollection services, Action<SqlSugarClient>? action = null)
{
var dbConnOptions = Appsettings.app<DbConnOptions>("DbConnOptions");
if (dbConnOptions.DbType is null)
{
throw new ArgumentException(SqlsugarConst.DbType配置为空);
}
var slavaConFig = new List<SlaveConnectionConfig>();
if (dbConnOptions.EnabledReadWrite)
{
if (dbConnOptions.ReadUrl is null)
{
throw new ArgumentException(SqlsugarConst.);
}
var readCon = dbConnOptions.ReadUrl;
readCon.ForEach(s =>
{
//如果是动态saas分库这里的连接串都不能写死需要动态添加这里只配置共享库的连接
slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s });
});
}
SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig()
{
//准备添加分表分库
DbType = dbConnOptions.DbType ?? DbType.Sqlite,
ConnectionString = dbConnOptions.Url,
IsAutoCloseConnection = true,
MoreSettings = new ConnMoreSettings()
{
DisableNvarchar = true
},
SlaveConnectionConfigs = slavaConFig,
//设置codefirst非空值判断
ConfigureExternalServices = new ConfigureExternalServices
{
EntityService = (c, p) =>
{
//高版C#写法 支持string?和string
if (new NullabilityInfoContext()
.Create(c).WriteState is NullabilityState.Nullable)
{
p.IsNullable = true;
}
}
}
},
db =>
{
//扩展
if (action is not null)
{
action(db);
}
db.Aop.DataExecuting = (oldValue, entityInfo) =>
{
switch (entityInfo.OperationType)
{
case DataFilterType.UpdateByObject:
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime)))
{
entityInfo.SetValue(DateTime.Now);
}
//if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
//{
// if (_currentUser != null)
// {
// entityInfo.SetValue(_currentUser.Id);
// }
//}
break;
case DataFilterType.InsertByObject:
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
{
entityInfo.SetValue(DateTime.Now);
}
//if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
//{
// if (_currentUser != null)
// {
// entityInfo.SetValue(_currentUser.Id);
// }
//}
//插入时需要租户id,先预留
if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
{
//if (this.CurrentTenant is not null)
//{
// entityInfo.SetValue(this.CurrentTenant.Id);
//}
}
break;
}
};
db.Aop.OnLogExecuting = (s, p) =>
{
var _logger = ServiceLocatorModel.Instance?.GetRequiredService<ILogger<SqlSugarClient>>();
StringBuilder sb = new StringBuilder();
sb.Append("执行SQL:" + s.ToString());
foreach (var i in p)
{
sb.Append($"\r\n参数:{i.ParameterName},参数值:{i.Value}");
}
sb.Append($"\r\n 完整SQL{UtilMethods.GetSqlString(DbType.MySql, s, p)}");
_logger?.LogDebug(sb.ToString());
};
});
services.AddSingleton<ISqlSugarClient>(sqlSugar);//这边是SqlSugarScope用AddSingleton
}
}
}

View File

@@ -0,0 +1,50 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Data.Filters;
namespace Yi.Framework.Core.Sqlsugar.Filters
{
public class SqlsugarDataFilter : IDataFilter
{
private ISqlSugarClient _Db { get; set; }
public SqlsugarDataFilter(ISqlSugarClient sqlSugarClient)
{
_Db = sqlSugarClient;
}
public void AddFilter<TFilter>(Expression<Func<TFilter, bool>> expression) where TFilter : class
{
_Db.QueryFilter.AddTableFilter<TFilter>(expression);
}
public IDisposable Disable<TFilter>() where TFilter : class
{
_Db.QueryFilter.ClearAndBackup<TFilter>();
return this;
}
public IDisposable Enable<TFilter>() where TFilter : class
{
throw new NotImplementedException("暂时没有单独还原过滤器的方式");
}
public bool IsEnabled<TFilter>() where TFilter : class
{
throw new NotImplementedException("暂时没有判断过滤器的方式");
}
public void RemoveFilter<TFilter>() where TFilter : class
{
_Db.QueryFilter.Clear<TFilter>();
}
public void Dispose()
{
_Db.QueryFilter.Restore();
}
}
}

View File

@@ -0,0 +1,47 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Sqlsugar.Options
{
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>
/// 开启读写分离
/// </summary>
public bool EnabledReadWrite { get; set; } = false;
/// <summary>
/// 开启codefirst
/// </summary>
public bool EnabledCodeFirst { get; set; }=false;
/// <summary>
/// 实体程序集
/// </summary>
public List<string>? EntityAssembly { get; set; }
/// <summary>
/// 读写分离
/// </summary>
public List<string>? ReadUrl { get; set; }
}
}

View File

@@ -0,0 +1,155 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Attributes;
using Yi.Framework.Core.Enums;
using Yi.Framework.Core.Helper;
using Yi.Framework.Data.Entities;
using Yi.Framework.Ddd.Dtos;
using Yi.Framework.Ddd.Entities;
using Yi.Framework.Ddd.Repositories;
namespace Yi.Framework.Core.Sqlsugar.Repositories
{
[AppService(typeof(IRepository<>))]
public class SqlsugarRepository<T> : SimpleClient<T>, IRepository<T> where T : class, new()
{
public SqlsugarRepository(ISqlSugarClient context) : base(context)
{
}
/// <summary>
/// 注释一下严格意义这里应该protected但是我认为 简易程度 与 耦合程度 中是需要进行衡量的
/// </summary>
public ISugarQueryable<T> _DbQueryable => base.AsQueryable();
protected ISqlSugarClient _Db { get { return Context; } set { } }
public async Task<List<T>> GetPageListAsync(Expression<Func<T, bool>> whereExpression, IPagedAndSortedResultRequestDto page)
{
return await base.GetPageListAsync(whereExpression, new PageModel { PageIndex = page.PageNum, PageSize = page.PageSize });
}
public async Task<List<T>> GetPageListAsync(Expression<Func<T, bool>> whereExpression, IPagedAndSortedResultRequestDto page, Expression<Func<T, object>>? orderByExpression = null, OrderByEnum orderByType = OrderByEnum.Asc)
{
return await base.GetPageListAsync(whereExpression, new PageModel { PageIndex = page.PageNum, PageSize = page.PageSize }, orderByExpression, orderByType.EnumToEnum<OrderByType>());
}
public async Task<List<T>> GetPageListAsync(Expression<Func<T, bool>> whereExpression, IPagedAndSortedResultRequestDto page, string? orderBy, OrderByEnum orderByType = OrderByEnum.Asc)
{
return await _DbQueryable.Where(whereExpression).OrderByIF(orderBy is not null, orderBy + " " + orderByType.ToString().ToLower()).ToPageListAsync(page.PageNum, page.PageSize);
}
public async Task<List<T>> GetPageListAsync(Expression<Func<T, bool>> whereExpression, int pageNum,int pageSize)
{
return await base.GetPageListAsync(whereExpression, new PageModel { PageIndex = pageNum, PageSize = pageSize });
}
public async Task<List<T>> GetPageListAsync(Expression<Func<T, bool>> whereExpression, int pageNum, int pageSize, Expression<Func<T, object>>? orderByExpression = null, OrderByEnum orderByType = OrderByEnum.Asc)
{
return await base.GetPageListAsync(whereExpression, new PageModel { PageIndex = pageNum, PageSize = pageSize }, orderByExpression, orderByType.EnumToEnum<OrderByType>());
}
public async Task<List<T>> GetPageListAsync(Expression<Func<T, bool>> whereExpression, int pageNum, int pageSize, string? orderBy, OrderByEnum orderByType = OrderByEnum.Asc)
{
return await _DbQueryable.Where(whereExpression).OrderByIF(orderBy is not null, orderBy + " " + orderByType.ToString().ToLower()).ToPageListAsync(pageNum, pageSize);
}
public async Task<bool> UpdateIgnoreNullAsync(T updateObj)
{
return await _Db.Updateable(updateObj).IgnoreColumns(true).ExecuteCommandAsync() > 0;
}
public override async Task<bool> DeleteAsync(T deleteObj)
{
//逻辑删除
if (deleteObj is ISoftDelete)
{
//反射赋值
ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, deleteObj);
return await UpdateAsync(deleteObj);
}
else
{
return await base.DeleteAsync(deleteObj);
}
}
public override async Task<bool> DeleteAsync(List<T> deleteObjs)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(T)))
{
//反射赋值
deleteObjs.ForEach(e => ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e));
return await UpdateRangeAsync(deleteObjs);
}
else
{
return await base.DeleteAsync(deleteObjs);
}
}
public override async Task<bool> DeleteAsync(Expression<Func<T, bool>> whereExpression)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(T)))
{
var entities = await GetListAsync(whereExpression);
//反射赋值
entities.ForEach(e => ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e));
return await UpdateRangeAsync(entities);
}
else
{
return await base.DeleteAsync(whereExpression);
}
}
public override async Task<bool> DeleteByIdAsync(dynamic id)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(T)))
{
var entity = await GetByIdAsync(id);
//反射赋值
ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, entity);
return await UpdateAsync(entity);
}
else
{
return await _Db.Deleteable<T>().In(id).ExecuteCommandAsync() > 0;
}
}
public override async Task<bool> DeleteByIdsAsync(dynamic[] ids)
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(T)))
{
var entities = await _DbQueryable.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 base.DeleteByIdsAsync(ids);
}
}
}
}

View File

@@ -0,0 +1,152 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.CurrentUsers;
using Yi.Framework.Core.Model;
using Yi.Framework.Core.Sqlsugar.Const;
using Yi.Framework.Core.Sqlsugar.Options;
using Yi.Framework.Data.Auditing;
using Yi.Framework.Data.Entities;
namespace Yi.Framework.Core.Sqlsugar
{
public class SqlSugarDbContext
{
/// <summary>
/// SqlSugar 客户端
/// </summary>
public ISqlSugarClient SqlSugarClient { get; set; }
protected ICurrentUser _currentUser;
protected ILogger<SqlSugarDbContext> _logger;
protected IOptions<DbConnOptions> _options;
public SqlSugarDbContext(IOptions<DbConnOptions> options, ICurrentUser currentUser, ILogger<SqlSugarDbContext> logger)
{
_currentUser = currentUser;
_logger = logger;
_options = options;
var dbConnOptions = options.Value;
#region options
if (dbConnOptions.DbType is null)
{
throw new ArgumentException(SqlsugarConst.DbType配置为空);
}
var slavaConFig = new List<SlaveConnectionConfig>();
if (dbConnOptions.EnabledReadWrite)
{
if (dbConnOptions.ReadUrl is null)
{
throw new ArgumentException(SqlsugarConst.);
}
var readCon = dbConnOptions.ReadUrl;
readCon.ForEach(s =>
{
//如果是动态saas分库这里的连接串都不能写死需要动态添加这里只配置共享库的连接
slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s });
});
}
#endregion
SqlSugarClient = new SqlSugarScope(new ConnectionConfig()
{
//准备添加分表分库
DbType = dbConnOptions.DbType ?? DbType.Sqlite,
ConnectionString = dbConnOptions.Url,
IsAutoCloseConnection = true,
MoreSettings = new ConnMoreSettings()
{
DisableNvarchar = true
},
SlaveConnectionConfigs = slavaConFig,
//设置codefirst非空值判断
ConfigureExternalServices = new ConfigureExternalServices
{
EntityService = (c, p) =>
{
//高版C#写法 支持string?和string
if (new NullabilityInfoContext()
.Create(c).WriteState is NullabilityState.Nullable)
{
p.IsNullable = true;
}
}
}
},
db =>
{
db.Aop.DataExecuting = (oldValue, entityInfo) =>
{
switch (entityInfo.OperationType)
{
case DataFilterType.UpdateByObject:
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime)))
{
entityInfo.SetValue(DateTime.Now);
}
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
{
if (_currentUser != null)
{
entityInfo.SetValue(_currentUser.Id);
}
}
break;
case DataFilterType.InsertByObject:
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
{
entityInfo.SetValue(DateTime.Now);
}
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
{
if (_currentUser != null)
{
entityInfo.SetValue(_currentUser.Id);
}
}
//插入时需要租户id,先预留
if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
{
//if (this.CurrentTenant is not null)
//{
// entityInfo.SetValue(this.CurrentTenant.Id);
//}
}
break;
}
};
db.Aop.OnLogExecuting = (s, p) =>
{
StringBuilder sb = new StringBuilder();
//sb.Append("执行SQL:" + s.ToString());
//foreach (var i in p)
//{
// sb.Append($"\r\n参数:{i.ParameterName},参数值:{i.Value}");
//}
sb.Append($"\r\n 完整SQL{UtilMethods.GetSqlString(DbType.MySql, s, p)}");
logger?.LogDebug(sb.ToString());
};
//扩展
this.OnSqlSugarClientConfig(db);
});
}
//上下文对象扩展
protected virtual void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
{
}
}
}

View File

@@ -0,0 +1,59 @@
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Model;
using Yi.Framework.Ddd.Repositories;
using Yi.Framework.Uow;
namespace Yi.Framework.Core.Sqlsugar.Uow
{
public class SqlsugarUnitOfWork : IUnitOfWork
{
public ISqlSugarClient Db { get; set; }
public ITenant Tenant { get; set; }
public bool IsTran { get; set; }
public bool IsCommit { get; set; }
public bool IsClose { get; set; }
public void Dispose()
{
if (this.IsTran && IsCommit == false)
{
this.Tenant.RollbackTran();
}
if (this.Db.Ado.Transaction == null && IsClose == false)
{
this.Db.Close();
}
}
public bool Commit()
{
if (this.IsTran && this.IsCommit == false)
{
this.Tenant.CommitTran();
IsCommit = true;
}
if (this.Db.Ado.Transaction == null && this.IsClose == false)
{
this.Db.Close();
IsClose = true;
}
return IsCommit;
}
public IRepository<T> GetRepository<T>()
{
if (ServiceLocatorModel.Instance is null)
throw new ArgumentNullException("ServiceLocatorModel.Instance");
//又是你这个骚东西
return ServiceLocatorModel.Instance.GetRequiredService<IRepository<T>>();
}
}
}

View File

@@ -0,0 +1,37 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Uow;
namespace Yi.Framework.Core.Sqlsugar.Uow
{
/// <summary>
/// 此部分为sqlsugr的魔改版本
/// </summary>
internal class SqlsugarUnitOfWorkManager : IUnitOfWorkManager
{
public SqlsugarUnitOfWorkManager(ISqlSugarClient db)
{
this.Db = db;
}
public ISqlSugarClient Db { get; set; }
public IUnitOfWork CreateContext(bool isTran = true)
{
SqlsugarUnitOfWork uow = new SqlsugarUnitOfWork();
return CreateContext(isTran, uow);
}
private IUnitOfWork CreateContext(bool isTran, SqlsugarUnitOfWork sugarUnitOf)
{
sugarUnitOf.Db = Db;
sugarUnitOf.Tenant = Db.AsTenant();
sugarUnitOf.IsTran = isTran;
Db.Open();
if (isTran)
Db.AsTenant().BeginTran();
return sugarUnitOf;
}
}
}

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SqlSugarCore" Version="5.1.3.49" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Yi.Framework.Core\Yi.Framework.Core.csproj" />
<ProjectReference Include="..\Yi.Framework.Data\Yi.Framework.Data.csproj" />
<ProjectReference Include="..\Yi.Framework.Ddd\Yi.Framework.Ddd.csproj" />
<ProjectReference Include="..\Yi.Framework.Uow\Yi.Framework.Uow.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="CodeFirst\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using StartupModules;
using Yi.Framework.Core.Configuration;
using Yi.Framework.Core.Sqlsugar.Extensions;
using Yi.Framework.Core.Sqlsugar.Filters;
using Yi.Framework.Core.Sqlsugar.Options;
using Yi.Framework.Core.Sqlsugar.Repositories;
using Yi.Framework.Core.Sqlsugar.Uow;
using Yi.Framework.Data.Filters;
using Yi.Framework.Ddd;
using Yi.Framework.Ddd.Repositories;
using Yi.Framework.Uow;
namespace Yi.Framework.Core.Sqlsugar
{
public class YiFrameworkCoreSqlsugarModule : IStartupModule
{
public void Configure(IApplicationBuilder app, ConfigureMiddlewareContext context)
{
app.UseSqlsugarCodeFirstServer();
}
public void ConfigureServices(IServiceCollection services, ConfigureServicesContext context)
{
services.AddTransient(typeof(IRepository<>), typeof(SqlsugarRepository<>));
//services.Replace(new ServiceDescriptor(typeof(IUnitOfWorkManager), typeof(SqlsugarUnitOfWorkManager), ServiceLifetime.Singleton));
services.Replace(new ServiceDescriptor(typeof(IDataFilter), typeof(SqlsugarDataFilter), ServiceLifetime.Scoped));
services.Configure<DbConnOptions>(Appsettings.appConfiguration("DbConnOptions"));
//使用db上下文
services.AddDbSqlsugarContextServer();
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Attributes
{
/// 1、[AppService]:自动去找接口,如果存在就是接口,如果不存在就是本身
/// 2、[AppService(ServiceType = typeof(注册抽象或者接口或者本身))]手动去注册放type即可
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public class AppServiceAttribute : Attribute
{
public AppServiceAttribute() { }
public AppServiceAttribute(Type? serviceType)
{
ServiceType=serviceType;
}
public AppServiceAttribute(Type? serviceType, LifeTime serviceLifetime)
{
ServiceType = serviceType;
ServiceLifetime= serviceLifetime;
}
/// <summary>
/// 服务声明周期
/// 不给默认值的话注册的是作用域
/// </summary>
public LifeTime ServiceLifetime { get; set; } = LifeTime.Transient;
/// <summary>
/// 指定服务类型
/// </summary>
public Type? ServiceType { get; set; }
}
public enum LifeTime
{
Transient, Scoped, Singleton
}
}

View File

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

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Attributes
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class DependsOnAttribute : Attribute
{
public Type[] DependedTypes { get; }
public DependsOnAttribute(params Type[] dependedTypes)
{
DependedTypes = dependedTypes ?? new Type[0];
}
public virtual Type[] GetDependedTypes()
{
return DependedTypes;
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Enums;
namespace Yi.Framework.Core.Attributes
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public class QueryParameterAttribute:Attribute
{
public QueryParameterAttribute()
{
}
public QueryParameterAttribute(QueryOperatorEnum queryOperatorEnum)
{
QueryOperator = queryOperatorEnum;
}
public QueryOperatorEnum QueryOperator { get; set; }
/// <summary>
/// 验证值为0时是否作为查询条件
/// true-作为查询条件 false-不作为查询条件
/// </summary>
public bool VerifyIsZero { get; set; } = false;
/// <summary>
///
/// </summary>
public string ColumnName { get; set; }
public ColumnTypeEnum ColumnType { get; set; }
}
public enum ColumnTypeEnum
{
datetime,
@bool
}
}

View File

@@ -0,0 +1,91 @@
using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Configuration
{
public class Appsettings
{
static IConfiguration? Configuration { get; set; }
static string? contentPath { get; set; }
public Appsettings(string contentPath)
{
string Path = "appsettings.json";
//如果你把配置文件 是 根据环境变量来分开了,可以这样写
//Path = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json";
Configuration = new ConfigurationBuilder()
.SetBasePath(contentPath)
.Add(new JsonConfigurationSource { Path = Path, Optional = false, ReloadOnChange = true })//这样的话可以直接读目录里的json文件而不是 bin 文件夹下的,所以不用修改复制属性
.Build();
}
public Appsettings(IConfiguration configuration)
{
Configuration = configuration;
}
/// <summary>
/// 封装要操作的字符
/// </summary>
/// <param name="sections">节点配置</param>
/// <returns></returns>
public static string? app(params string[] sections)
{
try
{
if (sections.Any())
{
return Configuration?[string.Join(":", sections)];
}
}
catch (Exception) { }
return "";
}
public static bool appBool(params string[] sections)
{
return Bool(app(sections));
}
public static bool Bool(object? thisValue)
{
bool reval = false;
if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval))
{
return reval;
}
return reval;
}
/// <summary>
/// 递归获取配置信息数组
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sections"></param>
/// <returns></returns>
public static T app<T>(params string[] sections)
{
T app = Activator.CreateInstance<T>();
// 引用 Microsoft.Extensions.Configuration.Binder 包
Configuration.Bind(string.Join(":", sections), app);
return app;
}
public static IConfiguration? appConfiguration(params string[] sections)
{
return Configuration?.GetSection(string.Join(":", sections));
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Const
{
/// <summary>
/// 定义公共文件常量
/// </summary>
public class PathConst
{
public const string wwwroot = "wwwroot";
public const string DataTemplate = "_DataTemplate";
public const string DataExport = "_DataExport";
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Const
{
public class TokenTypeConst
{
public const string Id = nameof(Id);
public const string UserName= nameof(UserName);
public const string TenantId = nameof(TenantId);
public const string Email = nameof(Email);
public const string PhoneNumber = nameof(PhoneNumber);
public const string Roles = nameof(Roles);
public const string Permission = nameof(Permission);
}
}

View File

@@ -0,0 +1,32 @@
using System.Security.Claims;
using Yi.Framework.Core.Utils;
namespace Yi.Framework.Core.CurrentUsers.Accessor
{
public abstract class CurrentPrincipalAccessorBase : ICurrentPrincipalAccessor
{
public ClaimsPrincipal Principal => _currentPrincipal.Value ?? GetClaimsPrincipal();
private readonly AsyncLocal<ClaimsPrincipal> _currentPrincipal = new AsyncLocal<ClaimsPrincipal>();
protected abstract ClaimsPrincipal GetClaimsPrincipal();
public virtual IDisposable Change(ClaimsPrincipal principal)
{
return SetCurrent(principal);
}
private IDisposable SetCurrent(ClaimsPrincipal principal)
{
var parent = Principal;
_currentPrincipal.Value = principal;
return new DisposeAction<ValueTuple<AsyncLocal<ClaimsPrincipal>, ClaimsPrincipal>>(static (state) =>
{
var (currentPrincipal, parent) = state;
currentPrincipal.Value = parent;
}, (_currentPrincipal, parent));
}
}
}

View File

@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.CurrentUsers.Accessor;
namespace Yi.Framework.Core.CurrentUsers.Accessor
{
public class HttpContextCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor
{
private readonly IHttpContextAccessor _httpContextAccessor;
public HttpContextCurrentPrincipalAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override ClaimsPrincipal GetClaimsPrincipal()
{
return _httpContextAccessor.HttpContext?.User ?? base.GetClaimsPrincipal();
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Security.Claims;
namespace Yi.Framework.Core.CurrentUsers.Accessor
{
public interface ICurrentPrincipalAccessor
{
ClaimsPrincipal Principal { get; }
IDisposable Change(ClaimsPrincipal principal);
}
}

View File

@@ -0,0 +1,15 @@
using System.Security.Claims;
using Yi.Framework.Core.CurrentUsers.Accessor;
namespace SF.CurrentUser.CS.Accessor
{
public class StaticPrincipalAccessor : CurrentPrincipalAccessorBase
{
public static ClaimsPrincipal ClaimsPrincipal { get; set; }
protected override ClaimsPrincipal GetClaimsPrincipal()
{
return ClaimsPrincipal;
}
}
}

View File

@@ -0,0 +1,13 @@
using System.Security.Claims;
namespace Yi.Framework.Core.CurrentUsers.Accessor
{
public class ThreadCurrentPrincipalAccessor : CurrentPrincipalAccessorBase
{
protected override ClaimsPrincipal GetClaimsPrincipal()
{
return Thread.CurrentPrincipal as ClaimsPrincipal;
}
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Const;
using Yi.Framework.Core.CurrentUsers.Accessor;
namespace Yi.Framework.Core.CurrentUsers
{
public class CurrentUser : ICurrentUser
{
private readonly ICurrentPrincipalAccessor _principalAccessor;
public CurrentUser(ICurrentPrincipalAccessor principalAccessor)
{
_principalAccessor = principalAccessor;
}
public bool IsAuthenticated => Id != 0;
public long Id => FindUserId();
public string UserName => this.FindClaimValue(TokenTypeConst.UserName);
/// <summary>
/// 暂时为默认值
/// </summary>
public Guid TenantId { get; set; } = Guid.Empty;
public string Email => FindClaimValue(TokenTypeConst.Email);
public bool EmailVerified=> false;
public string PhoneNumber => FindClaimValue(TokenTypeConst.PhoneNumber);
public bool PhoneNumberVerified => false;
public string[]? Roles => this.FindClaims(TokenTypeConst.Roles).Select(c => c.Value).Distinct().ToArray();
public string[]? Permission => this.FindClaims(TokenTypeConst.Permission).Select(c => c.Value).Distinct().ToArray();
public virtual Claim FindClaim(string claimType)
{
return _principalAccessor.Principal?.Claims.FirstOrDefault(c => c.Type == claimType);
}
public virtual Claim[] FindClaims(string claimType)
{
return _principalAccessor.Principal?.Claims.Where(c => c.Type == claimType).ToArray() ?? new Claim[0];
}
public virtual Claim[] GetAllClaims()
{
return _principalAccessor.Principal?.Claims.ToArray() ?? new Claim[0];
}
public string FindClaimValue(string claimType)
{
return FindClaim(claimType)?.Value;
}
public long FindUserId()
{
var userIdOrNull = _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == TokenTypeConst.Id);
if (userIdOrNull == null || string.IsNullOrWhiteSpace(userIdOrNull.Value))
{
return 0;
}
if (long.TryParse(userIdOrNull.Value, out long userId))
{
return userId;
}
return 0;
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.CurrentUsers
{
public interface ICurrentUser
{
public bool IsAuthenticated { get; }
public long Id { get; }
public string UserName { get; }
public Guid TenantId { get; }
public string Email { get; }
public bool EmailVerified { get; }
public string PhoneNumber { get; }
public bool PhoneNumberVerified { get; }
public string[]? Roles { get; }
public string[]? Permission { get; }
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.DependencyInjection
{
internal interface IScopedDependency
{
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.DependencyInjection
{
public interface ISingletonDependency
{
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.DependencyInjection
{
public interface ITransientDependency
{
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Enums
{
/// <summary>
/// 定义公共文件路径
/// </summary>
public enum FileTypeEnum
{
File,
Image,
Thumbnail,
Excel,
Temp
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Enums
{
public enum OrderByEnum
{
Asc,
Desc
}
}

View File

@@ -0,0 +1,72 @@
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

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Enums
{
public enum ResultCodeEnum
{
/// <summary>
/// 操作成功。
/// </summary>
Success = 200,
/// <summary>
/// 操作不成功
/// </summary>
NotSuccess = 500,
/// <summary>
/// 无权限
/// </summary>
NoPermission = 401,
/// <summary>
/// 被拒绝
/// </summary>
Denied = 403
}
}

View File

@@ -0,0 +1,53 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Enums;
namespace Yi.Framework.Core.Exceptions
{
public class AuthException : Exception,
IHasErrorCode,
IHasErrorDetails,
IHasLogLevel
{
public int Code { get; set; }
public string? Details { get; set; }
public LogLevel LogLevel { get; set; }
public AuthException(
string? message = null,
ResultCodeEnum code = ResultCodeEnum.NoPermission,
string? details = null,
Exception? innerException = null,
LogLevel logLevel = LogLevel.Warning)
: base(message, innerException)
{
Code =(int) code;
Details = details;
LogLevel = logLevel;
}
/// <summary>
/// 序列化参数的构造函数
/// </summary>
public AuthException(SerializationInfo serializationInfo, StreamingContext context)
: base(serializationInfo, context)
{
}
public AuthException WithData(string name, object value)
{
Data[name] = value;
return this;
}
}
}

View File

@@ -0,0 +1,52 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Enums;
namespace Yi.Framework.Core.Exceptions
{
public class BusinessException : Exception,
IHasErrorCode,
IHasErrorDetails,
IHasLogLevel
{
public int Code { get; set; }
public string? Details { get; set; }
public LogLevel LogLevel { get; set; }
public BusinessException(
int code = (int)ResultCodeEnum.Denied,
string? message = null,
string? details = null,
Exception? innerException = null,
LogLevel logLevel = LogLevel.Warning)
: base(message, innerException)
{
Code = code;
Details = details;
LogLevel = logLevel;
}
/// <summary>
/// 序列化参数的构造函数
/// </summary>
public BusinessException(SerializationInfo serializationInfo, StreamingContext context)
: base(serializationInfo, context)
{
}
public BusinessException WithData(string name, object value)
{
Data[name] = value;
return this;
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Runtime.ExceptionServices;
using Microsoft.Extensions.Logging;
using Yi.Framework.Core.Enums;
namespace Yi.Framework.Core.Exceptions;
/// <summary>
/// <see cref="Exception"/><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>չ<EFBFBD><D5B9><EFBFBD><EFBFBD>
/// </summary>
public static class ExceptionExtensions
{
/// <summary>
/// ʹ<><CAB9> <see cref="ExceptionDispatchInfo.Capture"/> <20>ٴ<EFBFBD><D9B4>׳<EFBFBD><D7B3>
/// </summary>
/// <param name="exception">Exception to be re-thrown</param>
public static void ReThrow(this Exception exception)
{
ExceptionDispatchInfo.Capture(exception).Throw();
}
/// <summary>
/// <20><>ȡ<EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD>־<EFBFBD>ȼ<EFBFBD>
/// </summary>
/// <param name="exception"></param>
/// <param name="defaultLevel"></param>
/// <returns></returns>
public static LogLevel GetLogLevel(this Exception exception, LogLevel defaultLevel = LogLevel.Error)
{
return (exception as IHasLogLevel)?.LogLevel ?? defaultLevel;
}
/// <summary>
/// <20><>ȡ<EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
/// <param name="exception"></param>
/// <param name="defaultLevel"></param>
/// <returns></returns>
public static int GetLogErrorCode(this Exception exception, ResultCodeEnum defaultCode = ResultCodeEnum.NotSuccess)
{
return (exception as IHasErrorCode)?.Code ?? (int)defaultCode;
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Enums;
namespace Yi.Framework.Core.Exceptions
{
internal interface IHasErrorCode
{
int Code { get; }
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Exceptions
{
public interface IHasErrorDetails
{
string? Details { get; }
}
}

View File

@@ -0,0 +1,14 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Exceptions
{
public interface IHasLogLevel
{
LogLevel LogLevel { get; set; }
}
}

View File

@@ -0,0 +1,39 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Enums;
namespace Yi.Framework.Core.Exceptions
{
public class UserFriendlyException : BusinessException
{
public UserFriendlyException(
string message,
int code = (int)ResultCodeEnum.Denied,
string? details = null,
Exception? innerException = null,
LogLevel logLevel = LogLevel.Warning)
: base(
code,
message,
details,
innerException,
logLevel)
{
Details = details;
}
/// <summary>
/// 序列化参数的构造函数
/// </summary>
public UserFriendlyException(SerializationInfo serializationInfo, StreamingContext context)
: base(serializationInfo, context)
{
}
}
}

View File

@@ -0,0 +1,132 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Attributes;
using Yi.Framework.Core.DependencyInjection;
namespace Yi.Framework.Core.Extensions
{
public static class AutoIocAddExtensions
{
public static IServiceCollection AddAutoIocServer(this IServiceCollection services, params string[] assemblyStr)
{
foreach (var a in assemblyStr)
{
RegIoc(services, Assembly.Load(a));
}
return services;
}
/// <summary>
/// 扫描全部
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddAutoIocServer(this IServiceCollection services)
{
var assemblys = Yi.Framework.Core.Module.ModuleAssembly.Assemblies;
foreach (var a in assemblys)
{
RegIoc(services, a);
}
return services;
}
private static void RegIoc(IServiceCollection services, Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
RegIocByAttribute(services, type);
RegIocByInterface(services, type);
}
}
private static void RegIocByAttribute(IServiceCollection services, Type type)
{
var serviceAttributes = type.GetCustomAttributes<AppServiceAttribute>();
if (serviceAttributes is null)
{
return;
}
//处理多个特性注入情况
foreach (var serviceAttribute in serviceAttributes)
{
if (serviceAttribute is not null)
{
//泛型类需要单独进行处理
//情况1使用自定义[AppService(ServiceType = typeof(注册抽象或者接口))]手动去注册放type即可
var serviceType = serviceAttribute.ServiceType;
//if (serviceType is not null && serviceType.Name.Contains("IDataSeed`"))
//{
// Console.WriteLine();
//}
//情况2 自动去找接口,如果存在就是接口,如果不存在就是本身
if (serviceType == null)
{
//获取最远靠近的接口
var p = type.GetInterfaces().ToList();
var firstInter = type.GetInterfaces().Where(u => u.Name == $"I{type.Name}").LastOrDefault();
if (firstInter is null)
{
serviceType = type;
}
else
{
serviceType = firstInter;
}
}
switch (serviceAttribute.ServiceLifetime)
{
case LifeTime.Singleton:
services.AddSingleton(serviceType, type);
break;
case LifeTime.Scoped:
services.AddScoped(serviceType, type);
break;
case LifeTime.Transient:
services.AddTransient(serviceType, type);
break;
}
}
}
}
private static void RegIocByInterface(IServiceCollection services, Type type)
{
var serviceInterfaces = type.GetInterfaces();
if (serviceInterfaces is not null)
{
var serviceType = type;
//规范
var firstInter = type.GetInterfaces().Where(u => u != typeof(ITransientDependency) && u.Name == $"I{type.Name}").LastOrDefault();
if (firstInter is not null)
{
serviceType = firstInter;
}
if (serviceInterfaces.Contains(typeof(ITransientDependency)))
{
services.AddTransient(serviceType, type);
}
if (serviceInterfaces.Contains(typeof(IScopedDependency)))
{
services.AddScoped(serviceType, type);
}
if (serviceInterfaces.Contains(typeof(ISingletonDependency)))
{
services.AddSingleton(serviceType, type);
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StartupModules.Internal;
using StartupModules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Yi.Framework.Core.Module;
namespace Yi.Framework.Core.Extensions
{
/// <summary>
/// 该类来自于StartupModules
/// </summary>
public static class ModuleExtensions
{
public static WebApplicationBuilder UseYiModules(this WebApplicationBuilder builder, Type startType)
{
var moduleManager = new ModuleManager(startType);
Assembly[] assemblies2 = moduleManager.ToAssemblyArray(moduleManager.Invoker());
return builder.UseStartupModules(delegate (StartupModulesOptions options)
{
options.DiscoverStartupModules(assemblies2);
});
}
}
}

View File

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

View File

@@ -0,0 +1,101 @@
using System;
using System.Text;
namespace Yi.Framework.Core.Helper
{
public sealed class Base32Helper
{
// the valid chars for the encoding
private static string ValidChars = "QAZ2WSX3" + "EDC4RFV5" + "TGB6YHN7" + "UJM8K9LP";
/// <summary>
/// Converts an array of bytes to a Base32-k string.
/// </summary>
public static string ToString(byte[] bytes)
{
StringBuilder sb = new StringBuilder(); // holds the base32 chars
byte index;
int hi = 5;
int currentByte = 0;
while (currentByte < bytes.Length)
{
// do we need to use the next byte?
if (hi > 8)
{
// get the last piece from the current byte, shift it to the right
// and increment the byte counter
index = (byte)(bytes[currentByte++] >> (hi - 5));
if (currentByte != bytes.Length)
{
// if we are not at the end, get the first piece from
// the next byte, clear it and shift it to the left
index = (byte)(((byte)(bytes[currentByte] << (16 - hi)) >> 3) | index);
}
hi -= 3;
}
else if (hi == 8)
{
index = (byte)(bytes[currentByte++] >> 3);
hi -= 3;
}
else
{
// simply get the stuff from the current byte
index = (byte)((byte)(bytes[currentByte] << (8 - hi)) >> 3);
hi += 5;
}
sb.Append(ValidChars[index]);
}
return sb.ToString();
}
/// <summary>
/// Converts a Base32-k string into an array of bytes.
/// </summary>
/// <exception cref="System.ArgumentException">
/// Input string <paramref name="s">s</paramref> contains invalid Base32-k characters.
/// </exception>
public static byte[] FromBase32String(string str)
{
int numBytes = str.Length * 5 / 8;
byte[] bytes = new Byte[numBytes];
// all UPPERCASE chars
str = str.ToUpper();
int bit_buffer;
int currentCharIndex;
int bits_in_buffer;
if (str.Length < 3)
{
bytes[0] = (byte)(ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5);
return bytes;
}
bit_buffer = (ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5);
bits_in_buffer = 10;
currentCharIndex = 2;
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)bit_buffer;
bit_buffer >>= 8;
bits_in_buffer -= 8;
while (bits_in_buffer < 8 && currentCharIndex < str.Length)
{
bit_buffer |= ValidChars.IndexOf(str[currentCharIndex++]) << bits_in_buffer;
bits_in_buffer += 5;
}
}
return bytes;
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
namespace Yi.Framework.Core.Helper
{
public static class ConsoleHelper
{
public static void WriteColorLine(string str, ConsoleColor color)
{
ConsoleColor currentForeColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.WriteLine(str);
Console.ForegroundColor = currentForeColor;
}
/// <summary>
/// 打印错误信息
/// </summary>
/// <param name="str">待打印的字符串</param>
/// <param name="color">想要打印的颜色</param>
public static void WriteErrorLine(this string str, ConsoleColor color = ConsoleColor.Red)
{
WriteColorLine(str, color);
}
/// <summary>
/// 打印警告信息
/// </summary>
/// <param name="str">待打印的字符串</param>
/// <param name="color">想要打印的颜色</param>
public static void WriteWarningLine(this string str, ConsoleColor color = ConsoleColor.Yellow)
{
WriteColorLine(str, color);
}
/// <summary>
/// 打印正常信息
/// </summary>
/// <param name="str">待打印的字符串</param>
/// <param name="color">想要打印的颜色</param>
public static void WriteInfoLine(this string str, ConsoleColor color = ConsoleColor.White)
{
WriteColorLine(str, color);
}
/// <summary>
/// 打印成功的信息
/// </summary>
/// <param name="str">待打印的字符串</param>
/// <param name="color">想要打印的颜色</param>
public static void WriteSuccessLine(this string str, ConsoleColor color = ConsoleColor.Green)
{
WriteColorLine(str, color);
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
namespace Yi.Framework.Core.Helper
{
public class DateHelper
{
public static DateTime StampToDateTime(string time)
{
time = time.Substring(0, 10);
double timestamp = Convert.ToInt64(time);
System.DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
dateTime = dateTime.AddSeconds(timestamp).ToLocalTime();
return dateTime;
}
public static string TimeSubTract(DateTime time1,DateTime time2)
{
TimeSpan subTract = time1.Subtract(time2);
return $"{subTract.Days} 天 {subTract.Hours} 时 {subTract.Minutes} 分 ";
}
/// <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();
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public class Compare<T, C> : IEqualityComparer<T>
{
private Func<T, C> _getField;
public Compare(Func<T, C> getfield)
{
this._getField = getfield;
}
public bool Equals(T? x, T? y)
{
return EqualityComparer<C>.Default.Equals(_getField(x!), _getField(y!));
}
public int GetHashCode(T obj)
{
return EqualityComparer<C>.Default.GetHashCode(this._getField(obj)!);
}
}
public static class DistinctHelper
{
/// <summary>
/// 自定义Distinct扩展方法
/// </summary>
/// <typeparam name="T">要去重的对象类</typeparam>
/// <typeparam name="C">自定义去重的字段类型</typeparam>
/// <param name="source">要去重的对象</param>
/// <param name="getfield">获取自定义去重字段的委托</param>
/// <returns></returns>
public static IEnumerable<T> DistinctNew<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
{
return source.Distinct(new Compare<T, C>(getfield));
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,490 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Yi.Framework.Core.Helper
{
public class FileHelper : IDisposable
{
private bool _alreadyDispose = false;
#region
public FileHelper()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
~FileHelper()
{
Dispose(); ;
}
protected virtual void Dispose(bool isDisposing)
{
if (_alreadyDispose) return;
_alreadyDispose = true;
}
#endregion
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#region
/****************************************
* 函数名称GetPostfixStr
* 功能说明:取得文件后缀名
* 参 数filename:文件名称
* 调用示列:
* string filename = "aaa.aspx";
* string s = EC.FileObj.GetPostfixStr(filename);
*****************************************/
/// <summary>
/// 取后缀名
/// </summary>
/// <param name="filename">文件名</param>
/// <returns>.gif|.html格式</returns>
public static string GetPostfixStr(string filename)
{
int start = filename.LastIndexOf(".");
int length = filename.Length;
string postfix = filename.Substring(start, length - start);
return postfix;
}
#endregion
#region
/// <summary>
/// 根据文件大小获取指定前缀的可用文件名
/// </summary>
/// <param name="folderPath">文件夹</param>
/// <param name="prefix">文件前缀</param>
/// <param name="size">文件大小(1m)</param>
/// <param name="ext">文件后缀(.log)</param>
/// <returns>可用文件名</returns>
//public static string GetAvailableFileWithPrefixOrderSize(string folderPath, string prefix, int size = 1 * 1024 * 1024, string ext = ".log")
//{
// var allFiles = new DirectoryInfo(folderPath);
// var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(prefix.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d=>d.Name).ToList();
// if (selectFiles.Count > 0)
// {
// return selectFiles.FirstOrDefault().FullName;
// }
// return Path.Combine(folderPath, $@"{prefix}_{DateTime.Now.DateToTimeStamp()}.log");
//}
//public static string GetAvailableFileNameWithPrefixOrderSize(string _contentRoot, string prefix, int size = 1 * 1024 * 1024, string ext = ".log")
//{
// var folderPath = Path.Combine(_contentRoot, "Log");
// if (!Directory.Exists(folderPath))
// {
// Directory.CreateDirectory(folderPath);
// }
// var allFiles = new DirectoryInfo(folderPath);
// var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(prefix.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d => d.Name).ToList();
// if (selectFiles.Count > 0)
// {
// return selectFiles.FirstOrDefault().Name.Replace(".log","");
// }
// return $@"{prefix}_{DateTime.Now.DateToTimeStamp()}";
//}
#endregion
#region
/****************************************
* 函数名称WriteFile
* 功能说明:写文件,会覆盖掉以前的内容
* 参 数Path:文件路径,Strings:文本内容
* 调用示列:
* string Path = Server.MapPath("Default2.aspx");
* string Strings = "这是我写的内容啊";
* EC.FileObj.WriteFile(Path,Strings);
*****************************************/
/// <summary>
/// 写文件
/// </summary>
/// <param name="Path">文件路径</param>
/// <param name="Strings">文件内容</param>
public static void WriteFile(string Path, string Strings)
{
if (!File.Exists(Path))
{
FileStream f = File.Create(Path);
f.Close();
}
StreamWriter f2 = new StreamWriter(Path, false, Encoding.GetEncoding("gb2312"));
f2.Write(Strings);
f2.Close();
f2.Dispose();
}
/// <summary>
/// 写文件
/// </summary>
/// <param name="Path">文件路径</param>
/// <param name="Strings">文件内容</param>
/// <param name="encode">编码格式</param>
public static void WriteFile(string Path, string Strings, Encoding encode)
{
if (!File.Exists(Path))
{
FileStream f = File.Create(Path);
f.Close();
}
StreamWriter f2 = new StreamWriter(Path, false, encode);
f2.Write(Strings);
f2.Close();
f2.Dispose();
}
#endregion
#region
/****************************************
* 函数名称ReadFile
* 功能说明:读取文本内容
* 参 数Path:文件路径
* 调用示列:
* string Path = Server.MapPath("Default2.aspx");
* string s = EC.FileObj.ReadFile(Path);
*****************************************/
/// <summary>
/// 读文件
/// </summary>
/// <param name="Path">文件路径</param>
/// <returns></returns>
public static string ReadFile(string Path)
{
string s = "";
if (!File.Exists(Path))
s = "不存在相应的目录";
else
{
StreamReader f2 = new StreamReader(Path, Encoding.GetEncoding("gb2312"));
s = f2.ReadToEnd();
f2.Close();
f2.Dispose();
}
return s;
}
/// <summary>
/// 读文件
/// </summary>
/// <param name="Path">文件路径</param>
/// <param name="encode">编码格式</param>
/// <returns></returns>
public static string ReadFile(string Path, Encoding encode)
{
string s = "";
if (!File.Exists(Path))
s = "不存在相应的目录";
else
{
StreamReader f2 = new StreamReader(Path, encode);
s = f2.ReadToEnd();
f2.Close();
f2.Dispose();
}
return s;
}
#endregion
#region
/****************************************
* 函数名称FileAdd
* 功能说明:追加文件内容
* 参 数Path:文件路径,strings:内容
* 调用示列:
* string Path = Server.MapPath("Default2.aspx");
* string Strings = "新追加内容";
* EC.FileObj.FileAdd(Path, Strings);
*****************************************/
/// <summary>
/// 追加文件
/// </summary>
/// <param name="Path">文件路径</param>
/// <param name="strings">内容</param>
public static void FileAdd(string Path, string strings)
{
StreamWriter sw = File.AppendText(Path);
sw.Write(strings);
sw.Flush();
sw.Close();
}
#endregion
#region
/****************************************
* 函数名称FileCoppy
* 功能说明:拷贝文件
* 参 数OrignFile:原始文件,NewFile:新文件路径
* 调用示列:
* string orignFile = Server.MapPath("Default2.aspx");
* string NewFile = Server.MapPath("Default3.aspx");
* EC.FileObj.FileCoppy(OrignFile, NewFile);
*****************************************/
/// <summary>
/// 拷贝文件
/// </summary>
/// <param name="OrignFile">原始文件</param>
/// <param name="NewFile">新文件路径</param>
public static void FileCoppy(string orignFile, string NewFile)
{
File.Copy(orignFile, NewFile, true);
}
#endregion
#region
/****************************************
* 函数名称FileDel
* 功能说明:删除文件
* 参 数Path:文件路径
* 调用示列:
* string Path = Server.MapPath("Default3.aspx");
* EC.FileObj.FileDel(Path);
*****************************************/
/// <summary>
/// 删除文件
/// </summary>
/// <param name="Path">路径</param>
public static void FileDel(string Path)
{
File.Delete(Path);
}
#endregion
#region
/****************************************
* 函数名称FileMove
* 功能说明:移动文件
* 参 数OrignFile:原始路径,NewFile:新文件路径
* 调用示列:
* string orignFile = Server.MapPath("../说明.txt");
* string NewFile = Server.MapPath("http://www.cnblogs.com/说明.txt");
* EC.FileObj.FileMove(OrignFile, NewFile);
*****************************************/
/// <summary>
/// 移动文件
/// </summary>
/// <param name="OrignFile">原始路径</param>
/// <param name="NewFile">新路径</param>
public static void FileMove(string orignFile, string NewFile)
{
File.Move(orignFile, NewFile);
}
#endregion
#region
/****************************************
* 函数名称FolderCreate
* 功能说明:在当前目录下创建目录
* 参 数OrignFolder:当前目录,NewFloder:新目录
* 调用示列:
* string orignFolder = Server.MapPath("test/");
* string NewFloder = "new";
* EC.FileObj.FolderCreate(OrignFolder, NewFloder);
*****************************************/
/// <summary>
/// 在当前目录下创建目录
/// </summary>
/// <param name="OrignFolder">当前目录</param>
/// <param name="NewFloder">新目录</param>
public static void FolderCreate(string orignFolder, string NewFloder)
{
Directory.SetCurrentDirectory(orignFolder);
Directory.CreateDirectory(NewFloder);
}
#endregion
#region
/****************************************
* 函数名称DeleteFolder
* 功能说明:递归删除文件夹目录及文件
* 参 数dir:文件夹路径
* 调用示列:
* string dir = Server.MapPath("test/");
* EC.FileObj.DeleteFolder(dir);
*****************************************/
/// <summary>
/// 递归删除文件夹目录及文件
/// </summary>
/// <param name="dir"></param>
/// <returns></returns>
public static void DeleteFolder(string dir)
{
if (Directory.Exists(dir)) //如果存在这个文件夹删除之
{
foreach (string d in Directory.GetFileSystemEntries(dir))
{
if (File.Exists(d))
File.Delete(d); //直接删除其中的文件
else
DeleteFolder(d); //递归删除子文件夹
}
Directory.Delete(dir); //删除已空文件夹
}
}
#endregion
#region copy到目标文件夹下面
/****************************************
* 函数名称CopyDir
* 功能说明将指定文件夹下面的所有内容copy到目标文件夹下面 果目标文件夹为只读属性就会报错。
* 参 数srcPath:原始路径,aimPath:目标文件夹
* 调用示列:
* string srcPath = Server.MapPath("test/");
* string aimPath = Server.MapPath("test1/");
* EC.FileObj.CopyDir(srcPath,aimPath);
*****************************************/
/// <summary>
/// 指定文件夹下面的所有内容copy到目标文件夹下面
/// </summary>
/// <param name="srcPath">原始路径</param>
/// <param name="aimPath">目标文件夹</param>
public static void CopyDir(string srcPath, string aimPath)
{
try
{
// 检查目标目录是否以目录分割字符结束如果不是则添加之
if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar)
aimPath += Path.DirectorySeparatorChar;
// 判断目标目录是否存在如果不存在则新建之
if (!Directory.Exists(aimPath))
Directory.CreateDirectory(aimPath);
// 得到源目录的文件列表,该里面是包含文件以及目录路径的一个数组
//如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法
//string[] fileList = Directory.GetFiles(srcPath);
string[] fileList = Directory.GetFileSystemEntries(srcPath);
//遍历所有的文件和目录
foreach (string file in fileList)
{
//先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
if (Directory.Exists(file))
CopyDir(file, aimPath + Path.GetFileName(file));
//否则直接Copy文件
else
File.Copy(file, aimPath + Path.GetFileName(file), true);
}
}
catch (Exception ee)
{
throw new Exception(ee.ToString());
}
}
#endregion
/// <summary>
/// 获取目录下全部文件名
/// </summary>
/// <param name="path"></param>
/// <param name="pattern"></param>
/// <returns></returns>
public static List<string> GetAllFileNames(string path, string pattern = "*")
{
List<FileInfo> folder = new DirectoryInfo(path).GetFiles(pattern).ToList();
return folder.Select(x => x.Name).ToList();
}
/// <summary>
/// 文件内容替换
/// </summary>
public static string FileContentReplace(string path, string oldStr, string newStr)
{
var content = File.ReadAllText(path);
if (content.Contains(oldStr))
{
File.Delete(path);
File.WriteAllText(path, content.Replace(oldStr, newStr));
}
return path;
}
/// <summary>
/// 文件名称
/// </summary>
public static string FileNameReplace(string path, string oldStr, string newStr)
{
string fileName = Path.GetFileName(path);
if (!fileName.Contains(oldStr))
{
return path;
}
string? directoryName = Path.GetDirectoryName(path);
string newFileName = fileName.Replace(oldStr, newStr);
string newPath = Path.Combine(directoryName ?? "", newFileName);
File.Move(path, newPath);
return newPath;
}
/// <summary>
/// 目录名替换
/// </summary>
public static string DirectoryNameReplace(string path, string oldStr, string newStr)
{
string fileName = Path.GetFileName(path);
if (!fileName.Contains(oldStr))
{
return path;
}
string? directoryName = Path.GetDirectoryName(path);
string newFileName = fileName.Replace(oldStr, newStr);
string newPath = Path.Combine(directoryName ?? "", newFileName);
Directory.Move(path, newPath);
return newPath;
}
/// <summary>
/// 全部信息递归替换
/// </summary>
/// <param name="dirPath"></param>
/// <param name="oldStr"></param>
/// <param name="newStr"></param>
public static void AllInfoReplace(string dirPath, string oldStr, string newStr)
{
var path = DirectoryNameReplace(dirPath, oldStr, newStr);
var dirInfo = new DirectoryInfo(path);
var files = dirInfo.GetFiles();
var dirs = dirInfo.GetDirectories();
if (files.Length > 0)
{
foreach (var f in files)
{
FileContentReplace(f.FullName, oldStr, newStr);
FileNameReplace(f.FullName, oldStr, newStr);
}
}
if (dirs.Length > 0)
{
foreach (var d in dirs)
{
AllInfoReplace(d.FullName, oldStr, newStr);
}
}
}
}
}

View File

@@ -0,0 +1,24 @@
namespace Yi.Framework.Core.Helper
{
public static class HtmlHelper
{
#region HTML标签
/// <summary>
/// 去除富文本中的HTML标签
/// </summary>
/// <param name="html"></param>
/// <param name="length"></param>
/// <returns></returns>
public static string ReplaceHtmlTag(string html, int length = 0)
{
string strText = System.Text.RegularExpressions.Regex.Replace(html, "<[^>]+>", "");
strText = System.Text.RegularExpressions.Regex.Replace(strText, "&[^;]+;", "");
if (length > 0 && strText.Length > length)
return strText.Substring(0, length);
return strText;
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public static class IdHelper
{
public static dynamic[] ToDynamicArray(this IEnumerable<long> ids)
{
return ids.Select(id => (dynamic)id).ToArray();
}
}
}

View File

@@ -0,0 +1,56 @@
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
namespace Yi.Framework.Core.Helper
{
public class IpHelper
{
/// <summary>
/// 获取当前IP地址
/// </summary>
/// <param name="preferredNetworks"></param>
/// <returns></returns>
public static string GetCurrentIp(string preferredNetworks)
{
var instanceIp = "127.0.0.1";
try
{
// 获取可用网卡
var nics = NetworkInterface.GetAllNetworkInterfaces()?.Where(network => network.OperationalStatus == OperationalStatus.Up);
// 获取所有可用网卡IP信息
var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses);
if (ipCollection is null)
{
return instanceIp;
}
foreach (var ipadd in ipCollection)
{
if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork)
{
if (string.IsNullOrEmpty(preferredNetworks))
{
instanceIp = ipadd.Address.ToString();
break;
}
if (!ipadd.Address.ToString().StartsWith(preferredNetworks)) continue;
instanceIp = ipadd.Address.ToString();
break;
}
}
}
catch
{
// ignored
}
return instanceIp;
}
}
}

View File

@@ -0,0 +1,518 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Text.Json;
namespace Yi.Framework.Core.Helper
{
public class JsonHelper
{
public static string ObjToStr<T>(T obj, string dateTimeFormat)
{
IsoDateTimeConverter timeConverter = new IsoDateTimeConverter()
{
DateTimeFormat = dateTimeFormat
};
return Newtonsoft.Json.JsonConvert.SerializeObject(obj, Formatting.Indented, timeConverter);
}
public static string ObjToStr<T>(T obj)
{
return Newtonsoft.Json.JsonConvert.SerializeObject(obj);
}
public static T StrToObj<T>(string str)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(str)!;
}
/// <summary>
/// 转换对象为JSON格式数据
/// </summary>
/// <typeparam name="T">类</typeparam>
/// <param name="obj">对象</param>
/// <returns>字符格式的JSON数据</returns>
public static string GetJSON<T>(object obj)
{
string result = String.Empty;
try
{
System.Text.Json.JsonSerializer.Serialize("");
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer =
new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
serializer.WriteObject(ms, obj);
result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
}
}
catch (Exception)
{
throw;
}
return result;
}
/// <summary>
/// 转换List<T>的数据为JSON格式
/// </summary>
/// <typeparam name="T">类</typeparam>
/// <param name="vals">列表值</param>
/// <returns>JSON格式数据</returns>
public string JSON<T>(List<T> vals)
{
System.Text.StringBuilder st = new System.Text.StringBuilder();
try
{
System.Runtime.Serialization.Json.DataContractJsonSerializer s = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
foreach (T city in vals)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
s.WriteObject(ms, city);
st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray()));
}
}
}
catch (Exception)
{
}
return st.ToString();
}
/// <summary>
/// JSON格式字符转换为T类型的对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="jsonStr"></param>
/// <returns></returns>
public static T ParseFormByJson<T>(string jsonStr)
{
T obj = Activator.CreateInstance<T>();
using (System.IO.MemoryStream ms =
new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonStr)))
{
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer =
new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(ms)!;
}
}
public string JSON1<SendData>(List<SendData> vals)
{
System.Text.StringBuilder st = new System.Text.StringBuilder();
try
{
System.Runtime.Serialization.Json.DataContractJsonSerializer s = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(SendData));
foreach (SendData city in vals)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
s.WriteObject(ms, city);
st.Append(System.Text.Encoding.UTF8.GetString(ms.ToArray()));
}
}
}
catch (Exception)
{
}
return st.ToString();
}
private static bool IsJsonStart(ref string json)
{
if (!string.IsNullOrEmpty(json))
{
json = json.Trim('\r', '\n', ' ');
if (json.Length > 1)
{
char s = json[0];
char e = json[json.Length - 1];
return (s == '{' && e == '}') || (s == '[' && e == ']');
}
}
return false;
}
public static bool IsJson(string json)
{
int errIndex;
return IsJson(json, out errIndex);
}
public static bool IsJson(string json, out int errIndex)
{
errIndex = 0;
if (IsJsonStart(ref json))
{
CharState cs = new CharState();
char c;
for (int i = 0; i < json.Length; i++)
{
c = json[i];
if (SetCharState(c, ref cs) && cs.childrenStart)//设置关键符号状态。
{
string item = json.Substring(i);
int err;
int length = GetValueLength(item, true, out err);
cs.childrenStart = false;
if (err > 0)
{
errIndex = i + err;
return false;
}
i = i + length - 1;
}
if (cs.isError)
{
errIndex = i;
return false;
}
}
return !cs.arrayStart && !cs.jsonStart;
}
return false;
}
/// <summary>
/// 获取值的长度当Json值嵌套以"{"或"["开头时)
/// </summary>
private static int GetValueLength(string json, bool breakOnErr, out int errIndex)
{
errIndex = 0;
int len = 0;
if (!string.IsNullOrEmpty(json))
{
CharState cs = new CharState();
char c;
for (int i = 0; i < json.Length; i++)
{
c = json[i];
if (!SetCharState(c, ref cs))//设置关键符号状态。
{
if (!cs.jsonStart && !cs.arrayStart)//json结束又不是数组则退出。
{
break;
}
}
else if (cs.childrenStart)//正常字符,值状态下。
{
int length = GetValueLength(json.Substring(i), breakOnErr, out errIndex);//递归子值,返回一个长度。。。
cs.childrenStart = false;
cs.valueStart = 0;
//cs.state = 0;
i = i + length - 1;
}
if (breakOnErr && cs.isError)
{
errIndex = i;
return i;
}
if (!cs.jsonStart && !cs.arrayStart)//记录当前结束位置。
{
len = i + 1;//长度比索引+1
break;
}
}
}
return len;
}
/// <summary>
/// 设置字符状态(返回true则为关键词返回false则当为普通字符处理
/// </summary>
private static bool SetCharState(char c, ref CharState cs)
{
cs.CheckIsError(c);
switch (c)
{
case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
#region
if (cs.keyStart <= 0 && cs.valueStart <= 0)
{
cs.keyStart = 0;
cs.valueStart = 0;
if (cs.jsonStart && cs.state == 1)
{
cs.childrenStart = true;
}
else
{
cs.state = 0;
}
cs.jsonStart = true;//开始。
return true;
}
#endregion
break;
case '}':
#region
if (cs.keyStart <= 0 && cs.valueStart < 2 && cs.jsonStart)
{
cs.jsonStart = false;//正常结束。
cs.state = 0;
cs.keyStart = 0;
cs.valueStart = 0;
cs.setDicValue = true;
return true;
}
// cs.isError = !cs.jsonStart && cs.state == 0;
#endregion
break;
case '[':
#region
if (!cs.jsonStart)
{
cs.arrayStart = true;
return true;
}
else if (cs.jsonStart && cs.state == 1)
{
cs.childrenStart = true;
return true;
}
#endregion
break;
case ']':
#region
if (cs.arrayStart && !cs.jsonStart && cs.keyStart <= 2 && cs.valueStart <= 0)//[{},333]//这样结束。
{
cs.keyStart = 0;
cs.valueStart = 0;
cs.arrayStart = false;
return true;
}
#endregion
break;
case '"':
case '\'':
#region
if (cs.jsonStart || cs.arrayStart)
{
if (cs.state == 0)//key阶段,有可能是数组["aa",{}]
{
if (cs.keyStart <= 0)
{
cs.keyStart = (c == '"' ? 3 : 2);
return true;
}
else if ((cs.keyStart == 2 && c == '\'') || (cs.keyStart == 3 && c == '"'))
{
if (!cs.escapeChar)
{
cs.keyStart = -1;
return true;
}
else
{
cs.escapeChar = false;
}
}
}
else if (cs.state == 1 && cs.jsonStart)//值阶段必须是Json开始了。
{
if (cs.valueStart <= 0)
{
cs.valueStart = (c == '"' ? 3 : 2);
return true;
}
else if ((cs.valueStart == 2 && c == '\'') || (cs.valueStart == 3 && c == '"'))
{
if (!cs.escapeChar)
{
cs.valueStart = -1;
return true;
}
else
{
cs.escapeChar = false;
}
}
}
}
#endregion
break;
case ':':
#region
if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 0)
{
if (cs.keyStart == 1)
{
cs.keyStart = -1;
}
cs.state = 1;
return true;
}
// cs.isError = !cs.jsonStart || (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1);
#endregion
break;
case ',':
#region //["aa",{aa:12,}]
if (cs.jsonStart)
{
if (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1)
{
cs.state = 0;
cs.keyStart = 0;
cs.valueStart = 0;
//if (cs.valueStart == 1)
//{
// cs.valueStart = 0;
//}
cs.setDicValue = true;
return true;
}
}
else if (cs.arrayStart && cs.keyStart <= 2)
{
cs.keyStart = 0;
//if (cs.keyStart == 1)
//{
// cs.keyStart = -1;
//}
return true;
}
#endregion
break;
case ' ':
case '\r':
case '\n'://[ "a",\r\n{} ]
case '\0':
case '\t':
if (cs.keyStart <= 0 && cs.valueStart <= 0) //cs.jsonStart &&
{
return true;//跳过空格。
}
break;
default: //值开头。。
if (c == '\\') //转义符号
{
if (cs.escapeChar)
{
cs.escapeChar = false;
}
else
{
cs.escapeChar = true;
return true;
}
}
else
{
cs.escapeChar = false;
}
if (cs.jsonStart || cs.arrayStart) // Json 或数组开始了。
{
if (cs.keyStart <= 0 && cs.state == 0)
{
cs.keyStart = 1;//无引号的
}
else if (cs.valueStart <= 0 && cs.state == 1 && cs.jsonStart)//只有Json开始才有值。
{
cs.valueStart = 1;//无引号的
}
}
break;
}
return false;
}
}
/// <summary>
/// 字符状态
/// </summary>
public class CharState
{
internal bool jsonStart = false;//以 "{"开始了...
internal bool setDicValue = false;// 可以设置字典值了。
internal bool escapeChar = false;//以"\"转义符号开始了
/// <summary>
/// 数组开始【仅第一开头才算】值嵌套的以【childrenStart】来标识。
/// </summary>
internal bool arrayStart = false;//以"[" 符号开始了
internal bool childrenStart = false;//子级嵌套开始了。
/// <summary>
/// 【0 初始状态,或 遇到“,”逗号】【1 遇到“:”冒号】
/// </summary>
internal int state = 0;
/// <summary>
/// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】
/// </summary>
internal int keyStart = 0;
/// <summary>
/// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】
/// </summary>
internal int valueStart = 0;
internal bool isError = false;//是否语法错误。
internal void CheckIsError(char c)//只当成一级处理因为GetLength会递归到每一个子项处理
{
if (keyStart > 1 || valueStart > 1)
{
return;
}
//示例 ["aa",{"bbbb":123,"fff","ddd"}]
switch (c)
{
case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。
break;
case '}':
isError = !jsonStart || (keyStart != 0 && state == 0);//重复结束错误 或者 提前结束{"aa"}。正常的有{}
break;
case '[':
isError = arrayStart && state == 0;//重复开始错误
break;
case ']':
isError = !arrayStart || jsonStart;//重复开始错误 或者 Json 未结束
break;
case '"':
case '\'':
isError = !(jsonStart || arrayStart); //json 或数组开始。
if (!isError)
{
//重复开始 [""",{"" "}]
isError = (state == 0 && keyStart == -1) || (state == 1 && valueStart == -1);
}
if (!isError && arrayStart && !jsonStart && c == '\'')//['aa',{}]
{
isError = true;
}
break;
case ':':
isError = !jsonStart || state == 1;//重复出现。
break;
case ',':
isError = !(jsonStart || arrayStart); //json 或数组开始。
if (!isError)
{
if (jsonStart)
{
isError = state == 0 || (state == 1 && valueStart > 1);//重复出现。
}
else if (arrayStart)//["aa,] [,] [{},{}]
{
isError = keyStart == 0 && !setDicValue;
}
}
break;
case ' ':
case '\r':
case '\n'://[ "a",\r\n{} ]
case '\0':
case '\t':
break;
default: //值开头。。
isError = (!jsonStart && !arrayStart) || (state == 0 && keyStart == -1) || (valueStart == -1 && state == 1);//
break;
}
//if (isError)
//{
//}
}
}
}

View File

@@ -0,0 +1,132 @@
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 = SHA512Managed.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

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

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public class RSAFileHelper
{
public static RSA GetKey()
{
return GetRSA("key.pem");
}
public static RSA GetPublicKey()
{
return GetRSA("public.pem");
}
private static RSA GetRSA(string fileName)
{
string rootPath = Directory.GetCurrentDirectory();
string filePath = Path.Combine(rootPath, fileName);
if (!System.IO.File.Exists(filePath))
throw new Exception("文件不存在");
string key = System.IO.File.ReadAllText(filePath);
var rsa = RSA.Create();
rsa.ImportFromPem(key.AsSpan());
return rsa;
}
}
}

View File

@@ -0,0 +1,390 @@
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 = (int)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

@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace Yi.Framework.Core.Helper
{
public class RandomHelper
{
public static string replaceBianLiang(string content)
{
content = content.Replace("{当前时间}", DateTime.Now.TimeOfDay.ToString());
string[] bianliang = new string[] { "{随机字母}", "{随机数字}", "{随机汉字}" };
Regex r;
int count;
string readstr = "";
foreach (string str in bianliang)
{
count = (content.Length - content.Replace(str, "").Length) / str.Length;
if (str == "{随机汉字}") readstr = RandChina(count);
if (str == "{随机数字}") readstr = GenerateCheckCodeNum(count);
if (str == "{随机字母}") readstr = GenerateRandomLetter(count);
if (count > readstr.Length) count = readstr.Length;
r = new Regex(str.Replace("{", "\\{").Replace("}", "\\}"));
for (int i = 0; i < count; i++)
{
content = r.Replace(content, readstr.Substring(i, 1), 1);
}
}
return content;
}
/// <summary>
/// 随机生成字母
/// </summary>
/// <param name="Length"></param>
/// <returns></returns>
public static string GenerateRandomLetter(int Length)
{
char[] Pattern = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
string result = "";
int n = Pattern.Length;
Random random = new Random(~unchecked((int)DateTime.Now.Ticks));
for (int i = 0; i < Length; i++)
{
int rnd = random.Next(0, n);
result += Pattern[rnd];
}
return result;
}
/// <summary>
/// 随机生成数字
/// </summary>
/// <param name="codeCount"></param>
/// <returns></returns>
public static string GenerateCheckCodeNum(int codeCount)
{
int rep = 0;
string str = string.Empty;
long num2 = DateTime.Now.Ticks + rep;
rep++;
Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep)));
for (int i = 0; i < codeCount; i++)
{
int num = random.Next();
str = str + ((char)(0x30 + ((ushort)(num % 10)))).ToString();
}
return str;
}
/// <summary>
/// 此函数为生成指定数目的汉字
/// </summary>
/// <param name="charLen">汉字数目</param>
/// <returns>所有汉字</returns>
public static string RandChina(int charLen)
{
int area, code;//汉字由区位和码位组成(都为0-94,其中区位16-55为一级汉字区,56-87为二级汉字区,1-9为特殊字符区)
StringBuilder strtem = new StringBuilder();
Random rand = new Random();
for (int i = 0; i < charLen; i++)
{
area = rand.Next(16, 88);
if (area == 55)//第55区只有89个字符
{
code = rand.Next(1, 90);
}
else
{
code = rand.Next(1, 94);
}
strtem.Append(Encoding.GetEncoding("GB2312").GetString(new byte[] { Convert.ToByte(area + 160), Convert.ToByte(code + 160) }));
}
return strtem.ToString();
}
}
}

View File

@@ -0,0 +1,63 @@
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

@@ -0,0 +1,102 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public static class SnowflakeHelper
{
public static long NextId { get => SnowFlakeSingle.Instance.NextId(); }
public static long Next()
{
SnowflakeTool snowflakeTool = new SnowflakeTool(1);
return snowflakeTool.NextId();
}
private class SnowflakeTool
{
//机器ID
private static long nodeId;
private static long twepoch = 687888001020L; //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳
private static long sequence = 0L;
private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码(定义为Long类型会出现最大偏移64位所以左移64位没有意义)
public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID
private static int sequenceBits = 10; //计数器字节数10个字节用来保存计数码
private static int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数
public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
private long lastTimestamp = -1L;
/// <summary>
/// 机器码
/// </summary>
/// <param name="workerId"></param>
public SnowflakeTool(long workerId)
{
if (workerId > maxWorkerId || workerId < 0)
throw new Exception(string.Format("节点id 不能大于 {0} 或者 小于 0 ", workerId));
SnowflakeTool.nodeId = workerId;
}
public long NextId()
{
lock (this)
{
long timestamp = TimeGen();
if (this.lastTimestamp == timestamp)
{ //同一微妙中生成ID
SnowflakeTool.sequence = (SnowflakeTool.sequence + 1) & SnowflakeTool.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
if (SnowflakeTool.sequence == 0)
{
//一微妙内产生的ID计数已达上限等待下一微妙
timestamp = TillNextMillis(this.lastTimestamp);
}
}
else
{ //不同微秒生成ID
SnowflakeTool.sequence = 0; //计数清0
}
if (timestamp < lastTimestamp)
{ //如果当前时间戳比上一次生成ID时时间戳还小抛出异常因为不能保证现在生成的ID之前没有生成过
throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds",
this.lastTimestamp - timestamp));
}
this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
long nextId = (timestamp - twepoch << timestampLeftShift) | SnowflakeTool.nodeId << SnowflakeTool.workerIdShift | SnowflakeTool.sequence;
return nextId;
}
}
/// <summary>
/// 获取下一微秒时间戳
/// </summary>
/// <param name="lastTimestamp"></param>
/// <returns></returns>
private long TillNextMillis(long lastTimestamp)
{
long timestamp = TimeGen();
while (timestamp <= lastTimestamp)
{
timestamp = TimeGen();
}
return timestamp;
}
/// <summary>
/// 生成当前时间戳
/// </summary>
/// <returns></returns>
private long TimeGen()
{
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
}
}
}
}

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Yi.Framework.Core.Helper
{
public class StringHelper
{
/// <summary>
/// 根据分隔符返回前n条数据
/// </summary>
/// <param name="content">数据内容</param>
/// <param name="separator">分隔符</param>
/// <param name="top">前n条</param>
/// <param name="isDesc">是否倒序默认false</param>
/// <returns></returns>
public static List<string> GetTopDataBySeparator(string content, string separator, int top, bool isDesc = false)
{
if (string.IsNullOrEmpty(content))
{
return new List<string>() { };
}
if (string.IsNullOrEmpty(separator))
{
throw new ArgumentException("message", nameof(separator));
}
var dataArray = content.Split(separator).Where(d => !string.IsNullOrEmpty(d)).ToArray();
if (isDesc)
{
Array.Reverse(dataArray);
}
if (top > 0)
{
dataArray = dataArray.Take(top).ToArray();
}
return dataArray.ToList();
}
/// <summary>
/// 根据字段拼接get参数
/// </summary>
/// <param name="dic"></param>
/// <returns></returns>
public static string GetPars(Dictionary<string, object> dic)
{
StringBuilder sb = new StringBuilder();
string? urlPars = null;
bool isEnter = false;
foreach (var item in dic)
{
sb.Append($"{(isEnter ? "&" : "")}{item.Key}={item.Value}");
isEnter = true;
}
urlPars = sb.ToString();
return urlPars;
}
/// <summary>
/// 根据字段拼接get参数
/// </summary>
/// <param name="dic"></param>
/// <returns></returns>
public static string GetPars(Dictionary<string, string> dic)
{
StringBuilder sb = new StringBuilder();
string? urlPars = null;
bool isEnter = false;
foreach (var item in dic)
{
sb.Append($"{(isEnter ? "&" : "")}{item.Key}={item.Value}");
isEnter = true;
}
urlPars = sb.ToString();
return urlPars;
}
/// <summary>
/// 获取一个GUID
/// </summary>
/// <param name="format">格式-默认为N</param>
/// <returns></returns>
public static string GetGUID(string format="N") {
return Guid.NewGuid().ToString(format);
}
/// <summary>
/// 根据GUID获取19位的唯一数字序列
/// </summary>
/// <returns></returns>
public static long GetGuidToLongID()
{
byte[] buffer = Guid.NewGuid().ToByteArray();
return BitConverter.ToInt64(buffer, 0);
}
/// <summary>
/// 获取字符串最后X行
/// </summary>
/// <param name="resourceStr"></param>
/// <param name="length"></param>
/// <returns></returns>
public static string GetCusLine(string resourceStr, int length) {
string[] arrStr = resourceStr.Split("\r\n");
return string.Join("", (from q in arrStr select q).Skip(arrStr.Length - length + 1).Take(length).ToArray());
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Core.Helper
{
public static class TreeHelper
{
public static List<T> SetTree<T>(List<T> list, Action<T> action = null!)
{
if (list is not null && list.Count > 0)
{
IList<T> result = new List<T>();
long pid = list.Min(m => (m as ITreeModel<T>)!.ParentId);
IList<T> t = list.Where(m => (m as ITreeModel<T>)!.ParentId == pid).ToList();
foreach (T model in t)
{
if (action is not null)
{
action(model);
}
result.Add(model);
var item = (model as ITreeModel<T>);
IList<T> children = list.Where(m => (m as ITreeModel<T>)!.ParentId == item!.Id).ToList();
if (children.Count > 0)
{
SetTreeChildren(list, children, model, action!);
}
}
return result.OrderByDescending(m => (m as ITreeModel<T>)!.OrderNum).ToList();
}
return null!;
}
private static void SetTreeChildren<T>(IList<T> list, IList<T> children, T model, Action<T> action = null!)
{
var mm = (model as ITreeModel<T>);
mm!.Children = new List<T>();
foreach (T item in children)
{
if (action is not null)
{
action(item);
}
mm.Children.Add(item);
var _item = (item as ITreeModel<T>);
IList<T> _children = list.Where(m => (m as ITreeModel<T>)!.ParentId == _item!.Id).ToList();
if (_children.Count > 0)
{
SetTreeChildren(list, _children, item, action!);
}
}
mm.Children = mm.Children.OrderByDescending(m => (m as ITreeModel<T>)!.OrderNum).ToList();
}
public interface ITreeModel<T>
{
public long Id { get; set; }
public long ParentId { get; set; }
public int OrderNum { get; set; }
public List<T>? Children { get; set; }
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Text;
using System.Text.RegularExpressions;
namespace Yi.Framework.Core.Helper
{
public static class UnicodeHelper
{
/// <summary>
/// 字符串转Unicode码
/// </summary>
/// <returns>The to unicode.</returns>
/// <param name="value">Value.</param>
public static string StringToUnicode(string value)
{
byte[] bytes = Encoding.Unicode.GetBytes(value);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < bytes.Length; i += 2)
{
// 取两个字符,每个字符都是右对齐。
stringBuilder.AppendFormat("u{0}{1}", bytes[i + 1].ToString("x").PadLeft(2, '0'), bytes[i].ToString("x").PadLeft(2, '0'));
}
return stringBuilder.ToString();
}
/// <summary>
/// Unicode转字符串
/// </summary>
/// <returns>The to string.</returns>
/// <param name="unicode">Unicode.</param>
public static string UnicodeToString(string unicode)
{
unicode = unicode.Replace("%", "\\");
return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase | RegexOptions.Compiled).Replace(
unicode, x => string.Empty + Convert.ToChar(Convert.ToUInt16(x.Result("$1"), 16)));
//string resultStr = "";
//string[] strList = unicode.Split('u');
//for (int i = 1; i < strList.Length; i++)
//{
// resultStr += (char)int.Parse(strList[i], System.Globalization.NumberStyles.HexNumber);
//}
//return resultStr;
}
}
}

View File

@@ -0,0 +1,23 @@
namespace Yi.Framework.Core.Helper
{
public class UrlHelper
{
/// <summary>
/// UrlEncode编码
/// </summary>
/// <param name="url">url</param>
/// <returns></returns>
public static string UrlEncode(string url) {
return System.Web.HttpUtility.UrlEncode(url, System.Text.Encoding.UTF8);
}
/// <summary>
/// UrlEncode解码
/// </summary>
/// <param name="data">数据</param>
/// <returns></returns>
public static string UrlDecode(string data)
{
return System.Web.HttpUtility.UrlDecode(data, System.Text.Encoding.UTF8);
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace Yi.Framework.Core.Helper
{
public class XmlHelper
{
/// <summary>
/// 转换对象为JSON格式数据
/// </summary>
/// <typeparam name="T">类</typeparam>
/// <param name="obj">对象</param>
/// <returns>字符格式的JSON数据</returns>
public static string? GetXML<T>(object obj)
{
try
{
XmlSerializer xs = new XmlSerializer(typeof(T));
using (TextWriter tw = new StringWriter())
{
xs.Serialize(tw, obj);
return tw.ToString();
}
}
catch (Exception)
{
return string.Empty;
}
}
/// <summary>
/// Xml格式字符转换为T类型的对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="xml"></param>
/// <returns></returns>
public static T ParseFormByXml<T>(string xml,string rootName="root")
{
XmlSerializer serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(rootName));
StringReader reader = new StringReader(xml);
T res = (T)serializer.Deserialize(reader)!;
reader.Close();
reader.Dispose();
return res;
}
}
}

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