.gitignore
New file @@ -0,0 +1,14 @@ cylsg/.vs/ cylsg/cylsg.Application/bin/ cylsg/cylsg.Application/obj/ cylsg/cylsg.Core/bin/ cylsg/cylsg.Core/obj/ cylsg/cylsg.Model/bin/Debug/net8.0/cylsg.Core.dll cylsg/cylsg.Model/bin/ cylsg/cylsg.Model/obj/ cylsg/cylsg.utility/bin/ cylsg/cylsg.utility/obj/ cylsg/cylsg.Web.Core/bin/ cylsg/cylsg.Web.Core/obj/ cylsg/cylsg.Web.Entry/bin/ cylsg/cylsg.Web.Entry/obj/ cylsg/cylsg.Application/GlobalUsings.cs
New file @@ -0,0 +1,15 @@ global using Furion; global using Furion.DataEncryption; global using Furion.DataValidation; global using Furion.DependencyInjection; global using Furion.DynamicApiController; global using Furion.Extensions; global using Furion.FriendlyException; global using Furion.Logging; global using Mapster; global using Microsoft.AspNetCore.Authorization; global using Microsoft.AspNetCore.Http; global using Microsoft.AspNetCore.Mvc; global using Microsoft.CodeAnalysis; global using System.ComponentModel.DataAnnotations; global using SqlSugar; cylsg/cylsg.Application/System/Dtos/Mapper.cs
New file @@ -0,0 +1,8 @@ namespace cylsg.Application; public class Mapper : IRegister { public void Register(TypeAdapterConfig config) { } } cylsg/cylsg.Application/System/Services/ISystemService.cs
New file @@ -0,0 +1,6 @@ namespace cylsg.Application; public interface ISystemService { string GetDescription(); } cylsg/cylsg.Application/System/Services/SystemService.cs
New file @@ -0,0 +1,9 @@ namespace cylsg.Application; public class SystemService : ISystemService, ITransient { public string GetDescription() { return "让 .NET 开发更简单,更通用,更流行。"; } } cylsg/cylsg.Application/System/SystemAppService.cs
New file @@ -0,0 +1,47 @@ using cylsg.Core.Attributes; using cylsg.Core; namespace cylsg.Application; /// <summary> /// 系统服务接口 /// </summary> public class SystemAppService : IDynamicApiController { private readonly ISystemService _systemService; private ISqlSugarClient _sqlSugarClient; public SystemAppService(ISystemService systemService,ISqlSugarClient sqlSugarClient) { _systemService = systemService; _sqlSugarClient = sqlSugarClient; } /// <summary> /// 创建系统 /// </summary> /// <returns></returns> public string codefirst() { try { //_ez.GetDb().AsTenant().ChangeDatabase(ConfigId); _sqlSugarClient.DbMaintenance.CreateDatabase(); Type[]? types = DbCoreUntil.DbCodeFirstModes("cylsg.Model", thisAttribute: typeof(CoderFirstAttribute)); _sqlSugarClient.CodeFirst.SetStringDefaultLength(512).InitTables(types ?? new Type[] { }); return "创建成功"; } catch (Exception e) { return $"创建失败,报错: {e.Message},-----详情:{e.StackTrace}"; } } } cylsg/cylsg.Application/applicationsettings.json
New file @@ -0,0 +1,31 @@ { "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", "SpecificationDocumentSettings": { "DocumentTitle": "Furion | 规范化接口", "GroupOpenApiInfos": [ { "Group": "Default", "Title": "规范化演示", "Description": "川印灵时工", "Version": "1.0.0", "Contact": { "Name": "", "Email": "monksoul@outlook.com" }, "License": { "Name": "Apache-2.0" } } ] }, "CorsAccessorSettings": { "WithExposedHeaders": [ "access-token", "x-access-token", "environment" ] } } cylsg/cylsg.Application/cylsg.Application.csproj
New file @@ -0,0 +1,33 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <NoWarn>1701;1702;1591</NoWarn> <DocumentationFile>cylsg.Application.xml</DocumentationFile> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <None Remove="applicationsettings.json" /> <None Remove="cylsg.Application.xml" /> </ItemGroup> <ItemGroup> <Content Include="applicationsettings.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup> <ItemGroup> <ProjectReference Include="..\cylsg.Core\cylsg.Core.csproj" /> <ProjectReference Include="..\cylsg.Model\cylsg.Model.csproj" /> </ItemGroup> <ItemGroup> <Folder Include="System\Services\" /> </ItemGroup> </Project> cylsg/cylsg.Application/cylsg.Application.xml
New file @@ -0,0 +1,19 @@ <?xml version="1.0"?> <doc> <assembly> <name>cylsg.Application</name> </assembly> <members> <member name="T:cylsg.Application.SystemAppService"> <summary> 系统服务接口 </summary> </member> <member name="M:cylsg.Application.SystemAppService.codefirst"> <summary> 创建系统 </summary> <returns></returns> </member> </members> </doc> cylsg/cylsg.Core/Attributes/CoderFirstAttribute.cs
New file @@ -0,0 +1,16 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace cylsg.Core.Attributes { /// <summary> /// /标记是否是codefirst /// </summary> [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class CoderFirstAttribute : Attribute { } } cylsg/cylsg.Core/BaseModelBase.cs
New file @@ -0,0 +1,86 @@ using SqlSugar; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace cylsg.Core { /// <summary> /// 最基础的模型,创建时间创建人记录 /// </summary> public class BaseModelBase { /// <summary> /// 创建时间 /// </summary> [Display(Name = "创建时间 ")] [SugarColumn(ColumnDescription = "创建时间 ")] public DateTime? CreateTime { get; set; } /// <summary> /// 创建人 /// </summary> [Display(Name = "创建人 ")] [SugarColumn(ColumnDescription = "创建人 ", Length = 100)] public string CreateBy { get; set; } /// <summary> /// 修改时间 /// </summary> [Display(Name = "修改时间 ")] [SugarColumn(ColumnDescription = "修改时间 ")] public DateTime? UpDataTime { get; set; } /// <summary> /// 修改人 /// </summary> [Display(Name = "修改人 ")] [SugarColumn(ColumnDescription = "修改人 ", Length = 100)] public string UpDataBy { get; set; } } /// <summary> /// 修正基础模型,包括了删除标志,生效标志,排序,和使能 /// </summary> public class BaseModel : BaseModelBase { /// <summary> /// 是否删除 /// </summary> [Display(Name = "是否删除 ")] [SugarColumn(ColumnDescription = "是否删除 ", DefaultValue = "0")] public bool IsDeleted { get; set; } = false; /// <summary> /// 是否有效 /// </summary> [Display(Name = "是否有效 ")] [SugarColumn(ColumnDescription = "是否有效 ", DefaultValue = "1")] public bool IsEn { get; set; } = true; /// <summary> /// 排序 /// </summary> [Display(Name = "排序 ")] [SugarColumn(ColumnDescription = "排序 ", IsNullable = true)] public int? Sort { get; set; } /// <summary> /// 标注 /// </summary> [Display(Name = "标注 ")] [SugarColumn(ColumnDescription = "标注 ", IsNullable = true)] public string Remake { get; set; } /// <summary> /// 租户 /// </summary> [Display(Name = "租户 ")] [SugarColumn(ColumnDescription = "租户 扩展 ", IsNullable = true)] public int? TenantID { get; set; } } } cylsg/cylsg.Core/BaseRepository.cs
New file @@ -0,0 +1,98 @@ using Furion; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text; using System.Threading.Tasks; namespace cylsg.Core { /// <summary> /// 仓储类,使用方式只需要继承就行 /// </summary> /// <typeparam name="T"></typeparam> public class BaseRepository<T> : SimpleClient<T> where T : class, new() { public BaseRepository(ISqlSugarClient context = null) : base(context)//默认值等于null不能少 { base.Context = App.GetService<ISqlSugarClient>();//用手动获取方式支持切换仓储 } /// <summary> /// 重写更新方法 /// </summary> /// <param name="updateObj"></param> /// <returns></returns> public Task<bool> EzUpdateAsync(T updateObj) { var intbs = updateObj as BaseModelBase; if (intbs != null) { intbs.UpDataBy = GetJwtBy(); intbs.UpDataTime = DateTime.Now; } return base.UpdateAsync(updateObj); } /// <summary> /// 异步插入 /// </summary> /// <param name="insertObj"></param> /// <returns></returns> public Task<bool> EzInsertAsync(T insertObj) { var intbs = insertObj as BaseModelBase; if (intbs != null) { intbs.CreateBy = GetJwtBy(); intbs.CreateTime = DateTime.Now; } return base.InsertAsync(insertObj); } /// <summary> /// 重写插入 /// </summary> /// <param name="insertObj"></param> /// <returns></returns> public T EzInsertReturnEntity(T insertObj) { var intbs = insertObj as BaseModelBase; if (intbs != null) { intbs.CreateBy = GetJwtBy(); intbs.CreateTime = DateTime.Now; } return base.InsertReturnEntity(insertObj); } /// <summary> /// 异步插入 /// </summary> /// <param name="insertObj"></param> /// <returns></returns> public Task<int> EzInsertReturnIdentityAsync(T insertObj) { var intbs = insertObj as BaseModelBase; if (intbs != null) { intbs.CreateBy = GetJwtBy(); intbs.CreateTime = DateTime.Now; } return base.InsertReturnIdentityAsync(insertObj); } /// <summary> /// 获取用户姓名和ID /// </summary> /// <returns></returns> private string GetJwtBy() { return (App.User?.FindFirstValue("UserID") ?? "") + "|" + (App.User?.FindFirstValue("NickName") ?? "系统自主处理"); } } } cylsg/cylsg.Core/DbContext.cs
New file @@ -0,0 +1,22 @@ using Furion; using SqlSugar; using System.Collections.Generic; namespace cylsg.Core; /// <summary> /// 数据库上下文对象 /// </summary> public static class DbContext { /// <summary> /// SqlSugar 数据库实例 /// </summary> public static readonly SqlSugarScope Instance = new( // 读取 appsettings.json 中的 ConnectionConfigs 配置节点 App.GetConfig<List<ConnectionConfig>>("ConnectionConfigs") , db => { // 这里配置全局事件,比如拦截执行 SQL }); } cylsg/cylsg.Core/DbCoreUntil.cs
New file @@ -0,0 +1,34 @@ using cylsg.utility; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace cylsg.Core { public class DbCoreUntil { /// 获取需要更新或者是创建的 数据库表模型List /// </summary> /// <typeparam name="T">继承表某个表的所有</typeparam> /// <param name="ModeProjectName"></param> /// <param name="ModeNamespace"></param> /// <param name="ConfigId"></param> /// <returns></returns> public static Type[] DbCodeFirstModes(string ModeProjectName, string ModeNamespace = null, string ConfigId = null, Type subClass = null, Type thisAttribute = null) { #nullable enable Type[]? types = CommonHelper.GetAllAssembly().Where(x => x.FullName.Contains(ModeProjectName + ",")).FirstOrDefault()?.GetTypes().WhereIF(!string.IsNullOrEmpty(ModeNamespace), name => name.FullName.Contains(ModeNamespace + ".")).ToArray() .WhereIF(subClass != null, x => x.IsSubclassOf(subClass)).ToArray() .WhereIF(thisAttribute != null, x => x.GetCustomAttributes(thisAttribute, true).Length > 0).ToArray(); return types; } } } cylsg/cylsg.Core/cylsg.Core.csproj
New file @@ -0,0 +1,27 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <NoWarn>1701;1702;1591</NoWarn> <DocumentationFile>cylsg.Core.xml</DocumentationFile> </PropertyGroup> <ItemGroup> <None Remove="cylsg.Core.xml" /> </ItemGroup> <ItemGroup> <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.5.3" /> <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.5.3" /> <PackageReference Include="Furion.Pure" Version="4.9.5.3" /> <PackageReference Include="SqlSugarCore" Version="5.1.4.166" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\cylsg.utility\cylsg.utility.csproj" /> </ItemGroup> </Project> cylsg/cylsg.Core/cylsg.Core.xml
New file @@ -0,0 +1,119 @@ <?xml version="1.0"?> <doc> <assembly> <name>cylsg.Core</name> </assembly> <members> <member name="T:cylsg.Core.Attributes.CoderFirstAttribute"> <summary> /标记是否是codefirst </summary> </member> <member name="T:cylsg.Core.BaseModelBase"> <summary> 最基础的模型,创建时间创建人记录 </summary> </member> <member name="P:cylsg.Core.BaseModelBase.CreateTime"> <summary> 创建时间 </summary> </member> <member name="P:cylsg.Core.BaseModelBase.CreateBy"> <summary> 创建人 </summary> </member> <member name="P:cylsg.Core.BaseModelBase.UpDataTime"> <summary> 修改时间 </summary> </member> <member name="P:cylsg.Core.BaseModelBase.UpDataBy"> <summary> 修改人 </summary> </member> <member name="T:cylsg.Core.BaseModel"> <summary> 修正基础模型,包括了删除标志,生效标志,排序,和使能 </summary> </member> <member name="P:cylsg.Core.BaseModel.IsDeleted"> <summary> 是否删除 </summary> </member> <member name="P:cylsg.Core.BaseModel.IsEn"> <summary> 是否有效 </summary> </member> <member name="P:cylsg.Core.BaseModel.Sort"> <summary> 排序 </summary> </member> <member name="P:cylsg.Core.BaseModel.Remake"> <summary> 标注 </summary> </member> <member name="P:cylsg.Core.BaseModel.TenantID"> <summary> 租户 </summary> </member> <member name="T:cylsg.Core.BaseRepository`1"> <summary> 仓储类,使用方式只需要继承就行 </summary> <typeparam name="T"></typeparam> </member> <member name="M:cylsg.Core.BaseRepository`1.EzUpdateAsync(`0)"> <summary> 重写更新方法 </summary> <param name="updateObj"></param> <returns></returns> </member> <member name="M:cylsg.Core.BaseRepository`1.EzInsertAsync(`0)"> <summary> 异步插入 </summary> <param name="insertObj"></param> <returns></returns> </member> <member name="M:cylsg.Core.BaseRepository`1.EzInsertReturnEntity(`0)"> <summary> 重写插入 </summary> <param name="insertObj"></param> <returns></returns> </member> <member name="M:cylsg.Core.BaseRepository`1.EzInsertReturnIdentityAsync(`0)"> <summary> 异步插入 </summary> <param name="insertObj"></param> <returns></returns> </member> <member name="M:cylsg.Core.BaseRepository`1.GetJwtBy"> <summary> 获取用户姓名和ID </summary> <returns></returns> </member> <member name="T:cylsg.Core.DbContext"> <summary> 数据库上下文对象 </summary> </member> <member name="F:cylsg.Core.DbContext.Instance"> <summary> SqlSugar 数据库实例 </summary> </member> <!-- Badly formed XML comment ignored for member "M:cylsg.Core.DbCoreUntil.DbCodeFirstModes(System.String,System.String,System.String,System.Type,System.Type)" --> </members> </doc> cylsg/cylsg.Model/UserModel/User.cs
New file @@ -0,0 +1,62 @@ using cylsg.Core; using cylsg.Core.Attributes; using SqlSugar; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace cylsg.Model.UserModel { /// <summary> /// 用户模型 /// </summary> [Description("用户模型")] [CoderFirst] public class User:BaseModelBase { /// <summary> /// 用户Id /// </summary> [SugarColumn(ColumnDescription = "用户ID", IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } /// <summary> /// 电话 /// </summary> [SugarColumn(ColumnDescription = "电话")] public string Phone { get; set; } /// <summary> /// 名称 /// </summary> [SugarColumn(ColumnDescription = "名称",Length =100)] public string name { get; set; } /// <summary> /// 电话号码 /// </summary> [SugarColumn(ColumnDescription = "电话号码", Length = 30)] public string ItCode { get; set; } /// <summary> /// 昵称 /// </summary> [SugarColumn(ColumnDescription = "用户ID", Length = 100)] public int Nickname { get; set; } /// <summary> /// 密码 /// </summary> [SugarColumn(ColumnDescription = "密码", Length = 100)] public int PassWord { get; set; } /// <summary> /// 头像地址 /// </summary> [SugarColumn(ColumnDescription = "头像地址")] public int Avatar { get; set; } } } cylsg/cylsg.Model/cylsg.Model.csproj
New file @@ -0,0 +1,14 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <GenerateDocumentationFile>True</GenerateDocumentationFile> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\cylsg.Core\cylsg.Core.csproj" /> </ItemGroup> </Project> cylsg/cylsg.Web.Core/Handlers/JwtHandler.cs
New file @@ -0,0 +1,16 @@ using Furion.Authorization; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using System.Threading.Tasks; namespace cylsg.Web.Core; public class JwtHandler : AppAuthorizeHandler { public override Task<bool> PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext) { // 这里写您的授权判断逻辑,授权通过返回 true,否则返回 false return Task.FromResult(true); } } cylsg/cylsg.Web.Core/Startup.cs
New file @@ -0,0 +1,62 @@ using cylsg.Core; using Furion; using Furion.VirtualFileServer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using SqlSugar; namespace cylsg.Web.Core; public class Startup : AppStartup { public void ConfigureServices(IServiceCollection services) { services.AddConsoleFormatter(); services.AddJwt<JwtHandler>(); services.AddCorsAccessor(); services.AddSingleton<ISqlSugarClient>(s => { return DbContext.Instance; } ); services.AddControllersWithViews() .AddInjectWithUnifyResult(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseCorsAccessor(); app.UseAuthentication(); app.UseAuthorization(); app.UseInject(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } cylsg/cylsg.Web.Core/cylsg.Web.Core.csproj
New file @@ -0,0 +1,20 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <NoWarn>1701;1702;1591</NoWarn> <DocumentationFile>cylsg.Web.Core.xml</DocumentationFile> </PropertyGroup> <ItemGroup> <None Remove="cylsg.Web.Core.xml" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\cylsg.Application\cylsg.Application.csproj" /> </ItemGroup> </Project> cylsg/cylsg.Web.Core/cylsg.Web.Core.xml
New file @@ -0,0 +1,8 @@ <?xml version="1.0"?> <doc> <assembly> <name>cylsg.Web.Core</name> </assembly> <members> </members> </doc> cylsg/cylsg.Web.Entry/Controllers/HomeController.cs
New file @@ -0,0 +1,23 @@ using cylsg.Application; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace cylsg.Web.Entry.Controllers; [AllowAnonymous] public class HomeController : Controller { private readonly ISystemService _systemService; public HomeController(ISystemService systemService) { _systemService = systemService; } public IActionResult Index() { ViewBag.Description = _systemService.GetDescription(); return View(); } } cylsg/cylsg.Web.Entry/Program.cs
New file @@ -0,0 +1 @@ Serve.Run(RunOptions.Default.WithArgs(args)); cylsg/cylsg.Web.Entry/Properties/launchSettings.json
New file @@ -0,0 +1,28 @@ { "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:58595", "sslPort": 44326 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "cylsg.Web.Entry": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } cylsg/cylsg.Web.Entry/SingleFilePublish.cs
New file @@ -0,0 +1,22 @@ using Furion; using System.Reflection; namespace cylsg.Web.Entry; public class SingleFilePublish : ISingleFilePublish { public Assembly[] IncludeAssemblies() { return Array.Empty<Assembly>(); } public string[] IncludeAssemblyNames() { return new[] { "cylsg.Application", "cylsg.Core", "cylsg.Web.Core" }; } } cylsg/cylsg.Web.Entry/Views/Home/Index.cshtml
New file @@ -0,0 +1,9 @@ @{ ViewData["Title"] = ViewBag.Description; } <div style="text-align:center;margin-top:50px;"> <p>@ViewBag.Description</p> <p><a href="/api">API 接口</a> </div> cylsg/cylsg.Web.Entry/Views/Shared/_Layout.cshtml
New file @@ -0,0 +1,11 @@ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewData["Title"] - Furion</title> </head> <body> @RenderBody() </body> </html> cylsg/cylsg.Web.Entry/Views/_ViewImports.cshtml
New file @@ -0,0 +1,2 @@ @using cylsg.Web.Entry @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers cylsg/cylsg.Web.Entry/Views/_ViewStart.cshtml
New file @@ -0,0 +1,3 @@ @{ Layout = "_Layout"; } cylsg/cylsg.Web.Entry/appsettings.Development.json
New file @@ -0,0 +1,10 @@ { "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "Microsoft.EntityFrameworkCore": "Information" } } } cylsg/cylsg.Web.Entry/appsettings.json
New file @@ -0,0 +1,23 @@ { "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "Microsoft.EntityFrameworkCore": "Information" } }, "AllowedHosts": "*", "ConnectionConfigs": [ { //"ConnectionString": "Data Source=./Furion.db", //"DbType": "Sqlite", //"IsAutoCloseConnection": true "ConnectionString": "Server=MS-FSEUTNLCXFDB\\SQLEXPRESS;Database=CyLsgDb; MultipleActiveResultSets=true;pooling=true;min pool size=5;max pool size=32767;connect timeout=20;Encrypt=True;TrustServerCertificate=True;integrated security=True;", "DbType": "SqlServer", // "SqlServer" ,mysql, "IsAutoCloseConnection": true } ] } cylsg/cylsg.Web.Entry/cylsg.Web.Entry.csproj
New file @@ -0,0 +1,17 @@ <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <SatelliteResourceLanguages>en-US</SatelliteResourceLanguages> <PublishReadyToRunComposite>true</PublishReadyToRunComposite> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\cylsg.Web.Core\cylsg.Web.Core.csproj" /> </ItemGroup> </Project> cylsg/cylsg.Web.Entry/cylsg.Web.Entry.csproj.user
New file @@ -0,0 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <DebuggerFlavor>ProjectDebugger</DebuggerFlavor> </PropertyGroup> <PropertyGroup> <ActiveDebugProfile>cylsg.Web.Entry</ActiveDebugProfile> </PropertyGroup> </Project> cylsg/cylsg.Web.Entry/wwwroot/images/logo.png
cylsg/cylsg.sln
New file @@ -0,0 +1,55 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32519.111 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cylsg.Application", "cylsg.Application\cylsg.Application.csproj", "{AB699EE9-43A8-46F2-A855-04A26DE63372}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cylsg.Web.Core", "cylsg.Web.Core\cylsg.Web.Core.csproj", "{9D14BB78-DA2A-4040-B9DB-5A515B599181}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cylsg.Core", "cylsg.Core\cylsg.Core.csproj", "{4FB30091-15C7-4FD9-AB7D-266814F360F5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cylsg.Web.Entry", "cylsg.Web.Entry\cylsg.Web.Entry.csproj", "{9826E365-EEE9-4721-A738-B02AB64D47E5}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cylsg.Model", "cylsg.Model\cylsg.Model.csproj", "{09E3AFC0-0975-4842-891F-9B5C78E12458}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cylsg.utility", "cylsg.utility\cylsg.utility.csproj", "{5ED2C481-2D74-43BC-ABAF-1455A052FAA4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {AB699EE9-43A8-46F2-A855-04A26DE63372}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AB699EE9-43A8-46F2-A855-04A26DE63372}.Debug|Any CPU.Build.0 = Debug|Any CPU {AB699EE9-43A8-46F2-A855-04A26DE63372}.Release|Any CPU.ActiveCfg = Release|Any CPU {AB699EE9-43A8-46F2-A855-04A26DE63372}.Release|Any CPU.Build.0 = Release|Any CPU {9D14BB78-DA2A-4040-B9DB-5A515B599181}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D14BB78-DA2A-4040-B9DB-5A515B599181}.Debug|Any CPU.Build.0 = Debug|Any CPU {9D14BB78-DA2A-4040-B9DB-5A515B599181}.Release|Any CPU.ActiveCfg = Release|Any CPU {9D14BB78-DA2A-4040-B9DB-5A515B599181}.Release|Any CPU.Build.0 = Release|Any CPU {4FB30091-15C7-4FD9-AB7D-266814F360F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4FB30091-15C7-4FD9-AB7D-266814F360F5}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FB30091-15C7-4FD9-AB7D-266814F360F5}.Release|Any CPU.ActiveCfg = Release|Any CPU {4FB30091-15C7-4FD9-AB7D-266814F360F5}.Release|Any CPU.Build.0 = Release|Any CPU {9826E365-EEE9-4721-A738-B02AB64D47E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9826E365-EEE9-4721-A738-B02AB64D47E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {9826E365-EEE9-4721-A738-B02AB64D47E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {9826E365-EEE9-4721-A738-B02AB64D47E5}.Release|Any CPU.Build.0 = Release|Any CPU {09E3AFC0-0975-4842-891F-9B5C78E12458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {09E3AFC0-0975-4842-891F-9B5C78E12458}.Debug|Any CPU.Build.0 = Debug|Any CPU {09E3AFC0-0975-4842-891F-9B5C78E12458}.Release|Any CPU.ActiveCfg = Release|Any CPU {09E3AFC0-0975-4842-891F-9B5C78E12458}.Release|Any CPU.Build.0 = Release|Any CPU {5ED2C481-2D74-43BC-ABAF-1455A052FAA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5ED2C481-2D74-43BC-ABAF-1455A052FAA4}.Debug|Any CPU.Build.0 = Debug|Any CPU {5ED2C481-2D74-43BC-ABAF-1455A052FAA4}.Release|Any CPU.ActiveCfg = Release|Any CPU {5ED2C481-2D74-43BC-ABAF-1455A052FAA4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B2073C2C-0FD3-452B-8047-8134D68E12CE} EndGlobalSection EndGlobal cylsg/cylsg.utility/CommonHelper.cs
New file @@ -0,0 +1,850 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.Loader; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace cylsg.utility { /// <summary> /// 通用帮助类 /// </summary> public static class CommonHelper { #region 判断字符串是否为手机号码 /// <summary> /// 判断字符串是否为手机号码 /// </summary> /// <param name="mobilePhoneNumber"></param> /// <returns></returns> public static bool IsMobile(string mobilePhoneNumber) { if (mobilePhoneNumber.Length < 11) { return false; } //电信手机号码正则 string dianxin = @"^1[345789][01379]\d{8}$"; Regex regexDx = new Regex(dianxin); //联通手机号码正则 string liantong = @"^1[345678][01256]\d{8}$"; Regex regexLt = new Regex(liantong); //移动手机号码正则 string yidong = @"^1[345789][0123456789]\d{8}$"; Regex regexYd = new Regex(yidong); if (regexDx.IsMatch(mobilePhoneNumber) || regexLt.IsMatch(mobilePhoneNumber) || regexYd.IsMatch(mobilePhoneNumber)) { return true; } else { return false; } } #endregion #region 检测是否符合email格式 /// <summary> /// 检测是否符合email格式 /// </summary> /// <param name="strEmail">要判断的email字符串</param> /// <returns>判断结果</returns> public static bool IsValidEmail(string strEmail) { return Regex.IsMatch(strEmail, @"^[\w\.]+([-]\w+)*@[A-Za-z0-9-_]+[\.][A-Za-z0-9-_]"); } public static bool IsValidDoEmail(string strEmail) { return Regex.IsMatch(strEmail, @"^@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"); } #endregion #region 检测是否是正确的Url /// <summary> /// 检测是否是正确的Url /// </summary> /// <param name="strUrl">要验证的Url</param> /// <returns>判断结果</returns> public static bool IsUrl(string strUrl) { return Regex.IsMatch(strUrl, @"^(http|https)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{1,10}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$"); } #endregion #region string 转int数组 public static int[] StringToIntArray(string str) { try { if (string.IsNullOrEmpty(str)) return new int[0]; if (str.EndsWith(",")) { str = str.Remove(str.Length - 1, 1); } var idstrarr = str.Split(','); var idintarr = new int[idstrarr.Length]; for (int i = 0; i < idstrarr.Length; i++) { idintarr[i] = Convert.ToInt32(idstrarr[i]); } return idintarr; } catch { return new int[0]; } } #endregion #region String转数组 public static string[] StringToStringArray(string str) { try { if (string.IsNullOrEmpty(str)) return new string[0]; if (str.EndsWith(",")) str = str.Remove(str.Length - 1, 1); return str.Split(','); } catch { return new string[0]; } } #endregion #region String数组转Int数组 public static int[] StringArrAyToIntArray(string[] str) { try { int[] iNums = Array.ConvertAll(str, s => int.Parse(s)); return iNums; } catch { return new int[0]; } } #endregion #region string转Guid数组 public static Guid[] StringToGuidArray(string str) { try { if (string.IsNullOrEmpty(str)) return new Guid[0]; if (str.EndsWith(",")) str = str.Remove(str.Length - 1, 1); var strarr = str.Split(','); Guid[] guids = new Guid[strarr.Length]; for (int index = 0; index < strarr.Length; index++) { guids[index] = Guid.Parse(strarr[index]); } return guids; } catch { return new Guid[0]; } } #endregion #region 转MD5 /// <summary> /// 转MD5 /// </summary> /// <param name="str"></param> /// <returns></returns> public static string ToMd5(string str) { MD5 md5 = MD5.Create(); // 将字符串转换成字节数组 byte[] byteOld = Encoding.UTF8.GetBytes(str); // 调用加密方法 byte[] byteNew = md5.ComputeHash(byteOld); // 将加密结果转换为字符串 StringBuilder sb = new StringBuilder(); foreach (byte b in byteNew) { // 将字节转换成16进制表示的字符串, sb.Append(b.ToString("x2")); } // 返回加密的字符串 return sb.ToString(); } #endregion #region 获取32位md5加密 /// <summary> /// 通过创建哈希字符串适用于任何 MD5 哈希函数 (在任何平台) 上创建 32 个字符的十六进制格式哈希字符串 /// </summary> /// <param name="source"></param> /// <returns>32位md5加密字符串</returns> public static string Md5For32(string source) { using (MD5 md5Hash = MD5.Create()) { byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(source)); StringBuilder sBuilder = new StringBuilder(); for (int i = 0; i < data.Length; i++) { sBuilder.Append(data[i].ToString("x2")); } string hash = sBuilder.ToString(); return hash.ToUpper(); } } #endregion #region 获取16位md5加密 /// <summary> /// 获取16位md5加密 /// </summary> /// <param name="source"></param> /// <returns>16位md5加密字符串</returns> public static string Md5For16(string source) { using (MD5 md5Hash = MD5.Create()) { byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(source)); //转换成字符串,并取9到25位 string sBuilder = BitConverter.ToString(data, 4, 8); //BitConverter转换出来的字符串会在每个字符中间产生一个分隔符,需要去除掉 sBuilder = sBuilder.Replace("-", ""); return sBuilder.ToUpper(); } } #endregion #region 返回当前的毫秒时间戳 /// <summary> /// 返回当前的毫秒时间戳 /// </summary> public static string Msectime() { long timeTicks = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000; return timeTicks.ToString(); } #endregion #region 剩余多久时间文字描述 /// <summary> /// 剩余多久时间 /// </summary> /// <param name="remainingTime"></param> /// <returns>文字描述</returns> public static string GetRemainingTime(DateTime remainingTime) { TimeSpan timeSpan = remainingTime - DateTime.Now; var day = timeSpan.Days; var hours = timeSpan.Hours; var minute = timeSpan.Minutes; var seconds = timeSpan.Seconds; if (day > 0) { return day + "天" + hours + "小时" + minute + "分" + seconds + "秒"; } else { if (hours > 0) { return hours + "小时" + minute + "分" + seconds + "秒"; } else { return minute + "分" + seconds + "秒"; } } } #endregion #region 剩余多久时间返回时间类型 /// <summary> /// 剩余多久时间 /// </summary> /// <param name="remainingTime"></param> /// <returns>返回时间类型</returns> public static void GetBackTime(DateTime remainingTime, out int day, out int hours, out int minute, out int seconds) { TimeSpan timeSpan = remainingTime - DateTime.Now; day = timeSpan.Days; hours = timeSpan.Hours; minute = timeSpan.Minutes; seconds = timeSpan.Seconds; } #endregion #region 计算时间戳剩余多久时间 /// <summary> /// 计算时间戳剩余多久时间 /// </summary> /// <param name="postTime">提交时间(要是以前的时间)</param> /// <returns></returns> public static string TimeAgo(DateTime postTime) { //当前时间的时间戳 var nowtimes = ConvertTicks(DateTime.Now); //提交的时间戳 var posttimes = ConvertTicks(postTime); //相差时间戳 var counttime = nowtimes - posttimes; //进行时间转换 if (counttime <= 60) { return "刚刚"; } else if (counttime > 60 && counttime <= 120) { return "1分钟前"; } else if (counttime > 120 && counttime <= 180) { return "2分钟前"; } else if (counttime > 180 && counttime < 3600) { return Convert.ToInt32(counttime / 60) + "分钟前"; } else if (counttime >= 3600 && counttime < 3600 * 24) { return Convert.ToInt32(counttime / 3600) + "小时前"; } else if (counttime >= 3600 * 24 && counttime < 3600 * 24 * 2) { return "昨天"; } else if (counttime >= 3600 * 24 * 2 && counttime < 3600 * 24 * 3) { return "前天"; } else if (counttime >= 3600 * 24 * 3 && counttime <= 3600 * 24 * 7) { return Convert.ToInt32(counttime / (3600 * 24)) + "天前"; } else if (counttime >= 3600 * 24 * 7 && counttime <= 3600 * 24 * 30) { return Convert.ToInt32(counttime / (3600 * 24 * 7)) + "周前"; } else if (counttime >= 3600 * 24 * 30 && counttime <= 3600 * 24 * 365) { return Convert.ToInt32(counttime / (3600 * 24 * 30)) + "个月前"; } else if (counttime >= 3600 * 24 * 365) { return Convert.ToInt32(counttime / (3600 * 24 * 365)) + "年前"; } else { return ""; } } /// <summary> /// 时间转换为秒的时间戳 /// </summary> /// <param name="time"></param> /// <returns></returns> private static long ConvertTicks(DateTime time) { long currentTicks = time.Ticks; DateTime dtFrom = new DateTime(1970, 1, 1, 0, 0, 0, 0); long currentMillis = (currentTicks - dtFrom.Ticks) / 10000000; //转换为秒为Ticks/10000000,转换为毫秒Ticks/10000 return currentMillis; } #endregion #region 清除HTML中指定样式 /// <summary> /// 清除HTML中指定样式 /// </summary> /// <param name="content"></param> /// <param name="rule"></param> /// <returns></returns> public static string ClearHtml(string content, string[] rule) { if (!rule.Any()) { return content; } foreach (var item in rule) { content = Regex.Replace(content, "/" + item + @"\s*=\s*\d+\s*/i", ""); content = Regex.Replace(content, "/" + item + @"\s*=\s*.+?[""]/i", ""); content = Regex.Replace(content, "/" + item + @"\s*:\s*\d+\s*px\s*;?/i", ""); } return content; } #endregion #region list随机排序方法 /// <summary> /// list随机排序方法 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ListT"></param> /// <returns></returns> public static List<T> RandomSortList<T>(List<T> ListT) { Random random = new Random(); List<T> newList = new List<T>(); foreach (T item in ListT) { newList.Insert(random.Next(newList.Count + 1), item); } return newList; } #endregion #region 截前后字符(串) ///<summary> /// 截前后字符(串) ///</summary> ///<param name="val">原字符串</param> ///<param name="str">要截掉的字符串</param> ///<param name="all">是否贪婪</param> ///<returns></returns> public static string GetCaptureInterceptedText(string val, string str, bool all = false) { return Regex.Replace(val, @"(^(" + str + ")" + (all ? "*" : "") + "|(" + str + ")" + (all ? "*" : "") + "$)", ""); } #endregion #region 密码加密方法 /// <summary> /// 密码加密方法 /// </summary> /// <param name="password">要加密的字符串</param> /// <param name="createTime">时间组合</param> /// <returns></returns> public static string EnPassword(string password, DateTime createTime) { var dtStr = createTime.ToString("yyyyMMddHHmmss"); var md5 = Md5For32(password); var enPwd = Md5For32(md5 + dtStr); return enPwd; } #endregion #region 获取现在是星期几 /// <summary> /// 获取现在是星期几 /// </summary> /// <returns></returns> public static string GetWeek() { string week = string.Empty; switch (DateTime.Now.DayOfWeek) { case DayOfWeek.Monday: week = "周一"; break; case DayOfWeek.Tuesday: week = "周二"; break; case DayOfWeek.Wednesday: week = "周三"; break; case DayOfWeek.Thursday: week = "周四"; break; case DayOfWeek.Friday: week = "周五"; break; case DayOfWeek.Saturday: week = "周六"; break; case DayOfWeek.Sunday: week = "周日"; break; default: week = "N/A"; break; } return week; } #endregion #region UrlEncode (URL编码) /// <summary> /// UrlEncode (URL编码) /// </summary> /// <param name="str"></param> /// <returns></returns> public static string UrlEncode(string str) { StringBuilder sb = new StringBuilder(); byte[] byStr = Encoding.UTF8.GetBytes(str); //默认是System.Text.Encoding.Default.GetBytes(str) for (int i = 0; i < byStr.Length; i++) { sb.Append(@"%" + Convert.ToString(byStr[i], 16)); } return sb.ToString(); } #endregion #region 获取10位时间戳 /// <summary> /// 获取10位时间戳 /// </summary> /// <returns></returns> public static long GetTimeStampByTotalSeconds() { TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds); } #endregion #region 获取13位时间戳 /// <summary> /// 获取13位时间戳 /// </summary> /// <returns></returns> public static long GetTimeStampByTotalMilliseconds() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalMilliseconds); } /// <summary> /// 获取时间戳 /// </summary> /// <param name="dt"></param> /// <returns></returns> public static int GetDateTimeStamp(DateTime dt) { DateTime dateStart = new DateTime(1970, 1, 1, 0, 0, 0); int timeStamp = Convert.ToInt32((dt.ToUniversalTime() - dateStart).TotalSeconds); return timeStamp; } #endregion #region 获取随机字符串 /// <summary> /// 获取随机字符串 /// </summary> /// <returns></returns> public static string GetSerialNumber() { var str = string.Empty; Random rand = new Random(); var charsStr2 = new[] { 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'P', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }; var charsLen2 = charsStr2.Length - 1; // shuffle($chars); str = ""; for (int i = 0; i < 16; i++) { str += charsStr2[rand.Next(0, charsLen2)]; } return str; } #endregion #region Sha1签名 /// <summary> /// Sha1签名 /// </summary> /// <param name="str">内容</param> /// <param name="encoding">编码</param> /// <returns></returns> public static string Sha1Signature(string str, Encoding encoding = null) { if (encoding == null) encoding = Encoding.UTF8; var buffer = encoding.GetBytes(str); var data = SHA1.Create().ComputeHash(buffer); StringBuilder sub = new StringBuilder(); foreach (var t in data) { sub.Append(t.ToString("x2")); } return sub.ToString(); } #endregion /// <summary> /// 精确计算base64字符串文件大小(单位:B) /// param base64String /// return double 字节大小 /// </summary> /// <param name="base64String"></param> /// <returns></returns> public static double Base64FileSize(string base64String) { //检测是否含有base64,文件头) if (base64String.LastIndexOf(",", StringComparison.Ordinal) > -1) { base64String = base64String[(base64String.LastIndexOf(",", StringComparison.Ordinal) + 1)..]; } //获取base64字符串长度(不含data:audio/wav;base64,文件头) var size0 = base64String.Length; if (size0 <= 10) return size0 - (double)size0 / 8 * 2; //获取字符串的尾巴的最后10个字符,用于判断尾巴是否有等号,正常生成的base64文件'等号'不会超过4个 var tail = base64String[(size0 - 10)..]; //找到等号,把等号也去掉,(等号其实是空的意思,不能算在文件大小里面) int equalIndex = tail.IndexOf("=", StringComparison.Ordinal); if (equalIndex > 0) { size0 = size0 - (10 - equalIndex); } //计算后得到的文件流大小,单位为字节 return size0 - (double)size0 / 8 * 2; } /// <summary> /// 判断文件大小 /// </summary> /// <param name="base64"></param> /// <param name="size"></param> /// <param name="unit"></param> /// <returns></returns> public static bool CheckBase64Size(string base64, int size, string unit = "M") { // 上传文件的大小, 单位为字节. var len = Base64FileSize(base64); // 准备接收换算后文件大小的容器 double fileSize = unit.ToUpperInvariant() switch { "B" => len, "K" => (double)len / 1024, "M" => (double)len / 1048576, "G" => (double)len / 1073741824, _ => 0 }; // 如果上传文件大于限定的容量 return !(fileSize > size); } /// <summary> /// 10位时间戳 转化 /// </summary> /// <param name="time"></param> /// <returns></returns> public static long ConvertDateTimeToInt(DateTime time) { DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0, 0)); long t = (time.Ticks - startTime.Ticks) / 10000000; //除10000000调整为10位 return t; } #region 反射相关 private static List<Assembly>? _allAssemblies = null; /// <summary> /// 获取所有程序目录下和常用的程序集 包括一些系统引用程序集 /// </summary> /// <returns> 当前工程下的程序集</returns> public static List<Assembly> GetAllAssembly() { if (_allAssemblies == null) { _allAssemblies = new List<Assembly>(); string? path = null; string singlefile = null; try { path = Assembly.GetEntryAssembly()?.Location; } catch { } if (string.IsNullOrEmpty(path)) { singlefile = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; path = Path.GetDirectoryName(singlefile); } if (string.IsNullOrEmpty(path)) throw new Exception("获取程序目录出错"); var dir = new DirectoryInfo(Path.GetDirectoryName(path) ?? ""); var dlls = dir.GetFiles("*.dll", SearchOption.TopDirectoryOnly); string[] systemdll = new string[] { "Microsoft.", "System.", "Swashbuckle.", "ICSharpCode", "Newtonsoft.", "Oracle.", "Pomelo.", "SQLitePCLRaw.", "Aliyun.OSS", "BouncyCastle.", "FreeSql.", "Google.Protobuf.dll", "Humanizer.dll", "IdleBus.dll", "K4os.", "MySql.Data.", "Npgsql.", "NPOI.", "netstandard", "MySqlConnector", "VueCliMiddleware" }; var filtered = dlls.Where(x => systemdll.Any(y => x.Name.StartsWith(y)) == false); foreach (var dll in filtered) { try { AssemblyLoadContext.Default.LoadFromAssemblyPath(dll.FullName); } catch { } } var dlllist = AssemblyLoadContext.Default.Assemblies.Where(x => systemdll.Any(y => x.FullName.StartsWith(y)) == false).ToList(); _allAssemblies.AddRange(dlllist); } return _allAssemblies; } #endregion #region 枚举获取所有项 /// <summary> /// 获取枚举的所有项 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static List<MenmItem> GetEnumItemsWithAttributes<T>() where T : Enum { var result = new List<MenmItem>(); foreach (var value in Enum.GetValues(typeof(T))) { var member = typeof(T).GetMember(value.ToString())[0]; var descriptionAttribute = member.GetCustomAttribute<DescriptionAttribute>(); var item = new MenmItem { Key = value.ToString(), Value = (int)value, // 或者直接使用 value.ToString() 如果不需要转换为整数字符串 Description = descriptionAttribute?.Description ?? string.Empty }; result.Add(item); } return result; } /// <summary> /// 获取枚举所有的项,返回名称 值 和Description 描述 /// </summary> /// <param name="enumType"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> public static List<MenmItem> EnumerateWithDescriptions(Type enumType) { if (!enumType.IsEnum) { throw new ArgumentException(" 这不是枚举"); } var result = new List<MenmItem>(); foreach (var value in Enum.GetValues(enumType)) { var member = enumType.GetMember(value.ToString())[0]; var descriptionAttribute = member.GetCustomAttribute<DescriptionAttribute>(); var item = new MenmItem { Key = value.ToString(), Value = (int)value, // 或者直接使用 value.ToString() 如果不需要转换为整数字符串 Description = descriptionAttribute?.Description ?? string.Empty }; result.Add(item); } return result; } /// <summary> /// 是否是系统类型 /// </summary> /// <param name="type"></param> /// <returns></returns> public static bool IsCustomType(Type type) { // 定义一个或多个基础命名空间列表,这些命名空间下的类型通常认为是系统类型 string[] frameworkNamespaces = { "System", "Microsoft", "mscorlib", "netstandard", "System.Private.CoreLib" }; // 获取类型所在的命名空间 string typeNameSpace = type.Namespace; // 检查该命名空间是否在基础命名空间列表中,如果不在,则认为是自定义类型 return frameworkNamespaces.Any(n => typeNameSpace.StartsWith(n, StringComparison.OrdinalIgnoreCase)); } #endregion } /// <summary> /// 枚举项属性 /// </summary> [Description("枚举项属性")] public class MenmItem { /// <summary> /// 枚举key /// </summary> [Description("枚举key")] public string? Key { get; set; } /// <summary> /// 枚举值 /// </summary> [Description("枚举值")] public int Value { get; set; } /// <summary> /// 枚举描述 /// </summary> [Description("枚举项属性")] public string? Description { get; set; } } } cylsg/cylsg.utility/Extend/EmunEx.cs
New file @@ -0,0 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace cylsg.utility.Extend { /// <summary> /// 枚举扩展 /// </summary> public static class EmunEx { } } cylsg/cylsg.utility/Extend/StringEx.cs
New file @@ -0,0 +1,236 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace cylsg.utility.Extend { /// <summary> /// 字符串扩展 /// </summary> public static class StringEx { /// <summary> /// 首字母小写 /// </summary> /// <param name="self"></param> /// <returns></returns> public static string FirstToLower(this string self) { string str1 = self?.Substring(0, 1).ToLower() ?? ""; string str2 = self?.Substring(1) ?? ""; //首字母转小写 return str1 + str2; } /// <summary> /// 带有xxx.xxx结束的的所有字符串 的后面xxx.xxx /// </summary> /// <param name="strtypr"></param> /// <returns></returns> public static string GetFileName(this string strtypr) { return Path.GetFileName(strtypr); } /// <summary> /// 是否是数字序列 /// </summary> /// <param name="str"></param> /// <returns></returns> public static bool isPureNum(this string strtypr) { if (strtypr.Length == 0 || strtypr == null)//验证这个字符串是否为空 { return false; } byte[] strBytes = Encoding.ASCII.GetBytes(strtypr);//获取字符串的byte类型的字符数组,编码方式ASCII foreach (byte strByte in strBytes) { if (strByte < 48 || strByte > 57) //判断每个字符是否为数字,根据每个字符的ASCII值所在范围判断 { return false; //不是,就返回false } } return true; //是,就返回true } /// <summary> /// 是否是数字序列 /// </summary> /// <param name="str"></param> /// <returns></returns> public static bool isGuid(this string strtypr) { if (strtypr.Length < 20 || strtypr == null)//验证这个字符串是否为空 { return false; } try { new Guid(strtypr); return true; } catch (Exception) { return false; } } /// <summary> /// 字符串 /// </summary> /// <param name="strtypr"></param> /// <returns></returns> /// <exception cref="Exception"></exception> public static int toInt(this string strtypr) { if (!strtypr.isPureNum()) throw new Exception("并非完整的数字序列"); return int.Parse(strtypr); } /// <summary> /// 移除第一个字符串为指定字符串的 如 “axtXXXXX" 如果以"axt"开头的字符串,就移除"axt" 没有则不变 /// </summary> /// <param name="strtypr"></param> /// <param name="str">开始字符</param> /// <returns></returns> public static string RemoveStartWithStr(this string strtypr, string str) { string strret = strtypr; if (strtypr.StartsWith(str)) { strret = strtypr.Remove(0, str.Length); } return strret; } /// <summary> /// 对字符串进行隐私处理,比如中间的用*显示 /// </summary> /// <param name="strtypr"></param> /// <returns></returns> public static string PrivacyStr(this string strtypr) { // 如果是手机号码,仅保留前3位和后4位,中间用星号替换 if (Regex.IsMatch(strtypr, @"^1[3-9]\d{9}$")) { return $"{strtypr.Substring(0, 3)}****{strtypr.Substring(7)}"; } // 对于中文名字或者非手机号格式,仅保留首尾各1个字符,中间用星号替换 else { if (strtypr.Length <= 2) return $"{strtypr.Substring(0, 1)}*"; // 长度小于等于2时,返回固定的星号 var masked = $"{strtypr.Substring(0, 1)}*{strtypr.Substring(strtypr.Length - 1, 1)}"; return masked; } } #region 时间区间字符串转其实和结束时间 /// <summary> /// 解析时间区间字符串 /// </summary> /// <param name="input"></param> /// <returns></returns> public static (DateTime? StartDate, DateTime? EndDate) TryParseDateRangString(this string input) { DateTime startDate, endDate; var culture = CultureInfo.InvariantCulture; // 尝试解析第一种格式 "2023-01-012023-01-31" if (DateTime.TryParseExact(input.Substring(0, 10), "yyyy-MM-dd", culture, DateTimeStyles.None, out startDate) && DateTime.TryParseExact(input.Substring(10), "yyyy-MM-dd", culture, DateTimeStyles.None, out endDate)) { return (startDate, endDate); } // 尝试解析第二种格式 "2023-01-01 08:02:032023-01-31 08:02:03" if (DateTime.TryParseExact(input.Substring(0, 19), "yyyy-MM-dd HH:mm:ss", culture, DateTimeStyles.None, out startDate) && DateTime.TryParseExact(input.Substring(19), "yyyy-MM-dd HH:mm:ss", culture, DateTimeStyles.None, out endDate)) { return (startDate, endDate); } // 尝试解析第二种格式 "2023-01-01T08:02:032023-01-31T08:02:03" if (DateTime.TryParseExact(input.Substring(0, 19), "yyyy-MM-ddTHH:mm:ss", culture, DateTimeStyles.None, out startDate) && DateTime.TryParseExact(input.Substring(19), "yyyy-MM-ddTHH:mm:ss", culture, DateTimeStyles.None, out endDate)) { return (startDate, endDate); } // 如果都不是,返回null return (null, null); } /// <summary> /// 移除最后一个字符的?号 /// </summary> /// <param name="input"> </param> /// /// <param name="inChar">字符</param> /// <returns></returns> public static string RemoveCharIfPresent(this string input, char inChar) { if (string.IsNullOrEmpty(input)) return input; // 检查字符串的最后一个字符是否为问号 if (input[^1] == '?') { // 使用切片操作符创建不包含问号的新字符串 return input[..^1]; } else { // 字符串不以问号结尾,返回原字符串 return input; } } /// <summary> /// 移除最后的字符串 /// </summary> /// <param name="input"></param> /// <param name="endString"></param> /// <returns></returns> public static string RemoveEndStringIfExists(this string input, string endString) { if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(endString)) { return input; // 如果输入字符串或结束字符串为空或null,直接返回原字符串 } if (input.EndsWith(endString)) { return input.Substring(0, input.Length - endString.Length); // 移除结束字符串 } return input; // 如果不以指定字符串结束,返回原字符串 } /// <summary> /// 首字母转小写 /// </summary> /// <param name="input"></param> /// <returns></returns> public static string FirstCharToLower(this string input) { if (string.IsNullOrEmpty(input)) { return input; } // 使用正则表达式 return Regex.Replace(input, @"^\p{Lu}", match => match.Value.ToLower()); } #endregion } } cylsg/cylsg.utility/Extend/TypeAndExpressionEx.cs
New file @@ -0,0 +1,1021 @@ using System; using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel.DataAnnotations; using System.ComponentModel; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using cylsg.utility.Extend; using Microsoft.Extensions.Primitives; namespace cylsg.utility.Extend { /// <summary> /// 反射扩展函数 /// </summary> public static class TypeAndExpressionEx { #region 属性扩展 反射 public static Func<object, object> GetPropertyExpression(Type objtype, string property) { property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty); List<string> level = new List<string>(); if (property.Contains('.')) { level.AddRange(property.Split('.')); } else { level.Add(property); } var pe = Expression.Parameter(objtype); #pragma warning disable 8604 var member = Expression.Property(pe, objtype.GetSingleProperty(level[0])); for (int i = 1; i < level.Count; i++) { member = Expression.Property(member, member.Type.GetSingleProperty(level[i])); } return Expression.Lambda<Func<object, object>>(member, pe).Compile(); } /// <summary> /// 获取属性名 /// </summary> /// <param name="expression">属性表达式</param> /// <param name="getAll">是否获取全部级别名称,比如a.b.c</param> /// <returns>属性名</returns> public static string GetPropertyName(this Expression expression, bool getAll = true) { if (expression == null) { return ""; } MemberExpression me = null; LambdaExpression le = null; if (expression is MemberExpression) { me = expression as MemberExpression; } if (expression is LambdaExpression) { le = expression as LambdaExpression; if (le.Body is MemberExpression) { me = le.Body as MemberExpression; } if (le.Body is UnaryExpression) { me = (le.Body as UnaryExpression).Operand as MemberExpression; } } string rv = ""; if (me != null) { rv = me.Member.Name; } while (me != null && getAll && me.NodeType == ExpressionType.MemberAccess) { Expression exp = me.Expression; if (exp is MemberExpression) { rv = (exp as MemberExpression).Member.Name + "." + rv; me = exp as MemberExpression; } else if (exp is MethodCallExpression) { var mexp = exp as MethodCallExpression; if (mexp.Method.Name == "get_Item") { object index = 0; if (mexp.Arguments[0] is MemberExpression) { var obj = ((mexp.Arguments[0] as MemberExpression).Expression as ConstantExpression).Value; index = obj.GetType().GetField((mexp.Arguments[0] as MemberExpression).Member.Name).GetValue(obj); } else { index = (mexp.Arguments[0] as ConstantExpression).Value; } rv = (mexp.Object as MemberExpression).Member.Name + "[" + index + "]." + rv; me = mexp.Object as MemberExpression; } } else { break; } } return rv; } public static Expression GetMemberExp(this ParameterExpression self, Expression member) { return self.GetMemberExp(member.GetPropertyName()); } public static Expression GetMemberExp(this ParameterExpression self, string memberName) { var names = memberName.Split(','); Expression rv = Expression.PropertyOrField(self, names[0]); ; for (int i = 1; i < names.Length; i++) { rv = Expression.PropertyOrField(rv, names[i]); } return rv; } /// <summary> /// 获取正则表达式错误 /// </summary> /// <param name="pi">属性信息</param> /// <returns>错误文本</returns> public static string GetRegexErrorMessage(this MemberInfo pi) { string rv = ""; if (pi.GetCustomAttributes(typeof(RegularExpressionAttribute), false).FirstOrDefault() is RegularExpressionAttribute dis && !string.IsNullOrEmpty(dis.ErrorMessage)) { rv = dis.ErrorMessage; //if (CoreProgram._localizer != null) //{ // rv = CoreProgram._localizer[rv]; //} } else { rv = ""; } return rv; } /// <summary> /// 获取属性显示名称 /// </summary> /// <param name="pi">属性信息</param> /// <returns>属性名称</returns> public static string GetPropertyDisplayName(this MemberInfo pi) { string rv = ""; if (pi.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault() is DisplayAttribute dis && !string.IsNullOrEmpty(dis.Name)) { rv = dis.Name; } else { rv = pi.Name; } return rv; } /// <summary> /// 获取属性显示名称 /// </summary> /// <param name="expression">属性表达式</param> /// <returns>属性显示名称</returns> public static string GetPropertyDisplayName(this Expression expression) { return expression.GetPropertyInfo().GetPropertyDisplayName(); } /// <summary> /// 获取属性的 Description 标注名,如果没有,则返回 属性名称 /// </summary> /// <param name="pi"></param> /// <returns></returns> public static string GetPropertyDescription(this MemberInfo pi) { string rv = ""; if (pi.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() is DescriptionAttribute dis && !string.IsNullOrEmpty(dis.Description)) { rv = dis.Description; } else { rv = pi.Name; } return rv; } /// <summary> /// 获取属性的 Description 标注名,如果没有,则返回 属性名称 /// </summary> /// <param name="expression"></param> /// <returns></returns> public static string GetPropertyDescription(this Expression expression) { return expression.GetPropertyInfo().GetPropertyDisplayName(); } /// <summary> /// 获取枚举显示名称 /// </summary> /// <param name="value">枚举值</param> /// <returns>枚举显示名称</returns> public static string? GetEnumDisplayName(this Enum value) { return GetEnumDisplayName(value.GetType(), value.ToString()); } /// <summary> /// 获取属性信息 /// </summary> /// <param name="expression">属性表达式</param> /// <returns>属性信息</returns> public static PropertyInfo? GetPropertyInfo(this Expression expression) { MemberExpression me = null; LambdaExpression le = null; if (expression is MemberExpression) { me = expression as MemberExpression; } if (expression is LambdaExpression) { le = expression as LambdaExpression; if (le.Body is MemberExpression) { me = le.Body as MemberExpression; } if (le.Body is UnaryExpression) { me = (le.Body as UnaryExpression).Operand as MemberExpression; } } PropertyInfo rv = null; if (me != null) { rv = me.Member.DeclaringType.GetSingleProperty(me.Member.Name); } return rv; } /// <summary> /// 获取属性值 /// </summary> /// <param name="exp">属性表达式</param> /// <param name="obj">属性所在实例</param> /// <returns>属性值</returns> public static object? GetPropertyValue(this object obj, LambdaExpression exp) { //获取表达式的值,并过滤单引号 try { var expValue = exp.Compile().DynamicInvoke(obj); object val = expValue; return val; } catch { return ""; } } /// <summary> /// 获取属性值 /// </summary> /// <param name="obj"></param> /// <param name="property"></param> /// <returns></returns> public static object? GetPropertyValue(this object obj, string property) { //获取表达式的值,并过滤单引号 try { return obj.GetType().GetSingleProperty(property).GetValue(obj); } catch { return null; } } public static List<string>? GetPropertySiblingValues(this object obj, string propertyName) { if (obj == null) { return new List<string>(); } Regex reg = new Regex("(.*?)\\[\\-?\\d?\\]\\.(.*?)$"); var match = reg.Match(propertyName); if (match.Success) { var name1 = match.Groups[1].Value; var name2 = match.Groups[2].Value; var levels = name1.Split('.'); var objtype = obj.GetType(); var pe = Expression.Parameter(objtype); var member = Expression.Property(pe, objtype.GetSingleProperty(levels[0])); for (int i = 1; i < levels.Length; i++) { member = Expression.Property(member, member.Type.GetSingleProperty(levels[i])); } var pe2 = Expression.Parameter(member.Type.GetGenericArguments()[0]); var cast = Expression.Call(typeof(Enumerable), "Cast", new Type[] { pe2.Type }, member); var name2exp = Expression.Property(pe2, pe2.Type.GetSingleProperty(name2)); var selectexp = Expression.Call(name2exp, "ToString", Type.EmptyTypes); Expression select = Expression.Call( typeof(Enumerable), "Select", new Type[] { pe2.Type, typeof(string) }, cast, Expression.Lambda(selectexp, pe2)); var lambda = Expression.Lambda(select, pe); var rv = new List<string>(); try { rv = (lambda.Compile().DynamicInvoke(obj) as IEnumerable<string>)?.ToList(); } catch { } return rv; } else { return new List<string>(); } } /// <summary> /// 判断属性是否必填 /// </summary> /// <param name="pi">属性信息</param> /// <returns>是否必填</returns> public static bool IsPropertyRequired(this MemberInfo pi) { bool isRequired = false; if (pi != null) { //如果需要显示星号,则判断是否是必填项,如果是必填则在内容后面加上星号 //所有int,float。。。这种Primitive类型的,肯定都是必填 Type t = pi.GetMemberType(); if (t != null && (t.IsPrimitive() || t.IsEnum() || t == typeof(decimal) || t == typeof(Guid))) { isRequired = true; } else { //对于其他类,检查是否有RequiredAttribute,如果有就是必填 if (pi.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault() is RequiredAttribute required && required.AllowEmptyStrings == false) { isRequired = true; } else if (pi.GetCustomAttributes(typeof(KeyAttribute), false).FirstOrDefault() != null) { isRequired = true; } } } return isRequired; } /// <summary> /// 设置属性值 /// </summary> /// <param name="source">属性所在实例</param> /// <param name="property">属性名</param> /// <param name="value">要赋的值</param> /// <param name="prefix">属性前缀</param> /// <param name="stringBasedValue">是否为字符串格式的值</param> public static void SetPropertyValue(this object source, string property, object value, string? prefix = null, bool stringBasedValue = false) { try { property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty); List<string> level = new List<string>(); if (property.Contains('.')) { level.AddRange(property.Split('.')); } else { level.Add(property); } if (!string.IsNullOrWhiteSpace(prefix)) { level.Insert(0, prefix); } object temp = source; Type tempType = source.GetType(); for (int i = 0; i < level.Count - 1; i++) { var member = tempType.GetMember(level[i])[0]; if (member != null) { var va = member.GetMemberValue(temp); if (va != null) { temp = va; } else { var newInstance = member.GetMemberType().GetConstructor(Type.EmptyTypes).Invoke(null); member.SetMemberValue(temp, newInstance, null); temp = newInstance; } tempType = member.GetMemberType(); } } var memberInfos = tempType.GetMember(level.Last()); if (!memberInfos.Any()) { return; } var fproperty = memberInfos[0]; if (value == null || value is StringValues s && StringValues.IsNullOrEmpty(s)) { fproperty.SetMemberValue(temp, null, null); return; } bool isArray = false; if (value != null && value.GetType().IsArray == true) { isArray = true; } if (stringBasedValue == true) { Type propertyType = fproperty.GetMemberType(); if (propertyType.IsGeneric(typeof(List<>)) == true) { var list = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null) as IList; var gs = propertyType.GenericTypeArguments; try { if (value.GetType() == typeof(StringValues)) { var strVals = (StringValues)value; var a = strVals.ToArray(); for (int i = 0; i < a.Length; i++) { list.Add(a[i].ConvertValue(gs[0])); } } else if (isArray) { var a = value as object[]; for (int i = 0; i < a.Length; i++) { list.Add(a[i].ConvertValue(gs[0])); } } else { list = value.ConvertValue(propertyType) as IList; } } catch { } fproperty.SetMemberValue(temp, list, null); } else if (propertyType.IsArray) { try { var strVals = (StringValues)value; var eletype = propertyType.GetElementType(); if (eletype != null) { var arr = Array.CreateInstance(eletype, strVals.Count); for (int i = 0; i < arr.Length; i++) { arr.SetValue(strVals[i].ConvertValue(eletype), i); } fproperty.SetMemberValue(temp, arr, null); } } catch { } } else { if (isArray) { var a = value as object[]; if (a.Length == 1) { value = a[0]; } } if (value is string) { value = value.ToString().Replace("\\", "/"); } fproperty.SetMemberValue(temp, value, null); } } else { if (value is string) { value = value.ToString().Replace("\\", "/"); } fproperty.SetMemberValue(temp, value, null); } } catch { } } /// <summary> /// 根据MemberInfo获取值 /// </summary> /// <param name="mi">MemberInfo</param> /// <param name="obj">所在实例</param> /// <param name="index">如果是数组,指定数组下标。默认为null</param> /// <returns>MemberInfo的值</returns> public static object? GetMemberValue(this MemberInfo mi, object obj, object[]? index = null) { object rv = null; if (mi.MemberType == MemberTypes.Property) { rv = ((PropertyInfo)mi).GetValue(obj, index); } else if (mi.MemberType == MemberTypes.Field) { rv = ((FieldInfo)mi).GetValue(obj); } return rv; } /// <summary> /// 设定MemberInfo的值 /// </summary> /// <param name="mi">MemberInfo</param> /// <param name="obj">所在实例</param> /// <param name="val">要赋的值</param> /// <param name="index">如果是数组,指定数组下标。默认为null</param> public static void SetMemberValue(this MemberInfo mi, object obj, object val, object[]? index = null) { object newval = val; if (val is string s) { if (string.IsNullOrEmpty(s)) { val = null; } } if (val != null && val.GetType() != mi.GetMemberType()) { newval = val.ConvertValue(mi.GetMemberType()); } if (mi.MemberType == MemberTypes.Property) { ((PropertyInfo)mi).SetValue(obj, newval, index); } else if (mi.MemberType == MemberTypes.Field) { ((FieldInfo)mi).SetValue(obj, newval); } } /// <summary> /// 获取某个MemberInfo的类型 /// </summary> /// <param name="mi">MemberInfo</param> /// <returns>类型</returns> public static Type? GetMemberType(this MemberInfo mi) { Type? rv = null; if (mi != null) { if (mi.MemberType == MemberTypes.Property) { rv = ((PropertyInfo)mi).PropertyType; } else if (mi.MemberType == MemberTypes.Field) { rv = ((FieldInfo)mi).FieldType; } } return rv; } /// <summary> /// 获取枚举显示名称 /// </summary> /// <param name="enumType">枚举类型</param> /// <param name="value">枚举值</param> /// <returns>枚举显示名称</returns> public static string? GetEnumDisplayName(Type enumType, string value) { string rv = ""; FieldInfo field = null; if (enumType.IsEnum()) { field = enumType.GetField(value); } //如果是nullable的枚举 if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum()) { field = enumType.GenericTypeArguments[0].GetField(value); } if (field != null) { var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList(); if (attribs.Count > 0) { rv = ((DisplayAttribute)attribs[0]).GetName(); //if (CoreProgram._localizer != null) //{ // rv = CoreProgram._localizer[rv]; //} } else { rv = value; } } return rv; } public static string? GetEnumDisplayName(Type enumType, int value) { string? rv = ""; FieldInfo? field = null; string? ename = ""; if (enumType.IsEnum()) { ename = enumType.GetEnumName(value); field = enumType.GetField(ename ?? ""); } //如果是nullable的枚举 if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum()) { ename = enumType.GenericTypeArguments[0].GetEnumName(value); field = enumType.GenericTypeArguments[0].GetField(ename ?? ""); } if (field != null) { var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList(); if (attribs.Count > 0) { rv = ((DisplayAttribute)attribs[0]).GetName(); //if (CoreProgram._localizer != null) //{ // rv = CoreProgram._localizer[rv]; //} } else { rv = ename; } } return rv; } /// <summary> /// 转化值 /// </summary> /// <param name="value">要转换的值</param> /// <param name="propertyType">转换后的类型</param> /// <returns>转换后的值</returns> public static object? ConvertValue(this object value, Type propertyType) { object val = null; if (propertyType.IsGeneric(typeof(Nullable<>)) == true) { var gs = propertyType.GenericTypeArguments; try { val = value.ConvertValue(gs[0]); } catch { } } else if (propertyType.IsEnum()) { val = Enum.Parse(propertyType, value.ToString()); } else if (propertyType == typeof(string)) { val = value?.ToString().Trim(); } else if (propertyType == typeof(Guid)) { bool suc = Guid.TryParse(value?.ToString(), out Guid g); if (suc) { val = g; } else { val = Guid.Empty; } } else { try { if (value.ToString().StartsWith("`") && value.ToString().EndsWith("`")) { string inner = value.ToString().Trim('`').TrimEnd(','); if (!string.IsNullOrWhiteSpace(inner)) { val = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null); string[] pair = inner.Split(','); var gs = propertyType.GetGenericArguments(); foreach (var p in pair) { (val as IList).Add(Convert.ChangeType(p, gs[0])); } } } else { val = Convert.ChangeType(value.ToString(), propertyType); } } catch { } } return val; } public static object MakeList(Type innerType, string propertyName, object[] values) { object rv = typeof(List<>).MakeGenericType(innerType).GetConstructor(Type.EmptyTypes).Invoke(null); var mi = rv.GetType().GetMethod("Add"); var con = innerType.GetConstructor(Type.EmptyTypes); foreach (var item in values) { var newobj = con.Invoke(null); newobj.SetPropertyValue(propertyName, item); mi.Invoke(rv, new object[] { newobj }); } return rv; } /// <summary> /// 获取 是否定义该标签属性 /// </summary> /// <param name="pi"></param> /// <param name="local"></param> /// <returns></returns> public static T? GetAttribute<T>(this MemberInfo pi) where T : Attribute { string rv = ""; if (pi.GetCustomAttributes(typeof(T), false).FirstOrDefault() is T dis) { return dis; } else { return null; } } public static ImmutableDictionary<string, List<PropertyInfo>> _propertyCache { get; set; } = new Dictionary<string, List<PropertyInfo>>().ToImmutableDictionary(); /// <summary> /// 判断是否是泛型 /// </summary> /// <param name="self">Type类</param> /// <param name="innerType">泛型类型</param> /// <returns>判断结果</returns> public static bool IsGeneric(this Type self, Type innerType) { if (self.GetTypeInfo().IsGenericType && self.GetGenericTypeDefinition() == innerType) { return true; } else { return false; } } /// <summary> /// 判断是否为Nullable<>类型 /// </summary> /// <param name="self">Type类</param> /// <returns>判断结果</returns> public static bool IsNullable(this Type self) { return self.IsGeneric(typeof(Nullable<>)); } /// <summary> /// 判断是否为List<>类型 /// </summary> /// <param name="self">Type类</param> /// <returns>判断结果</returns> public static bool IsList(this Type self) { return self.IsGeneric(typeof(List<>)) || self.IsGeneric(typeof(IEnumerable<>)); } /// <summary> /// 判断是否为List<>类型 /// </summary> /// <param name="self">Type类</param> /// <returns>判断结果</returns> public static bool IsListOf<T>(this Type self) { if (self.IsGeneric(typeof(List<>)) && typeof(T).IsAssignableFrom(self.GenericTypeArguments[0])) { return true; } else { return false; } } #region 判断是否为枚举 /// <summary> /// 判断是否为枚举 /// </summary> /// <param name="self">Type类</param> /// <returns>判断结果</returns> public static bool IsEnum(this Type self) { return self.GetTypeInfo().IsEnum; } /// <summary> /// 判断是否为枚举或者可空枚举 /// </summary> /// <param name="self"></param> /// <returns></returns> public static bool IsEnumOrNullableEnum(this Type self) { if (self == null) { return false; } if (self.IsEnum) { return true; } else { if (self.IsGenericType && self.GetGenericTypeDefinition() == typeof(Nullable<>) && self.GetGenericArguments()[0].IsEnum) { return true; } else { return false; } } } #endregion /// <summary> /// 判断是否为值类型 基础值类型 /// </summary> /// <param name="self">Type类</param> /// <returns>判断结果</returns> public static bool IsPrimitive(this Type self) { return self.GetTypeInfo().IsPrimitive || self == typeof(decimal); } /// <summary> /// 判断值是否是数字基础类型 /// </summary> /// <param name="self"></param> /// <returns></returns> public static bool IsNumber(this Type self) { Type checktype = self; if (self.IsNullable()) { checktype = self.GetGenericArguments()[0]; } if (checktype == typeof(int) || checktype == typeof(short) || checktype == typeof(long) || checktype == typeof(float) || checktype == typeof(decimal) || checktype == typeof(double)) { return true; } else { return false; } } #region 判断是否是Bool /// <summary> /// 是否是bool类型 /// </summary> /// <param name="self"></param> /// <returns></returns> public static bool IsBool(this Type self) { return self == typeof(bool); } /// <summary> /// 判断是否是 bool or bool?类型 /// </summary> /// <param name="self"></param> /// <returns></returns> public static bool IsBoolOrNullableBool(this Type self) { if (self == null) { return false; } if (self == typeof(bool) || self == typeof(bool?)) { return true; } else { return false; } } #endregion /// <summary> /// 根据名字获取 /// </summary> /// <param name="self"></param> /// <param name="name"></param> /// <returns></returns> public static PropertyInfo? GetSingleProperty(this Type self, string name) { if (self.FullName == null) throw new Exception("属性名为空"); if (_propertyCache.ContainsKey(self.FullName) == false) { var properties = self.GetProperties().ToList(); _propertyCache = _propertyCache.Add(self.FullName, properties); return properties.Where(x => x.Name == name).FirstOrDefault(); } else { return _propertyCache[self.FullName].Where(x => x.Name == name).FirstOrDefault(); } } /// <summary> /// 获取属性列表 并将 列表属性放入缓存 /// </summary> /// <param name="self"></param> /// <returns></returns> public static PropertyInfo? GetSingleProperty(this Type self, Func<PropertyInfo, bool> where) { if (self.FullName == null) throw new Exception("属性名为空"); if (_propertyCache.ContainsKey(self.FullName) == false) { var properties = self.GetProperties().ToList(); _propertyCache = _propertyCache.Add(self.FullName, properties); return properties.Where(where).FirstOrDefault(); } else { return _propertyCache[self.FullName].Where(where).FirstOrDefault(); } } /// <summary> /// 获取属性列表 并将 列表属性放入缓存 /// </summary> /// <param name="self"></param> /// <returns></returns> public static List<PropertyInfo> GetAllProperties(this Type self) { if (self.FullName == null) throw new Exception("属性名为空"); if (_propertyCache.ContainsKey(self.FullName) == false) { var properties = self.GetProperties().ToList(); _propertyCache = _propertyCache.Add(self.FullName, properties); return properties; } else { return _propertyCache[self.FullName]; } } #endregion } } cylsg/cylsg.utility/cylsg.utility.csproj
New file @@ -0,0 +1,13 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Primitives" Version="8.0.0" /> </ItemGroup> </Project>