Compare commits

...

4 Commits

Author SHA1 Message Date
Diego
b12e923c99 10.7.31 2025-06-06 23:47:07 +08:00
Diego
ab33eed8d3 10.7.22 2025-06-06 21:13:58 +08:00
Diego
d930a9a8eb 修改演示站登录ui 2025-06-05 08:40:25 +08:00
Diego
af381fce12 插件调试增加双击显示 2025-06-04 09:45:02 +08:00
801 changed files with 108781 additions and 517 deletions

View File

@@ -126,35 +126,8 @@ dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent dotnet_style_qualification_for_event = false:silent
dotnet_diagnostic.RCS1146.severity = warning
dotnet_diagnostic.CA2208.severity = none dotnet_diagnostic.RCS1059.severity = none
dotnet_diagnostic.CA2008.severity = none dotnet_diagnostic.RCS1138.severity = suggestion
dotnet_diagnostic.CA1812.severity = none
dotnet_diagnostic.CA1508.severity = none
dotnet_diagnostic.CA1512.severity = none
dotnet_diagnostic.CA1513.severity = none
dotnet_diagnostic.CA1810.severity = none
dotnet_diagnostic.CA1814.severity = none
dotnet_diagnostic.CA1815.severity = none
dotnet_diagnostic.CA1835.severity = none
dotnet_diagnostic.CA1819.severity = none
dotnet_diagnostic.CA1823.severity = none
dotnet_diagnostic.CA2002.severity = none
dotnet_diagnostic.CA5350.severity = none
dotnet_diagnostic.CA5351.severity = none
dotnet_diagnostic.CA5358.severity = none
dotnet_diagnostic.CA5384.severity = none
dotnet_diagnostic.CA5392.severity = none
dotnet_diagnostic.CA1805.severity = none
dotnet_diagnostic.CA1851.severity = none
dotnet_diagnostic.CA1510.severity = none
dotnet_diagnostic.CA5401.severity = none
dotnet_diagnostic.CA2022.severity = none
dotnet_diagnostic.CA1848.severity = none
dotnet_diagnostic.CA2000.severity = none
dotnet_diagnostic.CA5394.severity = none
dotnet_diagnostic.CA3003.severity = none
dotnet_diagnostic.CA1515.severity = none
dotnet_diagnostic.CA1849.severity = none
dotnet_code_quality.CA1822.api_surface = private, internal dotnet_code_quality.CA1822.api_surface = private, internal

View File

@@ -13,14 +13,16 @@ namespace ThingsGateway.Admin.Application;
/// <summary> /// <summary>
/// 需要角色授权权限 /// 需要角色授权权限
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Class)] [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class RolePermissionAttribute : Attribute public sealed class RolePermissionAttribute : Attribute
{ {
} }
/// <summary> /// <summary>
/// 忽略角色授权权限 /// 忽略角色授权权限
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public sealed class IgnoreRolePermissionAttribute : Attribute public sealed class IgnoreRolePermissionAttribute : Attribute
{ {
} }

View File

@@ -11,7 +11,7 @@
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class CacheConst public static class CacheConst
{ {
/// <summary> /// <summary>
/// Token表缓存Key /// Token表缓存Key

View File

@@ -13,7 +13,7 @@ namespace ThingsGateway.Admin.Application;
/// <summary> /// <summary>
/// 通讯器常量 /// 通讯器常量
/// </summary> /// </summary>
public class HubConst public static class HubConst
{ {
/// <summary> /// <summary>
/// 系统HubUrl /// 系统HubUrl

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// 资源表常量 /// 资源表常量
/// </summary> /// </summary>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class ResourceConst public static class ResourceConst
{ {
/// <summary> /// <summary>
/// 系统内置编码 /// 系统内置编码

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// 角色常量 /// 角色常量
/// </summary> /// </summary>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class RoleConst public static class RoleConst
{ {
/// <summary> /// <summary>
/// api角色 /// api角色

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// SqlSugar系统常量 /// SqlSugar系统常量
/// </summary> /// </summary>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class SqlSugarConst public static class SqlSugarConst
{ {
/// <summary> /// <summary>
/// DB_Admin /// DB_Admin

View File

@@ -1,14 +1,4 @@
// ------------------------------------------------------------------------ 
// 版权信息
// 版权归百小僧及百签科技(广东)有限公司所有。
// 所有权利保留。
// 官方网站https://baiqian.com
//
// 许可证信息
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------
using ThingsGateway.DependencyInjection; using ThingsGateway.DependencyInjection;
namespace System; namespace System;

View File

@@ -1,14 +1,4 @@
// ------------------------------------------------------------------------ 
// 版权信息
// 版权归百小僧及百签科技(广东)有限公司所有。
// 所有权利保留。
// 官方网站https://baiqian.com
//
// 许可证信息
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------
using ThingsGateway.DependencyInjection; using ThingsGateway.DependencyInjection;
namespace System; namespace System;

View File

@@ -33,83 +33,6 @@ public class AdminOAuthHandler<TOptions>(
) : OAuthHandler<TOptions>(options, logger, encoder) ) : OAuthHandler<TOptions>(options, logger, encoder)
where TOptions : AdminOAuthOptions, new() where TOptions : AdminOAuthOptions, new()
{ {
private async Task<LoginEvent> GetLogin()
{
var sysUser = await sysUserService.GetUserByIdAsync(RoleConst.SuperAdminId).ConfigureAwait(false);//获取用户信息
var appConfig = await configService.GetAppConfigAsync().ConfigureAwait(false);
var expire = appConfig.LoginPolicy.VerificatExpireTime;
var loginEvent = new LoginEvent
{
Ip = appService.RemoteIpAddress,
Device = appService.UserAgent?.Platform,
Expire = expire,
SysUser = sysUser,
VerificatId = CommonUtils.GetSingleId()
};
//获取verificat列表
var tokenTimeout = loginEvent.DateTime.AddMinutes(loginEvent.Expire);
//生成verificat信息
var verificatInfo = new VerificatInfo
{
Device = loginEvent.Device,
Expire = loginEvent.Expire,
VerificatTimeout = tokenTimeout,
Id = loginEvent.VerificatId,
UserId = loginEvent.SysUser.Id,
LoginIp = loginEvent.Ip,
LoginTime = loginEvent.DateTime
};
//添加到verificat列表
verificatInfoService.Add(verificatInfo);
return loginEvent;
}
/// <summary>
/// 登录事件
/// </summary>
/// <param name="loginEvent"></param>
/// <returns></returns>
private async Task UpdateUser(LoginEvent loginEvent)
{
var sysUser = loginEvent.SysUser;
#region /
var key = CacheConst.Cache_LoginErrorCount + sysUser.Account;//获取登录错误次数Key值
App.CacheService.Remove(key);//移除登录错误次数
//获取用户verificat列表
var userToken = verificatInfoService.GetOne(loginEvent.VerificatId);
#endregion /
#region ,
sysUser.LastLoginIp = sysUser.LatestLoginIp;
sysUser.LastLoginTime = sysUser.LatestLoginTime;
sysUser.LatestLoginIp = loginEvent.Ip;
sysUser.LatestLoginTime = loginEvent.DateTime;
#endregion ,
using var db = DbContext.Db.GetConnectionScopeWithAttr<SysUser>().CopyNew();
//更新用户登录信息
if (await db.Updateable(sysUser).UpdateColumns(it => new
{
it.LastLoginIp,
it.LastLoginTime,
it.LatestLoginIp,
it.LatestLoginTime,
}).ExecuteCommandAsync().ConfigureAwait(false) > 0)
App.CacheService.HashAdd(CacheConst.Cache_SysUser, sysUser.Id.ToString(), sysUser);//更新Cache信息
}
static AdminOAuthHandler() static AdminOAuthHandler()
@@ -152,7 +75,6 @@ public class AdminOAuthHandler<TOptions>(
} }
protected override async Task<AuthenticationTicket> CreateTicketAsync( protected override async Task<AuthenticationTicket> CreateTicketAsync(
ClaimsIdentity identity, ClaimsIdentity identity,
AuthenticationProperties properties, AuthenticationProperties properties,
@@ -160,14 +82,17 @@ public class AdminOAuthHandler<TOptions>(
{ {
properties.RedirectUri = Options.HomePath; properties.RedirectUri = Options.HomePath;
properties.IsPersistent = true; properties.IsPersistent = true;
var appConfig = await configService.GetAppConfigAsync().ConfigureAwait(false);
int expire = appConfig.LoginPolicy.VerificatExpireTime;
if (!string.IsNullOrEmpty(tokens.ExpiresIn) && int.TryParse(tokens.ExpiresIn, out var result)) if (!string.IsNullOrEmpty(tokens.ExpiresIn) && int.TryParse(tokens.ExpiresIn, out var result))
{ {
properties.ExpiresUtc = TimeProvider.System.GetUtcNow().AddSeconds(result); properties.ExpiresUtc = TimeProvider.System.GetUtcNow().AddSeconds(result);
expire = (int)(result / 60.0);
} }
var user = await HandleUserInfoAsync(tokens).ConfigureAwait(false); var user = await HandleUserInfoAsync(tokens).ConfigureAwait(false);
var loginEvent = await GetLogin().ConfigureAwait(false); var loginEvent = await GetLogin(expire).ConfigureAwait(false);
await UpdateUser(loginEvent).ConfigureAwait(false); await UpdateUser(loginEvent).ConfigureAwait(false);
identity.AddClaim(new Claim(ClaimConst.VerificatId, loginEvent.VerificatId.ToString())); identity.AddClaim(new Claim(ClaimConst.VerificatId, loginEvent.VerificatId.ToString()));
identity.AddClaim(new Claim(ClaimConst.UserId, RoleConst.SuperAdminId.ToString())); identity.AddClaim(new Claim(ClaimConst.UserId, RoleConst.SuperAdminId.ToString()));
@@ -222,29 +147,6 @@ public class AdminOAuthHandler<TOptions>(
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
} }
/// <summary>刷新 Token 方法</summary>
protected virtual async Task<OAuthTokenResponse> RefreshTokenAsync(OAuthTokenResponse oAuthToken)
{
var query = new Dictionary<string, string>
{
{ "refresh_token", oAuthToken.RefreshToken },
{ "grant_type", "refresh_token" }
};
var request = new HttpRequestMessage(HttpMethod.Post, QueryHelpers.AddQueryString(Options.TokenEndpoint, query));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await Backchannel.SendAsync(request, Context.RequestAborted).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
return OAuthTokenResponse.Success(JsonDocument.Parse(content));
}
return OAuthTokenResponse.Failed(new OAuthTokenException($"OAuth token endpoint failure: {await Display(response).ConfigureAwait(false)}"));
}
/// <summary>处理用户信息方法</summary> /// <summary>处理用户信息方法</summary>
protected virtual async Task<JsonElement> HandleUserInfoAsync(OAuthTokenResponse tokens) protected virtual async Task<JsonElement> HandleUserInfoAsync(OAuthTokenResponse tokens)
@@ -283,7 +185,93 @@ public class AdminOAuthHandler<TOptions>(
return output.ToString(); return output.ToString();
} }
private async Task<LoginEvent> GetLogin(int expire)
{
var sysUser = await sysUserService.GetUserByIdAsync(RoleConst.SuperAdminId).ConfigureAwait(false);//获取用户信息
var loginEvent = new LoginEvent
{
Ip = appService.RemoteIpAddress,
Device = appService.UserAgent?.Platform,
Expire = expire,
SysUser = sysUser,
VerificatId = CommonUtils.GetSingleId()
};
//获取verificat列表
var tokenTimeout = loginEvent.DateTime.AddMinutes(loginEvent.Expire);
//生成verificat信息
var verificatInfo = new VerificatInfo
{
Device = loginEvent.Device,
Expire = loginEvent.Expire,
VerificatTimeout = tokenTimeout,
Id = loginEvent.VerificatId,
UserId = loginEvent.SysUser.Id,
LoginIp = loginEvent.Ip,
LoginTime = loginEvent.DateTime
};
//添加到verificat列表
verificatInfoService.Add(verificatInfo);
return loginEvent;
}
/// <summary>
/// 登录事件
/// </summary>
/// <param name="loginEvent"></param>
/// <returns></returns>
private async Task UpdateUser(LoginEvent loginEvent)
{
var sysUser = loginEvent.SysUser;
#region /
var key = CacheConst.Cache_LoginErrorCount + sysUser.Account;//获取登录错误次数Key值
App.CacheService.Remove(key);//移除登录错误次数
//获取用户verificat列表
var userToken = verificatInfoService.GetOne(loginEvent.VerificatId);
#endregion /
#region ,
sysUser.LastLoginIp = sysUser.LatestLoginIp;
sysUser.LastLoginTime = sysUser.LatestLoginTime;
sysUser.LatestLoginIp = loginEvent.Ip;
sysUser.LatestLoginTime = loginEvent.DateTime;
#endregion ,
using var db = DbContext.Db.GetConnectionScopeWithAttr<SysUser>().CopyNew();
//更新用户登录信息
if (await db.Updateable(sysUser).UpdateColumns(it => new
{
it.LastLoginIp,
it.LastLoginTime,
it.LatestLoginIp,
it.LatestLoginTime,
}).ExecuteCommandAsync().ConfigureAwait(false) > 0)
App.CacheService.HashAdd(CacheConst.Cache_SysUser, sysUser.Id.ToString(), sysUser);//更新Cache信息
}
} }
/// <summary>自定义 Token 异常</summary> /// <summary>自定义 Token 异常</summary>
public class OAuthTokenException(string message) : Exception(message); public class OAuthTokenException : Exception
{
public OAuthTokenException() : base()
{
}
public OAuthTokenException(string? message, Exception? innerException) : base(message, innerException)
{
}
public OAuthTokenException(string? message) : base(message)
{
}
}

View File

@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Text;
using System.Text.Json; using System.Text.Json;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
@@ -32,6 +33,42 @@ public class GiteeOAuthOptions : AdminOAuthOptions
context.Response.Redirect(context.RedirectUri); context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask; return Task.CompletedTask;
}; };
}
/// <summary>刷新 Token 方法</summary>
protected virtual async Task<OAuthTokenResponse> RefreshTokenAsync(TicketReceivedContext ticketReceivedContext, string refreshToken)
{
var query = new Dictionary<string, string>
{
{ "refresh_token", refreshToken },
{ "grant_type", "refresh_token" }
};
var request = new HttpRequestMessage(HttpMethod.Post, QueryHelpers.AddQueryString(TokenEndpoint, query));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await Backchannel.SendAsync(request, ticketReceivedContext.HttpContext.RequestAborted).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
return OAuthTokenResponse.Success(JsonDocument.Parse(content));
}
return OAuthTokenResponse.Failed(new OAuthTokenException($"OAuth token endpoint failure: {await Display(response).ConfigureAwait(false)}"));
}
/// <summary>生成错误信息方法</summary>
protected static async Task<string> Display(HttpResponseMessage response)
{
var output = new StringBuilder();
output.Append($"Status: {response.StatusCode}; ");
output.Append($"Headers: {response.Headers}; ");
output.Append($"Body: {await response.Content.ReadAsStringAsync().ConfigureAwait(false)};");
return output.ToString();
} }
public override string GetName(JsonElement element) public override string GetName(JsonElement element)

View File

@@ -13,7 +13,7 @@ namespace ThingsGateway.Admin.Application;
/// <summary> /// <summary>
/// 日志常量 /// 日志常量
/// </summary> /// </summary>
public class LoggingConst public static class LoggingConst
{ {
/// <summary> /// <summary>
/// 分类 /// 分类

View File

@@ -87,7 +87,7 @@ public class BlazorAuthenticationHandler : AppAuthorizeHandler
var roles = await _sysRoleService.GetRoleListByUserIdAsync(userId).ConfigureAwait(false); var roles = await _sysRoleService.GetRoleListByUserIdAsync(userId).ConfigureAwait(false);
//这里鉴别用户使能状态 //这里鉴别用户使能状态
if (user == null || !user.Status) if (user?.Status != true)
{ {
return false; return false;
} }
@@ -137,7 +137,7 @@ public class BlazorAuthenticationHandler : AppAuthorizeHandler
else else
{ {
//这里鉴别用户使能状态 //这里鉴别用户使能状态
if (user == null || !user.Status) if (user?.Status != true)
{ {
return false; return false;
} }

View File

@@ -334,7 +334,7 @@ internal sealed class SysResourceService : BaseService<SysResource>, ISysResourc
flatList.Add(node); flatList.Add(node);
// 如果当前节点有子节点,则递归处理每个子节点 // 如果当前节点有子节点,则递归处理每个子节点
if (node.Children != null && node.Children.Count > 0) if (node.Children?.Count > 0)
{ {
foreach (var child in node.Children) foreach (var child in node.Children)
{ {

View File

@@ -47,7 +47,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ThingsGateway.Razor\ThingsGateway.Razor.csproj" /> <ProjectReference Include="..\ThingsGateway.Razor\ThingsGateway.Razor.csproj" />
<ProjectReference Include="..\ThingsGateway.SqlSugar\ThingsGateway.SqlSugar.csproj" /> <ProjectReference Include="..\ThingsGateway.DB\ThingsGateway.DB.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -13,7 +13,7 @@ using Microsoft.Extensions.DependencyInjection;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class ClearTokenUtil public static class ClearTokenUtil
{ {
private static IRelationService RelationService; private static IRelationService RelationService;
private static ISysUserService SysUserService; private static ISysUserService SysUserService;

View File

@@ -13,7 +13,7 @@ using Microsoft.Extensions.DependencyInjection;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class NoticeUtil public static class NoticeUtil
{ {
private static INoticeService NoticeService; private static INoticeService NoticeService;

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// <inheritdoc/> /// <inheritdoc/>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class OpenApiUtil public static class OpenApiUtil
{ {
/// <summary> /// <summary>
/// 构建树节点,传入的列表已经是树结构 /// 构建树节点,传入的列表已经是树结构

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// <inheritdoc/> /// <inheritdoc/>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class OrgUtil public static class OrgUtil
{ {
/// <summary> /// <summary>
/// 构造选择项ID/TITLE /// 构造选择项ID/TITLE

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// <inheritdoc/> /// <inheritdoc/>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class PositionUtil public static class PositionUtil
{ {
/// <summary> /// <summary>

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// <inheritdoc/> /// <inheritdoc/>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class RoleUtil public static class RoleUtil
{ {

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// <inheritdoc/> /// <inheritdoc/>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class UserUtil public static class UserUtil
{ {
/// <summary> /// <summary>

View File

@@ -14,7 +14,7 @@ using ThingsGateway.Extension.Generic;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
public class VerificatInfoUtil public static class VerificatInfoUtil
{ {
private static IVerificatInfoService VerificatInfoService { get; set; } private static IVerificatInfoService VerificatInfoService { get; set; }
static VerificatInfoUtil() static VerificatInfoUtil()

View File

@@ -11,7 +11,7 @@
namespace ThingsGateway.Admin.Razor; namespace ThingsGateway.Admin.Razor;
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class AdminOperConst public static class AdminOperConst
{ {
public const string Add = "新增"; public const string Add = "新增";
public const string Delete = "删除"; public const string Delete = "删除";

View File

@@ -48,7 +48,7 @@ public partial class SysUserAvatarEdit : IDisposable
private async Task OnAvatarUpload(UploadFile file) private async Task OnAvatarUpload(UploadFile file)
{ {
if (file != null && file.File != null) if (file?.File != null)
{ {
var format = file.File.ContentType; var format = file.File.ContentType;
ReadAvatarToken ??= new CancellationTokenSource(); ReadAvatarToken ??= new CancellationTokenSource();

View File

@@ -48,7 +48,7 @@ public partial class UserInfoEditComponent
private async Task OnAvatarUpload(UploadFile file) private async Task OnAvatarUpload(UploadFile file)
{ {
if (file != null && file.File != null) if (file?.File != null)
{ {
var format = file.File.ContentType; var format = file.File.ContentType;
ReadAvatarToken ??= new CancellationTokenSource(); ReadAvatarToken ??= new CancellationTokenSource();

View File

@@ -16,7 +16,7 @@ namespace ThingsGateway.Admin.Razor;
/// <inheritdoc/> /// <inheritdoc/>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class ResourceUtil public static class ResourceUtil
{ {
/// <summary> /// <summary>

View File

@@ -1,12 +1 @@
// ------------------------------------------------------------------------ global using ThingsGateway.Admin.Application;
// 版权信息
// 版权归百小僧及百签科技(广东)有限公司所有。
// 所有权利保留。
// 官方网站https://baiqian.com
//
// 许可证信息
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------
global using ThingsGateway.Admin.Application;

View File

@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Application;
/// 授权用户常量 /// 授权用户常量
/// </summary> /// </summary>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class ClaimConst public static class ClaimConst
{ {
/// <summary> /// <summary>
/// 账号 /// 账号

View File

@@ -225,7 +225,7 @@ public static class SqlSugarExtensions
private static IEnumerable<T> Sort<T>(this IEnumerable<T> list, BasePageInput basePageInput) private static IEnumerable<T> Sort<T>(this IEnumerable<T> list, BasePageInput basePageInput)
{ {
if (basePageInput != null && basePageInput.SortField != null) if (basePageInput?.SortField != null)
{ {
for (int i = 0; i < basePageInput.SortField.Count; i++) for (int i = 0; i < basePageInput.SortField.Count; i++)
{ {

View File

@@ -0,0 +1,11 @@
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
//------------------------------------------------------------------------------
global using ThingsGateway.NewLife.Extension;

View File

@@ -25,7 +25,7 @@ namespace ThingsGateway.Admin.Application;
/// 种子数据工具类 /// 种子数据工具类
/// </summary> /// </summary>
[ThingsGateway.DependencyInjection.SuppressSniffer] [ThingsGateway.DependencyInjection.SuppressSniffer]
public class SeedDataUtil public static class SeedDataUtil
{ {
/// <summary> /// <summary>
/// 获取List列表 /// 获取List列表

View File

@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)Version.props" />
<Import Project="$(SolutionDir)PackNuget.props" />
<PropertyGroup>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.5" />
</ItemGroup>
<ItemGroup>
<None Include="..\README.md" Pack="true" PackagePath="\" />
<None Include="..\README.zh-CN.md" Pack="true" PackagePath="\" />
<None Remove="$(SolutionDir)..\README.md" Pack="false" PackagePath="\" />
<None Remove="$(SolutionDir)..\README.zh-CN.md" Pack="false" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ThingsGateway.Razor\ThingsGateway.Razor.csproj" />
<ProjectReference Include="..\ThingsGateway.SqlSugar\ThingsGateway.SqlSugar.csproj" />
<!--<PackageReference Include="SqlSugarCore" Version="5.1.4.195" />-->
</ItemGroup>
</Project>

View File

@@ -471,7 +471,7 @@ public static class App
IEnumerable<string> pathOfExternalAssemblies = Array.Empty<string>(); IEnumerable<string> pathOfExternalAssemblies = Array.Empty<string>();
// 加载 appsettings.json 配置的外部程序集 // 加载 appsettings.json 配置的外部程序集
if (Settings.ExternalAssemblies != null && Settings.ExternalAssemblies.Length > 0) if (Settings.ExternalAssemblies?.Length > 0)
{ {
var externalDlls = new List<string>(); var externalDlls = new List<string>();
foreach (var item in Settings.ExternalAssemblies) foreach (var item in Settings.ExternalAssemblies)
@@ -552,7 +552,7 @@ public static class App
} }
// 处理排除的程序集 // 处理排除的程序集
if (Settings.ExcludeAssemblies != null && Settings.ExcludeAssemblies.Length > 0) if (Settings.ExcludeAssemblies?.Length > 0)
{ {
scanAssemblies = scanAssemblies.Where(ass => !Settings.ExcludeAssemblies.Contains(ass.GetName().Name, StringComparer.OrdinalIgnoreCase)); scanAssemblies = scanAssemblies.Where(ass => !Settings.ExcludeAssemblies.Contains(ass.GetName().Name, StringComparer.OrdinalIgnoreCase));
} }

View File

@@ -455,7 +455,7 @@ public static class ObjectExtensions
foreach (var property in propertys) foreach (var property in propertys)
{ {
var p = oldType.GetProperty(property.Name); var p = oldType.GetProperty(property.Name);
if (property.CanWrite && p != null && p.CanRead) if (property.CanWrite && p?.CanRead == true)
{ {
property.SetValue(o, ChangeType(p.GetValue(obj, null), property.PropertyType), null); property.SetValue(o, ChangeType(p.GetValue(obj, null), property.PropertyType), null);
} }
@@ -647,7 +647,7 @@ public static class ObjectExtensions
/// <returns><see cref="bool"/> 实例true 表示空集合false 表示非空集合</returns> /// <returns><see cref="bool"/> 实例true 表示空集合false 表示非空集合</returns>
internal static bool IsEmpty<T>(this IEnumerable<T> collection) internal static bool IsEmpty<T>(this IEnumerable<T> collection)
{ {
return collection == null || !collection.Any(); return collection?.Any() != true;
} }

View File

@@ -54,8 +54,7 @@ public class FromConvertBinderProvider : IModelBinderProvider
// 判断是否定义 [FromConvert] 特性 // 判断是否定义 [FromConvert] 特性
if (context.Metadata is DefaultModelMetadata actMetadata if (context.Metadata is DefaultModelMetadata actMetadata
&& actMetadata.Attributes.ParameterAttributes != null && actMetadata.Attributes.ParameterAttributes?.Count > 0
&& actMetadata.Attributes.ParameterAttributes.Count > 0
&& actMetadata.Attributes.ParameterAttributes.Any(u => u.GetType() == typeof(FromConvertAttribute))) && actMetadata.Attributes.ParameterAttributes.Any(u => u.GetType() == typeof(FromConvertAttribute)))
{ {
return new FromConvertBinder(_modelBinderConverts); return new FromConvertBinder(_modelBinderConverts);

View File

@@ -25,7 +25,7 @@ public sealed class AppAuthorizeAttribute : AuthorizeAttribute
/// <param name="policies">多个策略</param> /// <param name="policies">多个策略</param>
public AppAuthorizeAttribute(params string[] policies) public AppAuthorizeAttribute(params string[] policies)
{ {
if (policies != null && policies.Length > 0) Policies = policies; if (policies?.Length > 0) Policies = policies;
} }
/// <summary> /// <summary>

View File

@@ -47,7 +47,7 @@ public sealed class DependsOnAttribute : Attribute
var components = new List<Type>(); var components = new List<Type>();
// 遍历所有依赖组件 // 遍历所有依赖组件
if (dependComponents != null && dependComponents.Length > 0) if (dependComponents?.Length > 0)
{ {
foreach (var component in dependComponents) foreach (var component in dependComponents)
{ {
@@ -102,7 +102,7 @@ public sealed class DependsOnAttribute : Attribute
var components = new List<Type>(); var components = new List<Type>();
// 遍历所有依赖组件 // 遍历所有依赖组件
if (value != null && value.Length > 0) if (value?.Length > 0)
{ {
foreach (var component in value) foreach (var component in value)
{ {

View File

@@ -65,7 +65,7 @@ internal static class Penetrates
IEnumerable<string> exposedHeaders = corsAccessorSettings.FixedClientToken == true IEnumerable<string> exposedHeaders = corsAccessorSettings.FixedClientToken == true
? _defaultExposedHeaders ? _defaultExposedHeaders
: Array.Empty<string>(); : Array.Empty<string>();
if (corsAccessorSettings.WithExposedHeaders != null && corsAccessorSettings.WithExposedHeaders.Length > 0) if (corsAccessorSettings.WithExposedHeaders?.Length > 0)
{ {
exposedHeaders = exposedHeaders.Concat(corsAccessorSettings.WithExposedHeaders).Distinct(StringComparer.OrdinalIgnoreCase); exposedHeaders = exposedHeaders.Concat(corsAccessorSettings.WithExposedHeaders).Distinct(StringComparer.OrdinalIgnoreCase);
} }

View File

@@ -19,7 +19,7 @@ namespace ThingsGateway.DataEncryption;
/// AES 加解密 /// AES 加解密
/// </summary> /// </summary>
[SuppressSniffer] [SuppressSniffer]
public class AESEncryption public static class AESEncryption
{ {
/// <summary> /// <summary>
/// 加密 /// 加密

View File

@@ -20,7 +20,7 @@ namespace ThingsGateway.DataEncryption;
/// DES 加解密 /// DES 加解密
/// </summary> /// </summary>
[SuppressSniffer] [SuppressSniffer]
public class DESEncryption public static class DESEncryption
{ {
/// <summary> /// <summary>
/// 加密 /// 加密

View File

@@ -18,7 +18,7 @@ namespace ThingsGateway.DataEncryption;
/// KSort 加密(数据签名) /// KSort 加密(数据签名)
/// </summary> /// </summary>
[SuppressSniffer] [SuppressSniffer]
public class KSortEncryption public static class KSortEncryption
{ {
private static DateTime _timeStampStartTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private static DateTime _timeStampStartTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

View File

@@ -17,7 +17,7 @@ namespace ThingsGateway.DataEncryption;
/// PBKDF2 加密 /// PBKDF2 加密
/// </summary> /// </summary>
[SuppressSniffer] [SuppressSniffer]
public class PBKDF2Encryption public static class PBKDF2Encryption
{ {
private const string SaltHashSeparator = ":"; private const string SaltHashSeparator = ":";

View File

@@ -18,7 +18,7 @@ namespace ThingsGateway.DataEncryption;
/// SHA1 加密 /// SHA1 加密
/// </summary> /// </summary>
[SuppressSniffer] [SuppressSniffer]
public class SHA1Encryption public static class SHA1Encryption
{ {
/// <summary> /// <summary>
/// SHA1 加密 /// SHA1 加密

View File

@@ -18,6 +18,7 @@ namespace System.ComponentModel.DataAnnotations;
/// 数据类型验证特性 /// 数据类型验证特性
/// </summary> /// </summary>
[SuppressSniffer] [SuppressSniffer]
[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public sealed class DataValidationAttribute : ValidationAttribute public sealed class DataValidationAttribute : ValidationAttribute
{ {
/// <summary> /// <summary>

View File

@@ -215,7 +215,7 @@ public static class DependencyInjectionServiceCollectionExtensions
private static void AddDispatchProxy(IServiceCollection services, Type dependencyType, Type type, Type proxyType, Type inter, bool hasTarget = true) private static void AddDispatchProxy(IServiceCollection services, Type dependencyType, Type type, Type proxyType, Type inter, bool hasTarget = true)
{ {
proxyType ??= GlobalServiceProxyType; proxyType ??= GlobalServiceProxyType;
if (proxyType == null || (type != null && type.IsDefined(typeof(SuppressProxyAttribute), true))) return; if (proxyType == null || (type?.IsDefined(typeof(SuppressProxyAttribute), true) == true)) return;
var lifetime = TryGetServiceLifetime(dependencyType); var lifetime = TryGetServiceLifetime(dependencyType);

View File

@@ -220,8 +220,7 @@ internal sealed class DynamicApiControllerApplicationModelConvention : IApplicat
// 解决 Gitee 该 Issuehttps://gitee.com/dotnetchina/Furion/issues/I59B74 // 解决 Gitee 该 Issuehttps://gitee.com/dotnetchina/Furion/issues/I59B74
if (CheckIsForceWithDefaultRoute(controllerApiDescriptionSettings) if (CheckIsForceWithDefaultRoute(controllerApiDescriptionSettings)
&& !string.IsNullOrWhiteSpace(_dynamicApiControllerSettings.DefaultRoutePrefix) && !string.IsNullOrWhiteSpace(_dynamicApiControllerSettings.DefaultRoutePrefix)
&& controller.Selectors[0] != null && controller.Selectors[0]?.AttributeRouteModel != null
&& controller.Selectors[0].AttributeRouteModel != null
&& !ForceWithDefaultPrefixRouteControllerTypes.Contains(controller.ControllerType)) && !ForceWithDefaultPrefixRouteControllerTypes.Contains(controller.ControllerType))
{ {
// 读取模块 // 读取模块

View File

@@ -126,7 +126,7 @@ public static class DynamicApiControllerServiceCollectionExtensions
{ {
var partManager = mvcBuilder.PartManager; var partManager = mvcBuilder.PartManager;
// 载入程序集部件 // 载入程序集部件
if (partManager != null && assemblies != null && assemblies.Any()) if (partManager != null && assemblies?.Any() == true)
{ {
foreach (var assembly in assemblies) foreach (var assembly in assemblies)
{ {

View File

@@ -48,7 +48,7 @@ internal sealed class DynamicApiRuntimeChangeProvider : IDynamicApiRuntimeChange
/// <param name="assemblies">程序集</param> /// <param name="assemblies">程序集</param>
public void AddAssemblies(params Assembly[] assemblies) public void AddAssemblies(params Assembly[] assemblies)
{ {
if (assemblies != null && assemblies.Length > 0) if (assemblies?.Length > 0)
{ {
foreach (var assembly in assemblies) foreach (var assembly in assemblies)
{ {
@@ -63,7 +63,7 @@ internal sealed class DynamicApiRuntimeChangeProvider : IDynamicApiRuntimeChange
/// <param name="assemblies">程序集</param> /// <param name="assemblies">程序集</param>
public void AddAssembliesWithNotifyChanges(params Assembly[] assemblies) public void AddAssembliesWithNotifyChanges(params Assembly[] assemblies)
{ {
if (assemblies != null && assemblies.Length > 0) if (assemblies?.Length > 0)
{ {
AddAssemblies(assemblies); AddAssemblies(assemblies);
NotifyChanges(); NotifyChanges();
@@ -76,7 +76,7 @@ internal sealed class DynamicApiRuntimeChangeProvider : IDynamicApiRuntimeChange
/// <param name="assemblyNames">程序集名称</param> /// <param name="assemblyNames">程序集名称</param>
public void RemoveAssemblies(params string[] assemblyNames) public void RemoveAssemblies(params string[] assemblyNames)
{ {
if (assemblyNames != null && assemblyNames.Length > 0) if (assemblyNames?.Length > 0)
{ {
foreach (var assemblyName in assemblyNames) foreach (var assemblyName in assemblyNames)
{ {
@@ -93,7 +93,7 @@ internal sealed class DynamicApiRuntimeChangeProvider : IDynamicApiRuntimeChange
/// <param name="assemblies">程序集</param> /// <param name="assemblies">程序集</param>
public void RemoveAssemblies(params Assembly[] assemblies) public void RemoveAssemblies(params Assembly[] assemblies)
{ {
if (assemblies != null && assemblies.Length > 0) if (assemblies?.Length > 0)
{ {
RemoveAssemblies(assemblies.Select(ass => ass.GetName().Name).ToArray()); RemoveAssemblies(assemblies.Select(ass => ass.GetName().Name).ToArray());
} }
@@ -105,7 +105,7 @@ internal sealed class DynamicApiRuntimeChangeProvider : IDynamicApiRuntimeChange
/// <param name="assemblyNames">程序集名称</param> /// <param name="assemblyNames">程序集名称</param>
public void RemoveAssembliesWithNotifyChanges(params string[] assemblyNames) public void RemoveAssembliesWithNotifyChanges(params string[] assemblyNames)
{ {
if (assemblyNames != null && assemblyNames.Length > 0) if (assemblyNames?.Length > 0)
{ {
RemoveAssemblies(assemblyNames); RemoveAssemblies(assemblyNames);
NotifyChanges(); NotifyChanges();
@@ -118,7 +118,7 @@ internal sealed class DynamicApiRuntimeChangeProvider : IDynamicApiRuntimeChange
/// <param name="assemblies">程序集</param> /// <param name="assemblies">程序集</param>
public void RemoveAssembliesWithNotifyChanges(params Assembly[] assemblies) public void RemoveAssembliesWithNotifyChanges(params Assembly[] assemblies)
{ {
if (assemblies != null && assemblies.Length > 0) if (assemblies?.Length > 0)
{ {
RemoveAssemblies(assemblies); RemoveAssemblies(assemblies);
NotifyChanges(); NotifyChanges();

View File

@@ -49,6 +49,14 @@ public class AppFriendlyException : Exception
ErrorCode = OriginErrorCode = errorCode; ErrorCode = OriginErrorCode = errorCode;
} }
public AppFriendlyException(string? message) : base(message)
{
}
public AppFriendlyException(string? message, Exception? innerException) : base(message, innerException)
{
}
/// <summary> /// <summary>
/// 错误码 /// 错误码
/// </summary> /// </summary>

View File

@@ -102,7 +102,7 @@ public sealed class Retry
} }
// 如果填写了 exceptionTypes 且异常类型不在 exceptionTypes 之内,则终止重试 // 如果填写了 exceptionTypes 且异常类型不在 exceptionTypes 之内,则终止重试
if (exceptionTypes != null && exceptionTypes.Length > 0 && !exceptionTypes.Any(u => u.IsAssignableFrom(ex.GetType()))) if (exceptionTypes?.Length > 0 && !exceptionTypes.Any(u => u.IsAssignableFrom(ex.GetType())))
{ {
if (finalThrow) if (finalThrow)
{ {

View File

@@ -604,7 +604,7 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
private string TrySerializeObject(object obj, LoggingMonitorMethod monitorMethod, out bool succeed) private string TrySerializeObject(object obj, LoggingMonitorMethod monitorMethod, out bool succeed)
{ {
// 排除 IQueryable<> 泛型 // 排除 IQueryable<> 泛型
if (obj != null && obj.GetType().HasImplementedRawGeneric(typeof(IQueryable<>))) if (obj?.GetType().HasImplementedRawGeneric(typeof(IQueryable<>)) == true)
{ {
succeed = true; succeed = true;
return "{}"; return "{}";
@@ -961,8 +961,7 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
// token 信息 // token 信息
// 判断是否是授权访问 // 判断是否是授权访问
var isAuth = actionMethod.GetFoundAttribute<AllowAnonymousAttribute>(true) == null var isAuth = actionMethod.GetFoundAttribute<AllowAnonymousAttribute>(true) == null
&& resultHttpContext.User != null && resultHttpContext.User?.Identity.IsAuthenticated == true;
&& resultHttpContext.User.Identity.IsAuthenticated;
// 获取响应头信息 // 获取响应头信息
var accessToken = resultHttpContext.Response.Headers["access-token"].ToString(); var accessToken = resultHttpContext.Response.Headers["access-token"].ToString();
var authorization = string.IsNullOrWhiteSpace(accessToken) var authorization = string.IsNullOrWhiteSpace(accessToken)

View File

@@ -47,7 +47,7 @@ public sealed partial class StringLoggingPart
/// <param name="args"></param> /// <param name="args"></param>
public StringLoggingPart SetArgs(params object[] args) public StringLoggingPart SetArgs(params object[] args)
{ {
if (args != null && args.Length > 0) Args = args; if (args?.Length > 0) Args = args;
return this; return this;
} }

View File

@@ -47,7 +47,7 @@ public static class ObjectMapperServiceCollectionExtensions
var config = TypeAdapterConfig.GlobalSettings; var config = TypeAdapterConfig.GlobalSettings;
// 扫描所有继承 IRegister 接口的对象映射配置 // 扫描所有继承 IRegister 接口的对象映射配置
if (assemblies != null && assemblies.Length > 0) config.Scan(assemblies); if (assemblies?.Length > 0) config.Scan(assemblies);
// 配置支持依赖注入 // 配置支持依赖注入
services.AddSingleton(config); services.AddSingleton(config);

View File

@@ -235,7 +235,7 @@ public sealed class SchedulerBuilder
var schedulerBuilder = new SchedulerBuilder(jobBuilder); var schedulerBuilder = new SchedulerBuilder(jobBuilder);
// 批量添加触发器 // 批量添加触发器
if (triggerBuilders != null && triggerBuilders.Length > 0) if (triggerBuilders?.Length > 0)
{ {
schedulerBuilder.TriggerBuilders.AddRange(triggerBuilders); schedulerBuilder.TriggerBuilders.AddRange(triggerBuilders);
} }

View File

@@ -192,7 +192,7 @@ public static class ScheduleExtensions
var underScoreCasePropertyName = Penetrates.GetNaming(propertyName, NamingConventions.UnderScoreCase); var underScoreCasePropertyName = Penetrates.GetNaming(propertyName, NamingConventions.UnderScoreCase);
// 处理忽略属性问题 // 处理忽略属性问题
if (ignorePropertyNames != null && ignorePropertyNames.Length > 0) if (ignorePropertyNames?.Length > 0)
{ {
if (ignorePropertyNames.Contains(propertyName, StringComparer.OrdinalIgnoreCase) if (ignorePropertyNames.Contains(propertyName, StringComparer.OrdinalIgnoreCase)
|| ignorePropertyNames.Contains(camelCasePropertyName, StringComparer.OrdinalIgnoreCase) || ignorePropertyNames.Contains(camelCasePropertyName, StringComparer.OrdinalIgnoreCase)

View File

@@ -327,7 +327,7 @@ internal sealed class ScheduleHostedService : BackgroundService
}; };
// 是否定义 FallbackAsync 方法 // 是否定义 FallbackAsync 方法
var isDefinedFallbackAsyncMethod = jobHandler != null && jobHandler.GetType().GetMethod(nameof(IJob.FallbackAsync) var isDefinedFallbackAsyncMethod = jobHandler?.GetType().GetMethod(nameof(IJob.FallbackAsync)
, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly , BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly
, null , null
, new[] { typeof(JobExecutedContext), typeof(CancellationToken) } , new[] { typeof(JobExecutedContext), typeof(CancellationToken) }

View File

@@ -101,7 +101,7 @@ public class HttpJob : IJob
} }
// 添加请求头 // 添加请求头
if (httpJobMessage.Headers != null && httpJobMessage.Headers.Count > 0) if (httpJobMessage.Headers?.Count > 0)
{ {
foreach (var (name, value) in httpJobMessage.Headers) foreach (var (name, value) in httpJobMessage.Headers)
{ {

View File

@@ -711,7 +711,7 @@ public static class SpecificationDocumentBuilder
.Union( .Union(
actions.SelectMany(u => GetActionGroups(u)) actions.SelectMany(u => GetActionGroups(u))
) )
.Where(u => u != null && u.Visible) .Where(u => u?.Visible == true)
// 分组后取最大排序 // 分组后取最大排序
.GroupBy(u => u.Group) .GroupBy(u => u.Group)
.Select(u => new GroupExtraInfo .Select(u => new GroupExtraInfo

View File

@@ -47,7 +47,7 @@ public static class TP
} }
// 添加项 // 添加项
if (items != null && items.Length > 0) if (items?.Length > 0)
{ {
var propMaxLength = items.Where(u => _lazyRegex.Value.IsMatch(u)) var propMaxLength = items.Where(u => _lazyRegex.Value.IsMatch(u))
.DefaultIfEmpty(string.Empty) .DefaultIfEmpty(string.Empty)

View File

@@ -39,7 +39,7 @@
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" /> <PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="Mapster" Version="7.4.0" /> <PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" /> <PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.3" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.4" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' "> <ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">

View File

@@ -343,7 +343,7 @@ public partial class Crontab
// 如果存在且唯一,则进入下一轮判断 // 如果存在且唯一,则进入下一轮判断
// 接下来的判断是处理 SUN + L 的情况,如 SUNL == 0L == SUNDAY它们都是合法的 Cron 值 // 接下来的判断是处理 SUN + L 的情况,如 SUNL == 0L == SUNDAY它们都是合法的 Cron 值
if (replaceVal != null && replaceVal.Count == 1) if (replaceVal?.Count == 1)
{ {
var missingParser = ""; var missingParser = "";

View File

@@ -140,10 +140,10 @@ public static class UnifyContext
if (unifyResultSettings == null) return; if (unifyResultSettings == null) return;
// 篡改响应状态码 // 篡改响应状态码
if (unifyResultSettings.AdaptStatusCodes != null && unifyResultSettings.AdaptStatusCodes.Length > 0) if (unifyResultSettings.AdaptStatusCodes?.Length > 0)
{ {
var adaptStatusCode = unifyResultSettings.AdaptStatusCodes.FirstOrDefault(u => u[0] == statusCode); var adaptStatusCode = unifyResultSettings.AdaptStatusCodes.FirstOrDefault(u => u[0] == statusCode);
if (adaptStatusCode != null && adaptStatusCode.Length > 0 && adaptStatusCode[0] > 0) if (adaptStatusCode?.Length > 0 && adaptStatusCode[0] > 0)
{ {
context.Response.StatusCode = adaptStatusCode[1]; context.Response.StatusCode = adaptStatusCode[1];
return; return;

View File

@@ -139,8 +139,7 @@ internal static class TypeExtensions
} }
// 类型限定名是否以 <> 开头且以 AnonymousType 结尾 // 类型限定名是否以 <> 开头且以 AnonymousType 结尾
return type.FullName is not null return type.FullName?.StartsWith("<>") == true
&& type.FullName.StartsWith("<>")
&& type.FullName.Contains("AnonymousType"); && type.FullName.Contains("AnonymousType");
} }
@@ -463,7 +462,7 @@ internal static class TypeExtensions
var elementType = type.GetElementType(); var elementType = type.GetElementType();
// 检查元素类型是否是 KeyValuePair<,> 类型 // 检查元素类型是否是 KeyValuePair<,> 类型
if (elementType is null || !elementType.IsKeyValuePair()) if (elementType?.IsKeyValuePair() != true)
{ {
return false; return false;
} }

View File

@@ -135,7 +135,7 @@ internal static class V5_ObjectExtensions
var runtimeProperty = obj.GetType().GetRuntimeProperty("Count"); var runtimeProperty = obj.GetType().GetRuntimeProperty("Count");
// 反射获取 Count 属性值 // 反射获取 Count 属性值
if (runtimeProperty is not null && runtimeProperty.CanRead && runtimeProperty.PropertyType == typeof(int)) if (runtimeProperty?.CanRead == true && runtimeProperty.PropertyType == typeof(int))
{ {
count = (int)runtimeProperty.GetValue(obj)!; count = (int)runtimeProperty.GetValue(obj)!;
return true; return true;
@@ -332,7 +332,7 @@ internal static class V5_ObjectExtensions
var property = current.GetType().GetProperty(part, bindingFlags); var property = current.GetType().GetProperty(part, bindingFlags);
// 空检查 // 空检查
if (property is null || !property.CanRead) if (property?.CanRead != true)
{ {
return null; return null;
} }

View File

@@ -1591,7 +1591,7 @@ public sealed partial class HttpRequestBuilder
public HttpRequestBuilder SetBaseAddress(Uri? baseAddress) public HttpRequestBuilder SetBaseAddress(Uri? baseAddress)
{ {
// 检查基地址是否是绝对路径地址 // 检查基地址是否是绝对路径地址
if (baseAddress is not null && !baseAddress.IsAbsoluteUri) if (baseAddress?.IsAbsoluteUri == false)
{ {
throw new ArgumentException("The base address must be absolute.", nameof(baseAddress)); throw new ArgumentException("The base address must be absolute.", nameof(baseAddress));
} }

View File

@@ -136,7 +136,7 @@ public partial class Clay
{ {
handler(this, new ClayEventArgs(identifier, Contains(identifier))); handler(this, new ClayEventArgs(identifier, Contains(identifier)));
} }
catch (Exception) catch
{ {
// ignored // ignored
} }

View File

@@ -177,15 +177,6 @@ public partial class Clay
enumerableClay = this; enumerableClay = this;
} }
/// <summary>
/// </summary>
/// <param name="clay">dynamic 类型的 <see cref="Clay" /></param>
/// <param name="enumerableClay">
/// <see cref="IEnumerable{T}" />
/// </param>
/// <param name="rawClay">
/// <see cref="Clay" />
/// </param>
public void Deconstruct(out dynamic clay, out IEnumerable<dynamic?> enumerableClay, out Clay rawClay) public void Deconstruct(out dynamic clay, out IEnumerable<dynamic?> enumerableClay, out Clay rawClay)
{ {
clay = this; clay = this;
@@ -888,7 +879,7 @@ public partial class Clay
foreach (var item in values) foreach (var item in values)
{ {
// 检查值是否为空值或基本类型的值 // 检查值是否为空值或基本类型的值
if (item is null || item.GetType().IsBasicType()) if (item?.GetType().IsBasicType() != false)
{ {
throw new InvalidOperationException("Cannot extend a single object with null or basic type values."); throw new InvalidOperationException("Cannot extend a single object with null or basic type values.");
} }

View File

@@ -12,9 +12,11 @@ using System.ComponentModel.DataAnnotations;
namespace ThingsGateway; namespace ThingsGateway;
/// <summary> /// <summary>
/// 最小值校验 /// 最小值校验
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class MinValueAttribute : ValidationAttribute public sealed class MinValueAttribute : ValidationAttribute
{ {
/// <summary> /// <summary>

View File

@@ -244,7 +244,6 @@ public ref struct SpanReader
while (true) while (true)
{ {
var bt = ReadByte(); var bt = ReadByte();
if (bt < 0) throw new Exception($"The data stream is out of range! The integer read is {rs: n0}");
b = (Byte)bt; b = (Byte)bt;
// 必须转为Int32否则可能溢出 // 必须转为Int32否则可能溢出

View File

@@ -120,7 +120,7 @@ public class MemoryCache : Cache
/// <summary>是否包含缓存项</summary> /// <summary>是否包含缓存项</summary>
/// <param name="key"></param> /// <param name="key"></param>
/// <returns></returns> /// <returns></returns>
public override Boolean ContainsKey(String key) => _cache.TryGetValue(key, out var item) && item != null && !item.Expired; public override Boolean ContainsKey(String key) => _cache.TryGetValue(key, out var item) && item?.Expired == false;
/// <summary>添加缓存项,已存在时更新</summary> /// <summary>添加缓存项,已存在时更新</summary>
/// <typeparam name="T">值类型</typeparam> /// <typeparam name="T">值类型</typeparam>
@@ -166,7 +166,7 @@ public class MemoryCache : Cache
[return: MaybeNull] [return: MaybeNull]
public override T Get<T>(String key) public override T Get<T>(String key)
{ {
if (!_cache.TryGetValue(key, out var item) || item == null || item.Expired) return default; if (!_cache.TryGetValue(key, out var item) || item?.Expired != false) return default;
return item.Visit<T>(); return item.Visit<T>();
} }
@@ -712,7 +712,7 @@ public class MemoryCache : Cache
for (var i = 0; i < slist.Count && over > 0; i++) for (var i = 0; i < slist.Count && over > 0; i++)
{ {
var ss = slist.Values[i]; var ss = slist.Values[i];
if (ss != null && ss.Count > 0) if (ss?.Count > 0)
{ {
foreach (var item in ss) foreach (var item in ss)
{ {

View File

@@ -402,7 +402,7 @@ public class ObjectPool<T> : DisposeBase, IPool<T> where T : notnull
/// <param name="args"></param> /// <param name="args"></param>
public void WriteLog(String format, params Object?[] args) public void WriteLog(String format, params Object?[] args)
{ {
if (Log == null || !Log.Enable) return; if (Log?.Enable != true) return;
Log.Info(Name + "." + format, args); Log.Info(Name + "." + format, args);
} }

View File

@@ -15,7 +15,7 @@ namespace ThingsGateway.NewLife;
/// <summary> /// <summary>
/// FileUtil /// FileUtil
/// </summary> /// </summary>
public class FileUtil public static class FileUtil
{ {
/// <summary> /// <summary>
/// 读取文件 /// 读取文件

View File

@@ -633,7 +633,7 @@ public class MachineInfo
if (!_excludes.Contains(nameof(Temperature))) if (!_excludes.Contains(nameof(Temperature)))
{ {
var temp = ReadWmic(@"/namespace:\\root\wmi path MSAcpi_ThermalZoneTemperature", "CurrentTemperature"); var temp = ReadWmic(@"/namespace:\\root\wmi path MSAcpi_ThermalZoneTemperature", "CurrentTemperature");
if (temp != null && temp.Count > 0) if (temp?.Count > 0)
{ {
if (temp.TryGetValue("CurrentTemperature", out var str) && !str.IsNullOrEmpty()) if (temp.TryGetValue("CurrentTemperature", out var str) && !str.IsNullOrEmpty())
Temperature = (str.SplitAsInt().Average() - 2732) / 10.0; Temperature = (str.SplitAsInt().Average() - 2732) / 10.0;
@@ -651,7 +651,7 @@ public class MachineInfo
else if (!_excludes.Contains(nameof(Battery))) else if (!_excludes.Contains(nameof(Battery)))
{ {
var battery = ReadWmic("path win32_battery", "EstimatedChargeRemaining"); var battery = ReadWmic("path win32_battery", "EstimatedChargeRemaining");
if (battery != null && battery.Count > 0) if (battery?.Count > 0)
{ {
if (battery.TryGetValue("EstimatedChargeRemaining", out var str) && !str.IsNullOrEmpty()) if (battery.TryGetValue("EstimatedChargeRemaining", out var str) && !str.IsNullOrEmpty())
Battery = str.SplitAsInt().Average() / 100.0; Battery = str.SplitAsInt().Average() / 100.0;
@@ -937,7 +937,7 @@ public class MachineInfo
foreach (var item in ss) foreach (var item in ss)
{ {
var ks = item?.Split('='); var ks = item?.Split('=');
if (ks != null && ks.Length >= 2) if (ks?.Length >= 2)
{ {
var k = ks[0].Trim(); var k = ks[0].Trim();
var v = ks[1].Trim().TrimInvisible(); var v = ks[1].Trim().TrimInvisible();
@@ -1079,7 +1079,7 @@ public class MachineInfo
if (root.IsNullOrEmpty()) return 0; if (root.IsNullOrEmpty()) return 0;
var driveInfo = new DriveInfo(root); var driveInfo = new DriveInfo(root);
if (driveInfo == null || !driveInfo.IsReady) return -1; if (driveInfo?.IsReady != true) return -1;
try try
{ {

View File

@@ -6,7 +6,7 @@ namespace ThingsGateway.NewLife.Common;
/// <remarks> /// <remarks>
/// 文档 https://newlifex.com/core/pinyin /// 文档 https://newlifex.com/core/pinyin
/// </remarks> /// </remarks>
public class PinYin public static class PinYin
{ {
#region #region
private static readonly Int32[] pyValue = new[] { private static readonly Int32[] pyValue = new[] {

View File

@@ -199,7 +199,7 @@ public static class Runtime
if (processId != ProcessId) gc = false; if (processId != ProcessId) gc = false;
var log = XTrace.Log; var log = XTrace.Log;
if (log != null && log.Enable && log.Level <= LogLevel.Debug) if (log?.Enable == true && log.Level <= LogLevel.Debug)
{ {
p ??= Process.GetCurrentProcess(); p ??= Process.GetCurrentProcess();
var gcm = GC.GetTotalMemory(false) / 1024; var gcm = GC.GetTotalMemory(false) / 1024;
@@ -243,7 +243,7 @@ public static class Runtime
} }
} }
if (log != null && log.Enable && log.Level <= LogLevel.Debug) if (log?.Enable == true && log.Level <= LogLevel.Debug)
{ {
p ??= Process.GetProcessById(processId); p ??= Process.GetProcessById(processId);
p.Refresh(); p.Refresh();

View File

@@ -108,7 +108,7 @@ public static class ConfigHelper
dic[cfg.Key] = cfg.Value; dic[cfg.Key] = cfg.Value;
if (cfg.Childs != null && cfg.Childs.Count > 0) if (cfg.Childs?.Count > 0)
dic[cfg.Key] = cfg.Childs; dic[cfg.Key] = cfg.Childs;
} }

View File

@@ -54,6 +54,6 @@ public class ConfigSection : IConfigSection
/// <summary>已重载。</summary> /// <summary>已重载。</summary>
/// <returns></returns> /// <returns></returns>
public override String ToString() => Childs != null && Childs.Count > 0 ? $"{Key}[{Childs.Count}]" : $"{Key}={Value}"; public override String ToString() => Childs?.Count > 0 ? $"{Key}[{Childs.Count}]" : $"{Key}={Value}";
#endregion #endregion
} }

View File

@@ -75,7 +75,7 @@ public class InIConfigProvider : FileConfigProvider
var sb = new StringBuilder(); var sb = new StringBuilder();
foreach (var item in section.Childs.ToArray()) foreach (var item in section.Childs.ToArray())
{ {
if (item.Childs != null && item.Childs.Count > 0) if (item.Childs?.Count > 0)
{ {
// 段前空一行 // 段前空一行
sb.AppendLine(); sb.AppendLine();

View File

@@ -41,7 +41,7 @@ public class WeakAction<TArgs>
var target = Target; var target = Target;
if (target == null && Method.IsStatic) return true; if (target == null && Method.IsStatic) return true;
return target != null && target.IsAlive; return target?.IsAlive == true;
} }
} }
#endregion #endregion

View File

@@ -65,7 +65,7 @@ public static class DateExtensions
/// <param name="beginTime">开始时间</param> /// <param name="beginTime">开始时间</param>
/// <param name="endTime">结束时间</param> /// <param name="endTime">结束时间</param>
/// <returns>时间差</returns> /// <returns>时间差</returns>
public static string GetDiffTime(this in DateTime beginTime, in DateTime endTime) public static string GetDiffTime(this DateTime beginTime, DateTime endTime)
{ {
TimeSpan timeDifference = endTime - beginTime; TimeSpan timeDifference = endTime - beginTime;
if (timeDifference.TotalDays >= 1) if (timeDifference.TotalDays >= 1)
@@ -88,7 +88,7 @@ public static class DateExtensions
/// <param name="beginTime">开始时间</param> /// <param name="beginTime">开始时间</param>
/// <param name="endTime">结束时间</param> /// <param name="endTime">结束时间</param>
/// <returns>时间差</returns> /// <returns>时间差</returns>
public static string GetDiffTime(this in DateTimeOffset beginTime, in DateTimeOffset endTime) public static string GetDiffTime(this DateTimeOffset beginTime, DateTimeOffset endTime)
{ {
TimeSpan timeDifference = endTime - beginTime; TimeSpan timeDifference = endTime - beginTime;
if (timeDifference.TotalDays >= 1) if (timeDifference.TotalDays >= 1)
@@ -108,7 +108,7 @@ public static class DateExtensions
/// <summary> /// <summary>
/// 返回yyyy-MM-ddTHH:mm:ss.fffffffzzz时间格式字符串 /// 返回yyyy-MM-ddTHH:mm:ss.fffffffzzz时间格式字符串
/// </summary> /// </summary>
public static string ToDefaultDateTimeFormat(this in DateTime dt, TimeSpan offset) public static string ToDefaultDateTimeFormat(this DateTime dt, TimeSpan offset)
{ {
if (dt.Kind == DateTimeKind.Utc) if (dt.Kind == DateTimeKind.Utc)
return new DateTimeOffset(dt.ToLocalTime(), offset).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz"); return new DateTimeOffset(dt.ToLocalTime(), offset).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz");
@@ -129,7 +129,7 @@ public static class DateExtensions
/// <summary> /// <summary>
/// 返回yyyy-MM-ddTHH:mm:ss.fffffffzzz时间格式字符串 /// 返回yyyy-MM-ddTHH:mm:ss.fffffffzzz时间格式字符串
/// </summary> /// </summary>
public static string ToDefaultDateTimeFormat(this in DateTime dt) public static string ToDefaultDateTimeFormat(this DateTime dt)
{ {
return dt.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz"); return dt.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz");
} }
@@ -137,7 +137,7 @@ public static class DateExtensions
/// <summary> /// <summary>
/// 返回yyyy-MM-dd HH-mm-ss-fff zz时间格式字符串 /// 返回yyyy-MM-dd HH-mm-ss-fff zz时间格式字符串
/// </summary> /// </summary>
public static string ToFileDateTimeFormat(this in DateTime dt) public static string ToFileDateTimeFormat(this DateTime dt)
{ {
return ToDefaultDateTimeFormat(dt).Replace(":", "-"); return ToDefaultDateTimeFormat(dt).Replace(":", "-");
} }
@@ -145,7 +145,7 @@ public static class DateExtensions
/// <summary> /// <summary>
/// 返回yyyy-MM-dd HH-mm-ss-fff zz时间格式字符串 /// 返回yyyy-MM-dd HH-mm-ss-fff zz时间格式字符串
/// </summary> /// </summary>
public static string ToFileDateTimeFormat(this in DateTime dt, TimeSpan offset) public static string ToFileDateTimeFormat(this DateTime dt, TimeSpan offset)
{ {
return ToDefaultDateTimeFormat(dt, offset).Replace(":", "-"); return ToDefaultDateTimeFormat(dt, offset).Replace(":", "-");
} }

View File

@@ -6,31 +6,18 @@ namespace ThingsGateway.NewLife.Extension;
/// <summary>网络结点扩展</summary> /// <summary>网络结点扩展</summary>
public static class EndPointExtensions public static class EndPointExtensions
{ {
/// <summary>
///
/// </summary>
/// <param name="endpoint"></param>
/// <returns></returns>
public static String ToAddress(this EndPoint endpoint) public static String ToAddress(this EndPoint endpoint)
{ {
return ((IPEndPoint)endpoint).ToAddress(); return ((IPEndPoint)endpoint).ToAddress();
} }
/// <summary>
///
/// </summary>
/// <param name="endpoint"></param>
/// <returns></returns>
public static String ToAddress(this IPEndPoint endpoint) public static String ToAddress(this IPEndPoint endpoint)
{ {
return String.Format("{0}:{1}", endpoint.Address, endpoint.Port); return String.Format("{0}:{1}", endpoint.Address, endpoint.Port);
} }
private static readonly String[] SplitColon = new String[] { ":" }; private static readonly String[] SplitColon = new String[] { ":" };
/// <summary>
///
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public static IPEndPoint ToEndPoint(this String address) public static IPEndPoint ToEndPoint(this String address)
{ {
var array = address.Split(SplitColon, StringSplitOptions.RemoveEmptyEntries); var array = address.Split(SplitColon, StringSplitOptions.RemoveEmptyEntries);
@@ -44,11 +31,7 @@ public static class EndPointExtensions
} }
private static readonly String[] SplitComma = new String[] { "," }; private static readonly String[] SplitComma = new String[] { "," };
/// <summary>
///
/// </summary>
/// <param name="addresses"></param>
/// <returns></returns>
public static IEnumerable<IPEndPoint> ToEndPoints(this String addresses) public static IEnumerable<IPEndPoint> ToEndPoints(this String addresses)
{ {
var array = addresses.Split(SplitComma, StringSplitOptions.RemoveEmptyEntries); var array = addresses.Split(SplitComma, StringSplitOptions.RemoveEmptyEntries);

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