mirror of
https://github.com/nsnail/NetAdmin.git
synced 2025-06-20 02:38:15 +08:00
feat: ✨ 框架代码同步 (#158)
[skip ci] Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
using Microsoft.IdentityModel.Logging;
|
||||
using NetAdmin.AdmServer.Host;
|
||||
using NetAdmin.AdmServer.Host.Extensions;
|
||||
using NetAdmin.Host.Extensions;
|
||||
@ -78,8 +79,9 @@ namespace NetAdmin.AdmServer.Host
|
||||
public Task<int> Execute(CommandContext context, CommandLineArgs settings)
|
||||
#pragma warning restore ASA001
|
||||
{
|
||||
Args = settings;
|
||||
_ = Serve.Run(RunOptions.Default.WithArgs(context.Remaining.Raw.ToArray()));
|
||||
Args = settings;
|
||||
IdentityModelEventSource.ShowPII = true;
|
||||
_ = Serve.Run(RunOptions.Default.WithArgs(context.Remaining.Raw.ToArray()));
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
|
@ -979,7 +979,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1075,7 +1075,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1083,7 +1083,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1099,7 +1099,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1107,8 +1107,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@ -1116,7 +1115,7 @@ public class AllTests(WebApplicationFactory<Startup> factory, ITestOutputHelper
|
||||
/// <inheritdoc />
|
||||
[InlineData(default)]
|
||||
[Theory]
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
@ -30,6 +30,46 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
||||
set => Rpo.DbContextOptions.EnableCascadeSave = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出实体
|
||||
/// </summary>
|
||||
protected async Task<IActionResult> ExportAsync<TQuery, TExport>( //
|
||||
Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> query, string fileName
|
||||
, Expression<Func<TEntity, object>> listExp = null)
|
||||
where TQuery : DataAbstraction, new()
|
||||
{
|
||||
var select = selector(query)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.Take(Numbers.MAX_LIMIT_EXPORT);
|
||||
|
||||
object list = listExp == null
|
||||
? await select.ToListAsync().ConfigureAwait(false)
|
||||
: await select.ToListAsync(listExp).ConfigureAwait(false);
|
||||
|
||||
var listTyped = list.Adapt<List<TExport>>();
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
||||
csv.WriteHeader<TExport>();
|
||||
await csv.NextRecordAsync().ConfigureAwait(false);
|
||||
|
||||
foreach (var item in listTyped) {
|
||||
csv.WriteRecord(item);
|
||||
await csv.NextRecordAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await csv.FlushAsync().ConfigureAwait(false);
|
||||
_ = stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
App.HttpContext.Response.Headers.ContentDisposition
|
||||
= new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) {
|
||||
FileNameStar = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv"
|
||||
}.ToString();
|
||||
return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新实体
|
||||
/// </summary>
|
||||
@ -77,43 +117,6 @@ public abstract class RepositoryService<TEntity, TPrimary, TLogger>(BasicReposit
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 导出实体
|
||||
/// </summary>
|
||||
protected async Task<IActionResult> ExportAsync<TQuery, TExport>( //
|
||||
Func<QueryReq<TQuery>, ISelect<TEntity>> selector, QueryReq<TQuery> query, string fileName)
|
||||
where TQuery : DataAbstraction, new()
|
||||
{
|
||||
var data = await selector(query)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.Take(Numbers.MAX_LIMIT_EXPORT)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var list = data.Adapt<List<TExport>>();
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
||||
csv.WriteHeader<TExport>();
|
||||
await csv.NextRecordAsync().ConfigureAwait(false);
|
||||
|
||||
foreach (var item in list) {
|
||||
csv.WriteRecord(item);
|
||||
await csv.NextRecordAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await csv.FlushAsync().ConfigureAwait(false);
|
||||
_ = stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
App.HttpContext.Response.Headers.ContentDisposition
|
||||
= new ContentDispositionHeaderValue(Chars.FLG_HTTP_HEADER_VALUE_ATTACHMENT) {
|
||||
FileNameStar = $"{fileName}_{DateTime.Now:yyyy.MM.dd-HH.mm.ss}.csv"
|
||||
}.ToString();
|
||||
return new FileStreamResult(stream, Chars.FLG_HTTP_HEADER_VALUE_APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
|
||||
private IUpdate<TEntity> BuildUpdate( //
|
||||
TEntity entity //
|
||||
, IEnumerable<string> includeFields //
|
||||
|
@ -70,7 +70,8 @@ public abstract class DistributedCache<TService>(IDistributedCache cache, TServi
|
||||
, TimeSpan? slideLifeTime = null)
|
||||
{
|
||||
var cacheRead = await GetAsync<T>(key).ConfigureAwait(false);
|
||||
if (cacheRead is not null) {
|
||||
if (cacheRead is not null && App.HttpContext?.Request.Headers.CacheControl.FirstOrDefault() !=
|
||||
Chars.FLG_HTTP_HEADER_VALUE_NO_CACHE) {
|
||||
return cacheRead;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,12 @@ namespace NetAdmin.Domain.Contexts;
|
||||
/// </summary>
|
||||
public sealed record ContextUserToken : DataAbstraction
|
||||
{
|
||||
/// <summary>
|
||||
/// 部门编号
|
||||
/// </summary>
|
||||
/// ReSharper disable once MemberCanBePrivate.Global
|
||||
public long DeptId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户编号
|
||||
/// </summary>
|
||||
@ -39,6 +45,8 @@ public sealed record ContextUserToken : DataAbstraction
|
||||
/// </summary>
|
||||
public static ContextUserToken Create(QueryUserRsp user)
|
||||
{
|
||||
return new ContextUserToken { Id = user.Id, Token = user.Token, UserName = user.UserName };
|
||||
return new ContextUserToken {
|
||||
Id = user.Id, Token = user.Token, UserName = user.UserName, DeptId = user.DeptId
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
|
||||
|
||||
/// <summary>
|
||||
/// 创建者客户端IP字段接口
|
||||
/// </summary>
|
||||
public interface IFieldCreatedClientIp
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建者客户端IP
|
||||
/// </summary>
|
||||
int? CreatedClientIp { get; init; }
|
||||
}
|
@ -1,15 +1,10 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
|
||||
|
||||
/// <summary>
|
||||
/// 创建者客户端字段接口
|
||||
/// 创建者客户端用户代理字段接口
|
||||
/// </summary>
|
||||
public interface IFieldCreatedClient
|
||||
public interface IFieldCreatedClientUserAgent
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建者客户端IP
|
||||
/// </summary>
|
||||
int? CreatedClientIp { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建者客户端用户代理
|
||||
/// </summary>
|
@ -0,0 +1,12 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
|
||||
|
||||
/// <summary>
|
||||
/// 修改客户端IP字段接口
|
||||
/// </summary>
|
||||
public interface IFieldModifiedClientIp
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端IP
|
||||
/// </summary>
|
||||
int ModifiedClientIp { get; init; }
|
||||
}
|
@ -1,15 +1,10 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Dependency.Fields;
|
||||
|
||||
/// <summary>
|
||||
/// 修改客户端字段接口
|
||||
/// 修改客户端用户代理字段接口
|
||||
/// </summary>
|
||||
public interface IFieldModifiedClient
|
||||
public interface IFieldModifiedClientUserAgent
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端IP
|
||||
/// </summary>
|
||||
int ModifiedClientIp { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端用户代理
|
||||
/// </summary>
|
@ -4,6 +4,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
/// Api接口表
|
||||
/// </summary>
|
||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_Api))]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(PathCrc32), nameof(PathCrc32), true)]
|
||||
public record Sys_Api : ImmutableEntity<string>, IFieldSummary
|
||||
{
|
||||
/// <summary>
|
||||
@ -54,6 +55,14 @@ public record Sys_Api : ImmutableEntity<string>, IFieldSummary
|
||||
[JsonIgnore]
|
||||
public virtual string ParentId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 路径CRC32
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public int PathCrc32 { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色集合
|
||||
/// </summary>
|
||||
|
@ -18,7 +18,7 @@ public record Sys_DicCatalog : VersionEntity
|
||||
/// <summary>
|
||||
/// 字典编码
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string Code { get; init; }
|
||||
@ -34,7 +34,7 @@ public record Sys_DicCatalog : VersionEntity
|
||||
/// <summary>
|
||||
/// 字典名称
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string Name { get; init; }
|
||||
|
@ -4,8 +4,6 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
/// 字典内容表
|
||||
/// </summary>
|
||||
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(CatalogId)}_{nameof(Key)}", $"{nameof(CatalogId)},{nameof(Key)}", true)]
|
||||
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(CatalogId)}_{nameof(Value)}", $"{nameof(CatalogId)},{nameof(Value)}"
|
||||
, true)]
|
||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_DicContent))]
|
||||
public record Sys_DicContent : VersionEntity
|
||||
{
|
||||
|
@ -79,6 +79,22 @@ public record Sys_Job : VersionEntity, IFieldEnabled, IFieldSummary
|
||||
[JsonIgnore]
|
||||
public virtual long? NextTimeId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 随机延时起始值(毫秒)
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int? RandomDelayBegin { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 随机延时结束值(毫秒)
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int? RandomDelayEnd { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求体
|
||||
/// </summary>
|
||||
|
@ -6,7 +6,7 @@ namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
/// 计划作业执行记录表
|
||||
/// </summary>
|
||||
[SqlIndex($"{Chars.FLG_DB_INDEX_PREFIX}{nameof(JobId)}_{nameof(TimeId)}", $"{nameof(JobId)},{nameof(TimeId)}", true)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), nameof(CreatedTime), false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), $"{nameof(CreatedTime)} DESC", false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(JobId), nameof(JobId), false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_JobRecord))]
|
||||
|
@ -1,36 +1,38 @@
|
||||
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
|
||||
|
||||
namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志表
|
||||
/// </summary>
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(ApiId), nameof(ApiId), false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), nameof(CreatedTime), false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(UserId), nameof(UserId), false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(ApiPathCrc32), nameof(ApiPathCrc32), false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(CreatedTime), $"{nameof(CreatedTime)} DESC", false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(OwnerId), nameof(OwnerId), false)]
|
||||
[SqlIndex(Chars.FLG_DB_INDEX_PREFIX + nameof(HttpStatusCode), nameof(HttpStatusCode), false)]
|
||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLog))]
|
||||
public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldCreatedClient
|
||||
public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldOwner, IFieldCreatedClientIp
|
||||
{
|
||||
/// <summary>
|
||||
/// 接口
|
||||
/// </summary>
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
[Navigate(nameof(ApiId))]
|
||||
[Navigate(nameof(ApiPathCrc32), TempPrimary = nameof(Sys_Api.PathCrc32))]
|
||||
public Sys_Api Api { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 接口编号
|
||||
/// 接口路径CRC32
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ApiId { get; init; }
|
||||
public virtual int ApiPathCrc32 { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Column(Position = -1)]
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public int? CreatedClientIp { get; init; }
|
||||
public virtual int? CreatedClientIp { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false, Position = -1)]
|
||||
@ -38,161 +40,55 @@ public record Sys_RequestLog : SimpleEntity, IFieldCreatedTime, IFieldCreatedCli
|
||||
[JsonIgnore]
|
||||
public virtual DateTime CreatedTime { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_1022)]
|
||||
#else
|
||||
[Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 明细
|
||||
/// </summary>
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string CreatedUserAgent { get; init; }
|
||||
[Navigate(nameof(Id))]
|
||||
public Sys_RequestLogDetail Detail { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行耗时(微秒)
|
||||
/// 执行耗时(毫秒)
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual long Duration { get; init; }
|
||||
public virtual int Duration { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序响应码
|
||||
/// 请求方法
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_TINY_INT)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual ErrorCodes ErrorCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 异常信息
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string Exception { get; init; }
|
||||
public virtual HttpMethods HttpMethod { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP状态码
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_SMALL_INT)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int HttpStatusCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求方法
|
||||
/// 拥有者
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_15)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string Method { get; init; }
|
||||
[Navigate(nameof(OwnerId))]
|
||||
public Sys_User Owner { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求内容
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestBody { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求content-type
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestContentType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求头信息
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestHeaders { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求地址
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应内容
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ResponseBody { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应content-type
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ResponseContentType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应头
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ResponseHeaders { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务器IP
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int? ServerIp { get; init; }
|
||||
public virtual long? OwnerDeptId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求跟踪标识
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string TraceId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户
|
||||
/// </summary>
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
[Navigate(nameof(UserId))]
|
||||
public Sys_User User { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户编号
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual long? UserId { get; init; }
|
||||
public virtual long? OwnerId { get; init; }
|
||||
}
|
132
src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLogDetail.cs
Normal file
132
src/backend/NetAdmin.Domain/DbMaps/Sys/Sys_RequestLogDetail.cs
Normal file
@ -0,0 +1,132 @@
|
||||
namespace NetAdmin.Domain.DbMaps.Sys;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志明细表
|
||||
/// </summary>
|
||||
[Table(Name = Chars.FLG_DB_TABLE_NAME_PREFIX + nameof(Sys_RequestLogDetail))]
|
||||
public record Sys_RequestLogDetail : SimpleEntity, IFieldCreatedTime, IFieldCreatedClientUserAgent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false, Position = -1)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual DateTime CreatedTime { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_1022)]
|
||||
#else
|
||||
[Column(Position = -1, DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string CreatedUserAgent { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 程序响应码
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual ErrorCodes ErrorCode { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 异常信息
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string Exception { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求内容
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestBody { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求content-type
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestContentType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求头信息
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestHeaders { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求地址
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_127)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string RequestUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应内容
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ResponseBody { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应content-type
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ResponseContentType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 响应头
|
||||
/// </summary>
|
||||
#if DBTYPE_SQLSERVER
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_MAX)]
|
||||
#else
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
|
||||
#endif
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string ResponseHeaders { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务器IP
|
||||
/// </summary>
|
||||
[Column]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual int? ServerIp { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求跟踪标识
|
||||
/// </summary>
|
||||
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_31)]
|
||||
[Ignore]
|
||||
[JsonIgnore]
|
||||
public virtual string TraceId { get; init; }
|
||||
}
|
@ -37,6 +37,42 @@ public sealed record DynamicFilterInfo : DataAbstraction
|
||||
/// </summary>
|
||||
public static implicit operator FreeSql.Internal.Model.DynamicFilterInfo(DynamicFilterInfo d)
|
||||
{
|
||||
return d.Adapt<FreeSql.Internal.Model.DynamicFilterInfo>();
|
||||
var ret = d.Adapt<FreeSql.Internal.Model.DynamicFilterInfo>();
|
||||
ProcessDynamicFilter(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void ProcessDynamicFilter(FreeSql.Internal.Model.DynamicFilterInfo d)
|
||||
{
|
||||
if (d?.Filters != null) {
|
||||
foreach (var filterInfo in d.Filters) {
|
||||
ProcessDynamicFilter(filterInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (d?.Operator != DynamicFilterOperator.DateRange) {
|
||||
return;
|
||||
}
|
||||
|
||||
var values = ((JsonElement)d.Value).Deserialize<string[]>();
|
||||
if (!DateTime.TryParse(values[0], CultureInfo.InvariantCulture, out _)) {
|
||||
var result = values[0]
|
||||
.ExecuteCSharpCodeAsync<DateTime>([typeof(DateTime).Assembly], nameof(System))
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
values[0] = $"{result:yyyy-MM-dd HH:mm:ss}";
|
||||
}
|
||||
|
||||
if (!DateTime.TryParse(values[1], CultureInfo.InvariantCulture, out _)) {
|
||||
var result = values[1]
|
||||
.ExecuteCSharpCodeAsync<DateTime>([typeof(DateTime).Assembly], nameof(System))
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
values[1] = $"{result:yyyy-MM-dd HH:mm:ss}";
|
||||
}
|
||||
|
||||
d.Value = values;
|
||||
}
|
||||
}
|
@ -32,6 +32,14 @@ public record CreateJobReq : Sys_Job
|
||||
/// <inheritdoc />
|
||||
public override long? NextTimeId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Range(1, int.MaxValue, ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.随机延时起始时间不正确))]
|
||||
public override int? RandomDelayBegin { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Range(1, int.MaxValue, ErrorMessageResourceType = typeof(Ln), ErrorMessageResourceName = nameof(Ln.随机延时结束时间不正确))]
|
||||
public override int? RandomDelayEnd { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_Job.RequestBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestBody { get; init; }
|
||||
|
@ -90,6 +90,14 @@ public record QueryJobRsp : Sys_Job
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override long? NextTimeId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override int? RandomDelayBegin { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override int? RandomDelayEnd { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_Job.RequestBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestBody { get; init; }
|
||||
|
@ -1,6 +1,12 @@
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLog;
|
||||
|
||||
/// <summary>
|
||||
/// 请求:创建请求日志
|
||||
/// </summary>
|
||||
public sealed record CreateRequestLogReq : Sys_RequestLog;
|
||||
public sealed record CreateRequestLogReq : Sys_RequestLog
|
||||
{
|
||||
/// <inheritdoc cref="Sys_RequestLog.Detail" />
|
||||
public new CreateRequestLogDetailReq Detail { get; init; }
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
using NetAdmin.Domain.Dto.Sys.Api;
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
using NetAdmin.Domain.Dto.Sys.User;
|
||||
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
|
||||
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLog;
|
||||
|
||||
@ -7,39 +10,51 @@ namespace NetAdmin.Domain.Dto.Sys.RequestLog;
|
||||
/// </summary>
|
||||
public record ExportRequestLogRsp : QueryRequestLogRsp
|
||||
{
|
||||
/// <summary>
|
||||
/// 接口路径
|
||||
/// </summary>
|
||||
[CsvIndex(2)]
|
||||
[JsonInclude]
|
||||
[Name(nameof(Ln.接口路径))]
|
||||
public string ApiId => Api.Id;
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(6)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.客户端IP))]
|
||||
public override string CreatedClientIp => base.CreatedClientIp;
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
[CsvIndex(5)]
|
||||
[JsonInclude]
|
||||
[Name(nameof(Ln.用户名))]
|
||||
public string UserName => Owner?.UserName;
|
||||
|
||||
/// <inheritdoc />
|
||||
[Ignore]
|
||||
public override string LoginName => base.LoginName;
|
||||
public override QueryApiRsp Api { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(7)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.操作系统))]
|
||||
public override string Os => base.Os;
|
||||
[Ignore]
|
||||
public override DateTime CreatedTime { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(2)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.接口路径))]
|
||||
public override string ApiId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(8)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.用户代理))]
|
||||
public override string CreatedUserAgent { get; init; }
|
||||
[Ignore]
|
||||
public override QueryRequestLogDetailRsp Detail { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(4)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.执行耗时))]
|
||||
public override long Duration { get; init; }
|
||||
public override int Duration { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(3)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.请求方式))]
|
||||
public override HttpMethods HttpMethod { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(1)]
|
||||
@ -54,32 +69,14 @@ public record ExportRequestLogRsp : QueryRequestLogRsp
|
||||
public override long Id { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(3)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.请求方式))]
|
||||
public override string Method { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[CsvIndex(9)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.跟踪编号))]
|
||||
public override string TraceId { get; init; }
|
||||
[Ignore]
|
||||
public override QueryUserLiteRsp Owner { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Ignore]
|
||||
public override QueryUserRsp User { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
[CsvIndex(5)]
|
||||
[Ignore(false)]
|
||||
[Name(nameof(Ln.用户名))]
|
||||
public string UserName { get; init; }
|
||||
public override long? OwnerDeptId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Register(TypeAdapterConfig config)
|
||||
{
|
||||
_ = config.ForType<Sys_RequestLog, ExportRequestLogRsp>().Map(d => d.UserName, s => s.User.UserName);
|
||||
}
|
||||
[Ignore]
|
||||
public override long? OwnerId { get; init; }
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
using NetAdmin.Domain.Dto.Sys.Api;
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
using NetAdmin.Domain.Dto.Sys.User;
|
||||
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
|
||||
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLog;
|
||||
|
||||
/// <summary>
|
||||
/// 响应:查询请求日志
|
||||
/// </summary>
|
||||
public record QueryRequestLogRsp : Sys_RequestLog, IRegister
|
||||
public record QueryRequestLogRsp : Sys_RequestLog
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建者客户端IP
|
||||
@ -13,101 +16,39 @@ public record QueryRequestLogRsp : Sys_RequestLog, IRegister
|
||||
[JsonInclude]
|
||||
public new virtual string CreatedClientIp => base.CreatedClientIp?.ToIpV4();
|
||||
|
||||
/// <summary>
|
||||
/// 登录名
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public virtual string LoginName => RequestBody?.ToObject<LoginByPwdReq>()?.Account;
|
||||
|
||||
/// <summary>
|
||||
/// 操作系统
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public virtual string Os => UserAgentParser.Create(CreatedUserAgent)?.Platform;
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ApiId" />
|
||||
/// <inheritdoc cref="Sys_RequestLog.Api" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ApiId { get; init; }
|
||||
public new virtual QueryApiRsp Api { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 接口描述
|
||||
/// </summary>
|
||||
public string ApiSummary { get; init; }
|
||||
/// <inheritdoc cref="Sys_RequestLog.ApiPathCrc32" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override int ApiPathCrc32 { get; init; }
|
||||
|
||||
/// <inheritdoc cref="IFieldCreatedTime.CreatedTime" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override DateTime CreatedTime { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.CreatedUserAgent" />
|
||||
/// <inheritdoc cref="Sys_RequestLog.Detail" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string CreatedUserAgent { get; init; }
|
||||
public new virtual QueryRequestLogDetailRsp Detail { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.Duration" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override long Duration { get; init; }
|
||||
public override int Duration { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ErrorCode" />
|
||||
/// <inheritdoc cref="Sys_RequestLog.HttpMethod" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override ErrorCodes ErrorCode { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.Exception" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string Exception { get; init; }
|
||||
public override HttpMethods HttpMethod { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.HttpStatusCode" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override int HttpStatusCode { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.Method" />
|
||||
/// <inheritdoc cref="Sys_RequestLog.Owner" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string Method { get; init; }
|
||||
public new virtual QueryUserLiteRsp Owner { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.RequestBody" />
|
||||
/// <inheritdoc cref="IFieldOwner.OwnerId" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestBody { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.RequestContentType" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestContentType { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.RequestHeaders" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestHeaders { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.RequestUrl" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestUrl { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ResponseBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseBody { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ResponseContentType" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseContentType { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ResponseHeaders" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseHeaders { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.ServerIp" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override int? ServerIp { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.TraceId" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string TraceId { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.User" />
|
||||
public new virtual QueryUserRsp User { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLog.UserId" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override long? UserId { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void Register(TypeAdapterConfig config)
|
||||
{
|
||||
_ = config.ForType<Sys_RequestLog, QueryRequestLogRsp>().Map(d => d.ApiSummary, s => s.Api.Summary);
|
||||
}
|
||||
public override long? OwnerId { get; init; }
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
/// <summary>
|
||||
/// 请求:创建请求日志明细
|
||||
/// </summary>
|
||||
public record CreateRequestLogDetailReq : Sys_RequestLogDetail;
|
@ -0,0 +1,11 @@
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
/// <summary>
|
||||
/// 请求:查询请求日志明细
|
||||
/// </summary>
|
||||
public sealed record QueryRequestLogDetailReq : Sys_RequestLogDetail
|
||||
{
|
||||
/// <inheritdoc cref="EntityBase{T}.Id" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override long Id { get; init; }
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
using NetAdmin.Domain.Dto.Sys.User;
|
||||
|
||||
namespace NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
/// <summary>
|
||||
/// 响应:查询请求日志明细
|
||||
/// </summary>
|
||||
public sealed record QueryRequestLogDetailRsp : Sys_RequestLogDetail
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录名
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public string LoginName => RequestBody?.ToObject<LoginByPwdReq>()?.Account;
|
||||
|
||||
/// <summary>
|
||||
/// 操作系统
|
||||
/// </summary>
|
||||
[JsonInclude]
|
||||
public string Os => UserAgentParser.Create(CreatedUserAgent)?.Platform;
|
||||
|
||||
/// <inheritdoc cref="IFieldCreatedClientUserAgent.CreatedUserAgent" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string CreatedUserAgent { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ErrorCode" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override ErrorCodes ErrorCode { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.Exception" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string Exception { get; init; }
|
||||
|
||||
/// <inheritdoc cref="EntityBase{T}.Id" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override long Id { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.RequestBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestBody { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.RequestContentType" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestContentType { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.RequestHeaders" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestHeaders { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.RequestUrl" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string RequestUrl { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ResponseBody" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseBody { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ResponseContentType" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseContentType { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ResponseHeaders" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string ResponseHeaders { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.ServerIp" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override int? ServerIp { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_RequestLogDetail.TraceId" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string TraceId { get; init; }
|
||||
}
|
15
src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserLiteRsp.cs
Normal file
15
src/backend/NetAdmin.Domain/Dto/Sys/User/QueryUserLiteRsp.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace NetAdmin.Domain.Dto.Sys.User;
|
||||
|
||||
/// <summary>
|
||||
/// 响应:查询用户精简版
|
||||
/// </summary>
|
||||
public record QueryUserLiteRsp : Sys_User
|
||||
{
|
||||
/// <inheritdoc cref="EntityBase{T}.Id" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||
public override long Id { get; init; }
|
||||
|
||||
/// <inheritdoc cref="Sys_User.UserName" />
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public override string UserName { get; init; }
|
||||
}
|
@ -11,20 +11,19 @@ public sealed record SqlCommandAfterEvent : SqlCommandBeforeEvent
|
||||
public SqlCommandAfterEvent(CommandAfterEventArgs e) //
|
||||
: base(e)
|
||||
{
|
||||
ElapsedMicroseconds = (long)((double)e.ElapsedTicks / Stopwatch.Frequency * 1_000_000);
|
||||
ElapsedMilliseconds = (long)((double)e.ElapsedTicks / Stopwatch.Frequency * 1_000);
|
||||
EventId = nameof(SqlCommandAfterEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 耗时(单位:微秒)
|
||||
/// 耗时(单位:毫秒)
|
||||
/// </summary>
|
||||
/// de
|
||||
private long ElapsedMicroseconds { get; }
|
||||
private long ElapsedMilliseconds { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: {2} ms {1}", Id
|
||||
, Sql?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_SQL), ElapsedMicroseconds / 1000);
|
||||
return string.Format(CultureInfo.InvariantCulture, "SQL-{0}: {2} ms {1}", Id, Sql, ElapsedMilliseconds);
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
<ProjectReference Include="../NetAdmin.Infrastructure/NetAdmin.Infrastructure.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CronExpressionDescriptor" Version="2.34.0"/>
|
||||
<PackageReference Include="CronExpressionDescriptor" Version="2.36.0"/>
|
||||
<PackageReference Include="Cronos" Version="0.8.4"/>
|
||||
<PackageReference Include="CsvHelper.NS" Version="33.0.2-ns2"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-preview.6.24328.4"/>
|
||||
|
@ -35,20 +35,15 @@ public abstract class WorkBase<TLogger>
|
||||
/// </summary>
|
||||
protected UnitOfWorkManager UowManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取锁
|
||||
/// </summary>
|
||||
protected Task<IRedLock> GetLockerAsync(string lockId)
|
||||
{
|
||||
return _redLocker.RedLockFactory.CreateLockAsync(lockId, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY)
|
||||
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_WAIT)
|
||||
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用工作流
|
||||
/// </summary>
|
||||
protected abstract ValueTask WorkflowAsync(CancellationToken cancelToken);
|
||||
protected abstract ValueTask WorkflowAsync( //
|
||||
|
||||
// ReSharper disable once UnusedParameter.Global
|
||||
#pragma warning disable SA1114
|
||||
CancellationToken cancelToken);
|
||||
#pragma warning restore SA1114
|
||||
|
||||
/// <summary>
|
||||
/// 通用工作流
|
||||
@ -69,4 +64,14 @@ public abstract class WorkBase<TLogger>
|
||||
|
||||
await WorkflowAsync(cancelToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取锁
|
||||
/// </summary>
|
||||
private Task<IRedLock> GetLockerAsync(string lockId)
|
||||
{
|
||||
return _redLocker.RedLockFactory.CreateLockAsync(lockId, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_EXPIRY)
|
||||
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_WAIT)
|
||||
, TimeSpan.FromSeconds(Numbers.SECS_RED_LOCK_RETRY));
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ public sealed class RequestAuditMiddleware(
|
||||
.FirstOrDefault()
|
||||
?.Enum<ErrorCodes>() ?? 0;
|
||||
|
||||
_ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMicroseconds, responseBody, errorCode
|
||||
_ = await requestLogger.LogAsync(context, (long)sw.Elapsed.TotalMilliseconds, responseBody, errorCode
|
||||
, exception)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="IGeekFan.AspNetCore.Knife4jUI.NS" Condition="'$(Configuration)' == 'Debug'" Version="0.0.15-ns2"/>
|
||||
<PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.161"/>
|
||||
<PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.179"/>
|
||||
<PackageReference Include="prometheus-net.AspNetCore" Condition="'$(Configuration)' != 'Debug'" Version="8.2.1"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,6 +1,9 @@
|
||||
using NetAdmin.Domain.Contexts;
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLog;
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
using NetAdmin.Domain.Events.Sys;
|
||||
using Yitter.IdGenerator;
|
||||
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
|
||||
|
||||
namespace NetAdmin.Host.Utils;
|
||||
|
||||
@ -19,36 +22,39 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
||||
{
|
||||
// 从请求头中读取用户信息
|
||||
var associatedUser = GetAssociatedUser(context);
|
||||
var auditData = new CreateRequestLogReq {
|
||||
Duration = duration
|
||||
, Method = context.Request.Method
|
||||
, RequestContentType = context.Request.ContentType
|
||||
, RequestBody = Array.Exists( //
|
||||
_textContentTypes
|
||||
, x => context.Request.ContentType?.Contains(
|
||||
x, StringComparison.OrdinalIgnoreCase) ?? false)
|
||||
? (await context.ReadBodyContentAsync().ConfigureAwait(false))
|
||||
?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)
|
||||
: string.Empty
|
||||
, RequestUrl = context.Request.GetRequestUrlAddress()
|
||||
, ResponseBody
|
||||
= responseBody?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)
|
||||
, ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32()
|
||||
, ApiId = context.Request.Path.Value?.TrimStart('/')
|
||||
, RequestHeaders = context.Request.Headers.Json()
|
||||
, ResponseContentType = context.Response.ContentType
|
||||
, ResponseHeaders = context.Response.Headers.Json()
|
||||
, HttpStatusCode = context.Response.StatusCode
|
||||
, ErrorCode = errorCode
|
||||
, Exception = exception?.Error.ToString()
|
||||
, UserId = associatedUser?.UserId
|
||||
, CreatedUserAgent = context.Request.Headers.UserAgent.ToString()
|
||||
, CreatedClientIp = context.GetRealIpAddress()
|
||||
?.MapToIPv4()
|
||||
.ToString()
|
||||
.IpV4ToInt32()
|
||||
, TraceId = context.TraceIdentifier
|
||||
};
|
||||
var id = YitIdHelper.NextId();
|
||||
var requestBody = Array.Exists( //
|
||||
_textContentTypes
|
||||
, x => context.Request.ContentType?.Contains(x, StringComparison.OrdinalIgnoreCase) ?? false)
|
||||
? await context.ReadBodyContentAsync().ConfigureAwait(false)
|
||||
: string.Empty;
|
||||
var auditData = new CreateRequestLogReq //
|
||||
{
|
||||
Detail = new CreateRequestLogDetailReq //
|
||||
{
|
||||
Id = id
|
||||
, CreatedUserAgent = context.Request.Headers.UserAgent.ToString()
|
||||
, ErrorCode = errorCode
|
||||
, Exception = exception?.Error.ToString()
|
||||
, RequestBody = requestBody
|
||||
, RequestContentType = context.Request.ContentType
|
||||
, RequestHeaders = context.Request.Headers.Json()
|
||||
, RequestUrl = context.Request.GetRequestUrlAddress()
|
||||
, ResponseBody = responseBody
|
||||
, ResponseContentType = context.Response.ContentType
|
||||
, ResponseHeaders = context.Response.Headers.Json()
|
||||
, ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32()
|
||||
, TraceId = context.TraceIdentifier
|
||||
}
|
||||
, Duration = (int)duration
|
||||
, HttpMethod = Enum.Parse<HttpMethods>(context.Request.Method, true)
|
||||
, ApiPathCrc32 = context.Request.Path.Value!.TrimStart('/').Crc32()
|
||||
, HttpStatusCode = context.Response.StatusCode
|
||||
, CreatedClientIp = context.GetRealIpAddress()?.MapToIPv4().ToString().IpV4ToInt32()
|
||||
, OwnerId = associatedUser?.UserId
|
||||
, OwnerDeptId = associatedUser?.DeptId
|
||||
, Id = id
|
||||
};
|
||||
|
||||
// 打印日志
|
||||
logger.Info(auditData);
|
||||
@ -59,7 +65,7 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
||||
return auditData;
|
||||
}
|
||||
|
||||
private (long UserId, string UserName)? GetAssociatedUser(HttpContext context)
|
||||
private (long UserId, long DeptId, string UserName)? GetAssociatedUser(HttpContext context)
|
||||
{
|
||||
var token = context.Request.Headers.Authorization.FirstOrDefault();
|
||||
if (token == null) {
|
||||
@ -69,7 +75,7 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
||||
ContextUserToken userToken = null;
|
||||
try {
|
||||
var jsonWebToken
|
||||
= JWTEncryption.ReadJwtToken(token.TrimStart($"{Chars.FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA} "));
|
||||
= JWTEncryption.ReadJwtToken(token.TrimPrefix($"{Chars.FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA} "));
|
||||
var claim = jsonWebToken?.Claims.FirstOrDefault(y => y.Type == nameof(ContextUserToken));
|
||||
userToken = claim?.Value.ToObject<ContextUserToken>();
|
||||
}
|
||||
@ -77,6 +83,6 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
|
||||
logger.Warn($"{Ln.读取用户令牌出错}: {ex}");
|
||||
}
|
||||
|
||||
return userToken == null ? null : (userToken.Id, userToken.UserName);
|
||||
return userToken == null ? null : (userToken.Id, userToken.DeptId, userToken.UserName);
|
||||
}
|
||||
}
|
@ -104,10 +104,10 @@ public sealed class SqlAuditor : ISingleton
|
||||
case nameof(IFieldCreatedUser.CreatedUserName):
|
||||
SetCreatedUserName(e, userInfo);
|
||||
break;
|
||||
case nameof(IFieldCreatedClient.CreatedClientIp):
|
||||
case nameof(IFieldCreatedClientIp.CreatedClientIp):
|
||||
SetCreatedClientIp(e);
|
||||
break;
|
||||
case nameof(IFieldCreatedClient.CreatedUserAgent):
|
||||
case nameof(IFieldCreatedClientUserAgent.CreatedUserAgent):
|
||||
SetCreatedUserAgent(e);
|
||||
break;
|
||||
default:
|
||||
|
@ -29,6 +29,7 @@ public static class Chars
|
||||
public const string FLG_DB_FIELD_TYPE_NVARCHAR_MAX = "nvarchar(max)";
|
||||
public const string FLG_DB_FIELD_TYPE_SMALL_INT = "smallint";
|
||||
public const string FLG_DB_FIELD_TYPE_TEXT = "text";
|
||||
public const string FLG_DB_FIELD_TYPE_TINY_INT = "tinyint";
|
||||
public const string FLG_DB_FIELD_TYPE_VARCHAR = "varchar";
|
||||
public const string FLG_DB_FIELD_TYPE_VARCHAR_1022 = "varchar(1022)";
|
||||
public const string FLG_DB_FIELD_TYPE_VARCHAR_127 = "varchar(127)";
|
||||
@ -54,6 +55,7 @@ public static class Chars
|
||||
public const string FLG_HTTP_HEADER_KEY_USER_AGENT = "User-Agent";
|
||||
public const string FLG_HTTP_HEADER_KEY_X_ACCESS_TOKEN = "X-ACCESS-TOKEN";
|
||||
public const string FLG_HTTP_HEADER_KEY_X_ACCESS_TOKEN_HEADER_KEY = "X-Authorization";
|
||||
public const string FLG_HTTP_HEADER_KEY_X_CACHE_CONTROL = "X-Cache-Control";
|
||||
public const string FLG_HTTP_HEADER_KEY_X_FORWARDED_FOR = "X-Forwarded-For";
|
||||
public const string FLG_HTTP_HEADER_KEY_X_REAL_IP = "X-Real-IP";
|
||||
public const string FLG_HTTP_HEADER_VALUE_APPLICATION_JSON = "application/json";
|
||||
@ -61,6 +63,7 @@ public static class Chars
|
||||
public const string FLG_HTTP_HEADER_VALUE_APPLICATION_URLENCODED = "application/x-www-form-urlencoded";
|
||||
public const string FLG_HTTP_HEADER_VALUE_ATTACHMENT = "attachment";
|
||||
public const string FLG_HTTP_HEADER_VALUE_AUTH_SCHEMA = "Bearer";
|
||||
public const string FLG_HTTP_HEADER_VALUE_NO_CACHE = "no-cache";
|
||||
public const string FLG_HTTP_METHOD_CONNECT = "CONNECT";
|
||||
public const string FLG_HTTP_METHOD_DELETE = "DELETE";
|
||||
public const string FLG_HTTP_METHOD_GET = "GET";
|
||||
|
@ -30,5 +30,6 @@ public static class Numbers
|
||||
public const int SECS_RED_LOCK_EXPIRY = 30; // 秒:RedLock-锁过期时间,假如持有锁的进程挂掉,最多在此时间内锁将被释放(如持有锁的进程正常,此值不会生效)
|
||||
public const int SECS_RED_LOCK_RETRY = 1; // 秒:RedLock-锁等待时间内,多久尝试获取一次
|
||||
public const int SECS_RED_LOCK_WAIT = 10; // 秒:RedLock-锁等待时间,相同的 resource 如果当前的锁被其他线程占用,最多等待时间
|
||||
public const int SECS_TIMEOUT_HTTP_CLIENT = 15; // 秒:超时时间-默认HTTP客户端
|
||||
public const int SECS_TIMEOUT_JOB = 600; // 秒:超时时间-作业
|
||||
}
|
@ -10,8 +10,7 @@ public static class HttpRequestMessageExtensions
|
||||
/// </summary>
|
||||
public static async Task<HttpRequestMessage> LogAsync<T>(this HttpRequestMessage me, ILogger<T> logger)
|
||||
{
|
||||
logger.Info(
|
||||
$"HTTP Request {(await me.BuildJsonAsync().ConfigureAwait(false))?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)}");
|
||||
logger.Info($"HTTP Request {await me.BuildJsonAsync().ConfigureAwait(false)}");
|
||||
return me;
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,7 @@ public static class HttpResponseMessageExtensions
|
||||
public static async Task LogAsync<T>(this HttpResponseMessage me, ILogger<T> logger
|
||||
, Func<string, string> bodyPreHandle = null)
|
||||
{
|
||||
logger.Info($"HTTP Response {(await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false))?.Sub(
|
||||
0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)}");
|
||||
logger.Info($"HTTP Response {await me.BuildJsonAsync(bodyPreHandle).ConfigureAwait(false)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -21,8 +20,7 @@ public static class HttpResponseMessageExtensions
|
||||
public static async Task LogExceptionAsync<T>(this HttpResponseMessage me, string errors, ILogger<T> logger
|
||||
, Func<string, string> bodyHandle = null)
|
||||
{
|
||||
logger.Warn(
|
||||
$"{errors}: {(await me.BuildJsonAsync(bodyHandle).ConfigureAwait(false))?.Sub(0, Numbers.MAX_LIMIT_PRINT_LEN_CONTENT)}");
|
||||
logger.Warn($"{errors}: {await me.BuildJsonAsync(bodyHandle).ConfigureAwait(false)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,3 +1,6 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
||||
using Microsoft.CodeAnalysis.Scripting;
|
||||
|
||||
namespace NetAdmin.Infrastructure.Extensions;
|
||||
|
||||
/// <summary>
|
||||
@ -5,8 +8,24 @@ namespace NetAdmin.Infrastructure.Extensions;
|
||||
/// </summary>
|
||||
public static class StringExtensions
|
||||
{
|
||||
private static readonly Regex _regex = new("Options$");
|
||||
private static readonly Regex _regex2 = new("Async$");
|
||||
/// <summary>
|
||||
/// 计算Crc32
|
||||
/// </summary>
|
||||
public static int Crc32(this string me)
|
||||
{
|
||||
return BitConverter.ToInt32(System.IO.Hashing.Crc32.Hash(Encoding.UTF8.GetBytes(me)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行C#代码
|
||||
/// </summary>
|
||||
public static Task<T> ExecuteCSharpCodeAsync<T>(this string me, Assembly[] assemblies
|
||||
, params string[] importNamespaces)
|
||||
{
|
||||
// 使用 Roslyn 编译并执行代码
|
||||
return CSharpScript.EvaluateAsync<T>(
|
||||
me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// object -> json
|
||||
@ -31,7 +50,7 @@ public static class StringExtensions
|
||||
public static string TrimEndAsync(this string me)
|
||||
#pragma warning restore VSTHRD200, ASA002, RCS1047
|
||||
{
|
||||
return _regex2.Replace(me, string.Empty);
|
||||
return TrimSuffix(me, "Async");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -39,14 +58,22 @@ public static class StringExtensions
|
||||
/// </summary>
|
||||
public static string TrimEndOptions(this string me)
|
||||
{
|
||||
return _regex.Replace(me, string.Empty);
|
||||
return TrimSuffix(me, "Options");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 去掉前部字符串
|
||||
/// </summary>
|
||||
public static string TrimStart(this string me, string clearStr)
|
||||
public static string TrimPrefix(this string me, string clearStr)
|
||||
{
|
||||
return Regex.Replace(me, $"^{clearStr}", string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 去掉尾部字符串
|
||||
/// </summary>
|
||||
public static string TrimSuffix(this string me, string clearStr)
|
||||
{
|
||||
return Regex.Replace(me, $"{clearStr}$", string.Empty);
|
||||
}
|
||||
}
|
@ -24,11 +24,6 @@ public static class GlobalStatic
|
||||
#endif
|
||||
;
|
||||
|
||||
/// <summary>
|
||||
/// 日志保存跳过的API编号
|
||||
/// </summary>
|
||||
public static string[] LogSavingSkipApiIds => ["api/probe/health.check", "api/adm/device.log/create"];
|
||||
|
||||
/// <summary>
|
||||
/// 系统内部密钥
|
||||
/// </summary>
|
||||
|
@ -8,9 +8,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FreeSql.DbContext.NS" Version="3.2.833-preview20260627-ns1"/>
|
||||
<PackageReference Include="FreeSql.Provider.Sqlite.NS" Version="3.2.833-preview20260627-ns1"/>
|
||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.4"/>
|
||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.4-ns1"/>
|
||||
<PackageReference Include="Furion.Pure.NS" Version="4.9.4-ns1"/>
|
||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.4.6"/>
|
||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster.NS" Version="4.9.4.6-ns4"/>
|
||||
<PackageReference Include="Furion.Pure.NS" Version="4.9.4.6-ns4"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.10.0"/>
|
||||
<PackageReference Include="Minio" Version="6.0.3"/>
|
||||
<PackageReference Include="NSExt" Version="2.2.0"/>
|
||||
<PackageReference Include="RedLock.net" Version="2.3.2"/>
|
||||
|
@ -42,17 +42,17 @@ public interface IJobModule : ICrudModule<CreateJobReq, QueryJobRsp // 创建类
|
||||
/// <summary>
|
||||
/// 获取作业记录条形图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 状态码分组作业记录饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 名称分组作业记录饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询作业记录
|
||||
|
@ -0,0 +1,13 @@
|
||||
using NetAdmin.Application.Modules;
|
||||
using NetAdmin.Domain.Dto.Dependency;
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
|
||||
namespace NetAdmin.SysComponent.Application.Modules.Sys;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志明细模块
|
||||
/// </summary>
|
||||
public interface IRequestLogDetailModule : ICrudModule<CreateRequestLogDetailReq, QueryRequestLogDetailRsp // 创建类型
|
||||
, QueryRequestLogDetailReq, QueryRequestLogDetailRsp // 查询类型
|
||||
, DelReq // 删除类型
|
||||
>;
|
@ -16,15 +16,15 @@ public interface IRequestLogModule : ICrudModule<CreateRequestLogReq, QueryReque
|
||||
/// <summary>
|
||||
/// 获取条形图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req);
|
||||
Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 描述分组饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 状态码分组饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req);
|
||||
}
|
@ -108,13 +108,16 @@ public sealed class ApiService(
|
||||
QueryApiRsp SelectQueryApiRsp(IGrouping<TypeInfo, ControllerActionDescriptor> group)
|
||||
{
|
||||
var first = group.First()!;
|
||||
|
||||
var id = Regex.Replace( //
|
||||
first.AttributeRouteInfo!.Template!, $"/{first.ActionName}$", string.Empty);
|
||||
return new QueryApiRsp {
|
||||
Summary = xmlCommentReader.GetComments(group.Key)
|
||||
, Name = first.ControllerName
|
||||
, Id = Regex.Replace( //
|
||||
first.AttributeRouteInfo!.Template!, $"/{first.ActionName}$", string.Empty)
|
||||
Summary = xmlCommentReader.GetComments(group.Key)
|
||||
, Name = first.ControllerName
|
||||
, Id = id
|
||||
, Children = GetChildren(group)
|
||||
, Namespace = regex.Match(group.Key.Namespace!).Groups[1].Value.ToLowerInvariant()
|
||||
, PathCrc32 = id.Crc32()
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -136,19 +139,25 @@ public sealed class ApiService(
|
||||
private IEnumerable<QueryApiRsp> GetChildren(IEnumerable<ControllerActionDescriptor> actionDescriptors)
|
||||
{
|
||||
return actionDescriptors //
|
||||
.Select(x => new QueryApiRsp {
|
||||
Summary = xmlCommentReader.GetComments(x.MethodInfo)
|
||||
, Name = x.ActionName
|
||||
, Id = x.AttributeRouteInfo!.Template
|
||||
, Method = x.ActionConstraints?.OfType<HttpMethodActionConstraint>()
|
||||
.FirstOrDefault()
|
||||
?.HttpMethods.First()
|
||||
});
|
||||
.Select(x => {
|
||||
var id = x.AttributeRouteInfo!.Template;
|
||||
return new QueryApiRsp {
|
||||
Summary = xmlCommentReader.GetComments(x.MethodInfo)
|
||||
, Name = x.ActionName
|
||||
, Id = id
|
||||
, Method = x.ActionConstraints?.OfType<HttpMethodActionConstraint>()
|
||||
.FirstOrDefault()
|
||||
?.HttpMethods.First()
|
||||
, PathCrc32 = id.Crc32()
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private ISelect<Sys_Api> QueryInternal(QueryReq<QueryApiReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -142,6 +142,8 @@ public sealed class ConfigService(BasicRepository<Sys_Config, long> rpo) //
|
||||
.WhereDynamicFilter(req.DynamicFilter)
|
||||
.WhereIf( //
|
||||
req.Filter?.Enabled.HasValue ?? false, a => a.Enabled == req.Filter.Enabled.Value);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -14,15 +14,15 @@ public interface IJobRecordService : IService, IJobRecordModule
|
||||
/// <summary>
|
||||
/// 获取条形图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 状态码分组饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req);
|
||||
|
||||
/// <summary>
|
||||
/// 名称分组饼图数据
|
||||
/// </summary>
|
||||
Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByNameAsync(QueryReq<QueryJobRecordReq> req);
|
||||
Task<IEnumerable<GetPieChartRsp>> GetPieChartByNameAsync(QueryReq<QueryJobRecordReq> req);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using NetAdmin.Application.Services;
|
||||
using NetAdmin.SysComponent.Application.Modules.Sys;
|
||||
|
||||
namespace NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志明细服务
|
||||
/// </summary>
|
||||
public interface IRequestLogDetailService : IService, IRequestLogDetailModule;
|
@ -149,6 +149,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
|
||||
ret = ret.AsTreeCte();
|
||||
}
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -175,6 +175,7 @@ public sealed class DevService(IApiService apiService) : ServiceBase<DevService>
|
||||
await File.WriteAllTextAsync(file, content).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// ReSharper disable once SeparateLocalFunctionsWithJumpStatement
|
||||
IEnumerable<string> Select(QueryApiRsp item)
|
||||
{
|
||||
return item.Children.Select(x => tplInner.Replace("$actionDesc$", x.Summary)
|
||||
|
@ -128,6 +128,8 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
|
||||
private ISelect<Sys_DicCatalog> QueryInternal(QueryReq<QueryDicCatalogReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -155,6 +155,8 @@ public sealed class DicContentService(BasicRepository<Sys_DicContent, long> rpo)
|
||||
private ISelect<Sys_DicContent> QueryInternal(QueryReq<QueryDicContentReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -80,7 +80,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public async Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
|
||||
@ -105,8 +105,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public async Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(req with { Order = Orders.None })
|
||||
@ -124,7 +123,7 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public async Task<IEnumerable<GetPieChartRsp>> GetPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(req with { Order = Orders.None })
|
||||
@ -178,6 +177,8 @@ public sealed class JobRecordService(BasicRepository<Sys_JobRecord, long> rpo) /
|
||||
req.Keywords?.Length > 0
|
||||
, a => a.JobId == req.Keywords.Int64Try(0) || a.Id == req.Keywords.Int64Try(0) ||
|
||||
a.Job.JobName == req.Keywords);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -77,11 +77,13 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
||||
.Set(a => a.JobName == req.JobName)
|
||||
.SetIf(req.RequestHeaders == null, a => a.RequestHeader, null)
|
||||
.SetIf(req.RequestHeaders != null, a => a.RequestHeader, req.RequestHeaders.Json())
|
||||
.Set(a => a.RequestBody == req.RequestBody)
|
||||
.Set(a => a.RequestUrl == req.RequestUrl)
|
||||
.Set(a => a.UserId == req.UserId)
|
||||
.Set(a => a.Summary == req.Summary)
|
||||
.Where(a => a.Id == req.Id);
|
||||
.Set(a => a.RequestBody == req.RequestBody)
|
||||
.Set(a => a.RequestUrl == req.RequestUrl)
|
||||
.Set(a => a.RandomDelayBegin == req.RandomDelayBegin)
|
||||
.Set(a => a.RandomDelayEnd == req.RandomDelayEnd)
|
||||
.Set(a => a.UserId == req.UserId)
|
||||
.Set(a => a.Summary == req.Summary)
|
||||
.Where(a => a.Id == req.Id);
|
||||
|
||||
#if DBTYPE_SQLSERVER
|
||||
return (await update.ExecuteUpdatedAsync().ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryJobRsp>();
|
||||
@ -236,22 +238,21 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return jobRecordService.GetBarChartAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return jobRecordService.GetPieChartByHttpStatusCodeAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return jobRecordService.GetPieChartByNameAsync(req);
|
||||
@ -335,6 +336,8 @@ public sealed class JobService(BasicRepository<Sys_Job, long> rpo, IJobRecordSer
|
||||
.WhereIf( //
|
||||
req.Keywords?.Length > 0
|
||||
, a => a.Id == req.Keywords.Int64Try(0) || a.JobName.Contains(req.Keywords));
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -0,0 +1,131 @@
|
||||
using NetAdmin.Application.Repositories;
|
||||
using NetAdmin.Application.Services;
|
||||
using NetAdmin.Domain.Dto.Dependency;
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||
|
||||
namespace NetAdmin.SysComponent.Application.Services.Sys;
|
||||
|
||||
/// <inheritdoc cref="IRequestLogDetailService" />
|
||||
public sealed class RequestLogDetailService(BasicRepository<Sys_RequestLogDetail, long> rpo) //
|
||||
: RepositoryService<Sys_RequestLogDetail, long, IRequestLogDetailService>(rpo), IRequestLogDetailService
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = 0;
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var item in req.Items) {
|
||||
ret += await DeleteAsync(item).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<long> CountAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return QueryInternal(req)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.CountAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<QueryRequestLogDetailRsp> CreateAsync(CreateRequestLogDetailReq req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
|
||||
return ret.Adapt<QueryRequestLogDetailRsp>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> DeleteAsync(DelReq req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return Rpo.DeleteAsync(a => a.Id == req.Id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<bool> ExistAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return QueryInternal(req)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.AnyAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IActionResult> ExportAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<QueryRequestLogDetailRsp> GetAsync(QueryRequestLogDetailReq req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(new QueryReq<QueryRequestLogDetailReq> { Filter = req })
|
||||
.ToOneAsync()
|
||||
.ConfigureAwait(false);
|
||||
return ret.Adapt<QueryRequestLogDetailRsp>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<PagedQueryRsp<QueryRequestLogDetailRsp>> PagedQueryAsync(
|
||||
PagedQueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var list = await QueryInternal(req)
|
||||
.Page(req.Page, req.PageSize)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.Count(out var total)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return new PagedQueryRsp<QueryRequestLogDetailRsp>(req.Page, req.PageSize, total
|
||||
, list.Adapt<IEnumerable<QueryRequestLogDetailRsp>>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<QueryRequestLogDetailRsp>> QueryAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(req)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.Take(req.Count)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
return ret.Adapt<IEnumerable<QueryRequestLogDetailRsp>>();
|
||||
}
|
||||
|
||||
private ISelect<Sys_RequestLogDetail> QueryInternal(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
case Orders.Random:
|
||||
return ret.OrderByRandom();
|
||||
}
|
||||
|
||||
ret = ret.OrderByPropertyNameIf(req.Prop?.Length > 0, req.Prop, req.Order == Orders.Ascending);
|
||||
if (!req.Prop?.Equals(nameof(req.Filter.Id), StringComparison.OrdinalIgnoreCase) ?? true) {
|
||||
ret = ret.OrderByDescending(a => a.Id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -8,7 +8,9 @@ using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||
namespace NetAdmin.SysComponent.Application.Services.Sys;
|
||||
|
||||
/// <inheritdoc cref="IRequestLogService" />
|
||||
public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo) //
|
||||
public sealed class RequestLogService(
|
||||
BasicRepository<Sys_RequestLog, long> rpo
|
||||
, RequestLogDetailService requestLogDetailService) //
|
||||
: RepositoryService<Sys_RequestLog, long, IRequestLogService>(rpo), IRequestLogService
|
||||
{
|
||||
private static readonly Regex _regex = new(Chars.RGXL_IP_V4);
|
||||
@ -43,6 +45,7 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await Rpo.InsertAsync(req).ConfigureAwait(false);
|
||||
_ = await requestLogDetailService.CreateAsync(req.Detail).ConfigureAwait(false);
|
||||
return ret.Adapt<QueryRequestLogRsp>();
|
||||
}
|
||||
|
||||
@ -68,7 +71,17 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
public Task<IActionResult> ExportAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
return ExportAsync<QueryRequestLogReq, ExportRequestLogRsp>(QueryInternal, req, Ln.请求日志导出);
|
||||
return ExportAsync<QueryRequestLogReq, ExportRequestLogRsp>( //
|
||||
QueryInternal, req, Ln.请求日志导出, a => new {
|
||||
a.Id
|
||||
, Api = new { a.Api.Id }
|
||||
, a.CreatedClientIp
|
||||
, a.CreatedTime
|
||||
, a.Duration
|
||||
, a.HttpMethod
|
||||
, a.HttpStatusCode
|
||||
, Owner = new { a.Owner.UserName }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -76,17 +89,18 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(new QueryReq<QueryRequestLogReq> { Filter = req })
|
||||
.Include(a => a.Detail)
|
||||
.ToOneAsync()
|
||||
.ConfigureAwait(false);
|
||||
return ret.Adapt<QueryRequestLogRsp>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public async Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
|
||||
var ret = await QueryInternal(req with { Order = Orders.None })
|
||||
var ret = await QueryInternal(req with { Order = Orders.None }, false)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
@ -107,7 +121,7 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public async Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(req with { Order = Orders.None })
|
||||
@ -121,11 +135,10 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryRequestLogReq> req)
|
||||
public async Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
req.ThrowIfInvalid();
|
||||
var ret = await QueryInternal(req with { Order = Orders.None })
|
||||
var ret = await QueryInternal(req with { Order = Orders.None }, false)
|
||||
#if DBTYPE_SQLSERVER
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
@ -148,42 +161,40 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
|
||||
#endif
|
||||
.Count(out var total);
|
||||
object list = req.DynamicFilter?.Filters?.Exists(
|
||||
x => nameof(QueryRequestLogReq.ApiId).Equals(x.Field, StringComparison.OrdinalIgnoreCase) &&
|
||||
Chars.FLG_PATH_API_SYS_USER_LOGIN_BY_PWD.Equals( //
|
||||
x.Value.ToString(), StringComparison.OrdinalIgnoreCase)) ?? false
|
||||
? await select.ToListAsync(a => new {
|
||||
a.ApiId
|
||||
, ApiSummary = a.Api.Summary
|
||||
, a.CreatedClientIp
|
||||
, a.CreatedTime
|
||||
, a.Duration
|
||||
, a.Method
|
||||
, a.CreatedUserAgent
|
||||
, a.HttpStatusCode
|
||||
, a.Id
|
||||
, a.UserId
|
||||
, a.User
|
||||
, a.RequestBody
|
||||
})
|
||||
.ConfigureAwait(false)
|
||||
: await select.ToListAsync(a => new {
|
||||
a.ApiId
|
||||
, ApiSummary = a.Api.Summary
|
||||
, a.CreatedClientIp
|
||||
, a.CreatedTime
|
||||
, a.Duration
|
||||
, a.Method
|
||||
, a.CreatedUserAgent
|
||||
, a.HttpStatusCode
|
||||
, a.Id
|
||||
, a.UserId
|
||||
, a.User
|
||||
})
|
||||
.ConfigureAwait(false);
|
||||
|
||||
object ret
|
||||
= req.DynamicFilter?.Filters?.Exists(
|
||||
x => nameof(QueryRequestLogReq.ApiPathCrc32).Equals(x.Field, StringComparison.OrdinalIgnoreCase) &&
|
||||
x.Value.ToString().Int32() == Chars.FLG_PATH_API_SYS_USER_LOGIN_BY_PWD.Crc32()) ?? false
|
||||
? await select.Include(a => a.Detail)
|
||||
.ToListAsync(a => new {
|
||||
Api = new { a.Api.Summary, a.Api.Id }
|
||||
, Owner = new { a.Owner.Id, a.Owner.UserName }
|
||||
, a.CreatedClientIp
|
||||
, a.CreatedTime
|
||||
, a.Duration
|
||||
, a.HttpMethod
|
||||
, a.HttpStatusCode
|
||||
, a.Id
|
||||
, a.ApiPathCrc32
|
||||
, Detail = new { a.Detail.RequestBody, a.Detail.CreatedUserAgent }
|
||||
})
|
||||
.ConfigureAwait(false)
|
||||
: await select.ToListAsync(a => new {
|
||||
Api = new { a.Api.Summary, a.Api.Id }
|
||||
, Owner = new { a.Owner.Id, a.Owner.UserName }
|
||||
, a.CreatedClientIp
|
||||
, a.CreatedTime
|
||||
, a.Duration
|
||||
, a.HttpMethod
|
||||
, a.HttpStatusCode
|
||||
, a.Id
|
||||
, a.ApiPathCrc32
|
||||
})
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return new PagedQueryRsp<QueryRequestLogRsp>(req.Page, req.PageSize, total
|
||||
, list.Adapt<IEnumerable<QueryRequestLogRsp>>());
|
||||
, ret.Adapt<IEnumerable<QueryRequestLogRsp>>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -202,7 +213,17 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
|
||||
private ISelect<Sys_RequestLog> QueryInternal(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.Include(a => a.Api).Include(a => a.User).WhereDynamicFilter(req.DynamicFilter);
|
||||
return QueryInternal(req, true);
|
||||
}
|
||||
|
||||
private ISelect<Sys_RequestLog> QueryInternal(QueryReq<QueryRequestLogReq> req, bool include)
|
||||
{
|
||||
var ret = Rpo.Select;
|
||||
if (include) {
|
||||
ret = ret.Include(a => a.Api).Include(a => a.Owner);
|
||||
}
|
||||
|
||||
ret = ret.WhereDynamicFilter(req.DynamicFilter);
|
||||
if (req.Filter?.Id is not 0) {
|
||||
ret = ret.WhereDynamic(req.Filter);
|
||||
}
|
||||
@ -210,10 +231,11 @@ public sealed class RequestLogService(BasicRepository<Sys_RequestLog, long> rpo)
|
||||
if (req.Keywords?.Length > 0) {
|
||||
ret = _regex.IsMatch(req.Keywords)
|
||||
? ret.Where(a => a.CreatedClientIp == req.Keywords.IpV4ToInt32())
|
||||
: ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.UserId == req.Keywords.Int64Try(0) ||
|
||||
a.User.UserName == req.Keywords || a.RequestBody.Contains(req.Keywords));
|
||||
: ret.Where(a => a.Id == req.Keywords.Int64Try(0) || a.OwnerId == req.Keywords.Int64Try(0) ||
|
||||
a.Owner.UserName == req.Keywords);
|
||||
}
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -161,6 +161,8 @@ public sealed class RoleService(BasicRepository<Sys_Role, long> rpo) //
|
||||
req.Keywords?.Length > 0
|
||||
, a => a.Id == req.Keywords.Int64Try(0) || a.Name.Contains(req.Keywords) ||
|
||||
a.Summary.Contains(req.Keywords));
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -111,6 +111,8 @@ public sealed class SiteMsgDeptService(BasicRepository<Sys_SiteMsgDept, long> rp
|
||||
private ISelect<Sys_SiteMsgDept> QueryInternal(QueryReq<QuerySiteMsgDeptReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -119,6 +119,8 @@ public sealed class SiteMsgFlagService(BasicRepository<Sys_SiteMsgFlag, long> rp
|
||||
private ISelect<Sys_SiteMsgFlag> QueryInternal(QueryReq<QuerySiteMsgFlagReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -111,6 +111,8 @@ public sealed class SiteMsgRoleService(BasicRepository<Sys_SiteMsgRole, long> rp
|
||||
private ISelect<Sys_SiteMsgRole> QueryInternal(QueryReq<QuerySiteMsgRoleReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -301,6 +301,8 @@ public sealed class SiteMsgService(
|
||||
req.Keywords?.Length > 0
|
||||
, a => a.Id == req.Keywords.Int64Try(0) || a.Title.Contains(req.Keywords) ||
|
||||
a.Summary.Contains(req.Keywords));
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -111,6 +111,8 @@ public sealed class SiteMsgUserService(BasicRepository<Sys_SiteMsgUser, long> rp
|
||||
private ISelect<Sys_SiteMsgUser> QueryInternal(QueryReq<QuerySiteMsgUserReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -490,6 +490,8 @@ public sealed class UserService(
|
||||
, a => a.Id == req.Keywords.Int64Try(0) || a.UserName == req.Keywords ||
|
||||
a.Mobile == req.Keywords ||
|
||||
a.Email == req.Keywords || a.Summary.Contains(req.Keywords));
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -198,6 +198,8 @@ public sealed class VerifyCodeService(BasicRepository<Sys_VerifyCode, long> rpo,
|
||||
private ISelect<Sys_VerifyCode> QueryInternal(QueryReq<QueryVerifyCodeReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -113,6 +113,8 @@ public sealed class ExampleService(BasicRepository<Tpl_Example, long> rpo) //
|
||||
private ISelect<Tpl_Example> QueryInternal(QueryReq<QueryExampleReq> req)
|
||||
{
|
||||
var ret = Rpo.Select.WhereDynamicFilter(req.DynamicFilter).WhereDynamic(req.Filter);
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (req.Order) {
|
||||
case Orders.None:
|
||||
return ret;
|
||||
|
@ -0,0 +1,10 @@
|
||||
using NetAdmin.Cache;
|
||||
using NetAdmin.SysComponent.Application.Modules.Sys;
|
||||
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||
|
||||
namespace NetAdmin.SysComponent.Cache.Sys.Dependency;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志明细缓存
|
||||
/// </summary>
|
||||
public interface IRequestLogDetailCache : ICache<IDistributedCache, IRequestLogDetailService>, IRequestLogDetailModule;
|
@ -81,8 +81,8 @@ public sealed class DicCache(IDistributedCache cache, IDicService service) //
|
||||
public Task<string> GetDicValueAsync(GetDicValueReq req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetDicValueAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT));
|
||||
#else
|
||||
return Service.GetDicValueAsync(req);
|
||||
|
@ -85,11 +85,11 @@ public sealed class JobCache(IDistributedCache cache, IJobService service)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetRecordBarChartAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetRecordBarChartAsync(req);
|
||||
@ -97,12 +97,11 @@ public sealed class JobCache(IDistributedCache cache, IJobService service)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetRecordPieChartByHttpStatusCodeAsync(req)
|
||||
, TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT));
|
||||
#else
|
||||
@ -111,11 +110,11 @@ public sealed class JobCache(IDistributedCache cache, IJobService service)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetRecordPieChartByNameAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetRecordPieChartByNameAsync(req);
|
||||
|
@ -18,9 +18,22 @@ public sealed class RequestLogCache(IDistributedCache cache, IRequestLogService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
#if !DEBUG
|
||||
public async Task<long> CountAsync(QueryReq<QueryRequestLogReq> req)
|
||||
#else
|
||||
public Task<long> CountAsync(QueryReq<QueryRequestLogReq> req)
|
||||
#endif
|
||||
{
|
||||
#if !DEBUG
|
||||
var ret = await GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, async () => (long?)await Service.CountAsync(req).ConfigureAwait(false)
|
||||
, TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT))
|
||||
.ConfigureAwait(false);
|
||||
return ret ?? 0;
|
||||
#else
|
||||
return Service.CountAsync(req);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -54,11 +67,11 @@ public sealed class RequestLogCache(IDistributedCache cache, IRequestLogService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetBarChartAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetBarChartAsync(req);
|
||||
@ -66,11 +79,11 @@ public sealed class RequestLogCache(IDistributedCache cache, IRequestLogService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetPieChartByApiSummaryAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetPieChartByApiSummaryAsync(req);
|
||||
@ -78,11 +91,11 @@ public sealed class RequestLogCache(IDistributedCache cache, IRequestLogService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.GetPieChartByHttpStatusCodeAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_CHART));
|
||||
#else
|
||||
return Service.GetPieChartByHttpStatusCodeAsync(req);
|
||||
|
@ -0,0 +1,66 @@
|
||||
using NetAdmin.Cache;
|
||||
using NetAdmin.Domain.Dto.Dependency;
|
||||
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
|
||||
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
|
||||
using NetAdmin.SysComponent.Cache.Sys.Dependency;
|
||||
|
||||
namespace NetAdmin.SysComponent.Cache.Sys;
|
||||
|
||||
/// <inheritdoc cref="IRequestLogDetailCache" />
|
||||
public sealed class RequestLogDetailCache(IDistributedCache cache, IRequestLogDetailService service)
|
||||
: DistributedCache<IRequestLogDetailService>(cache, service), IScoped, IRequestLogDetailCache
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
|
||||
{
|
||||
return Service.BulkDeleteAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<long> CountAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.CountAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<QueryRequestLogDetailRsp> CreateAsync(CreateRequestLogDetailReq req)
|
||||
{
|
||||
return Service.CreateAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> DeleteAsync(DelReq req)
|
||||
{
|
||||
return Service.DeleteAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<bool> ExistAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.ExistAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IActionResult> ExportAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.ExportAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<QueryRequestLogDetailRsp> GetAsync(QueryRequestLogDetailReq req)
|
||||
{
|
||||
return Service.GetAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<PagedQueryRsp<QueryRequestLogDetailRsp>> PagedQueryAsync(PagedQueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.PagedQueryAsync(req);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IEnumerable<QueryRequestLogDetailRsp>> QueryAsync(QueryReq<QueryRequestLogDetailReq> req)
|
||||
{
|
||||
return Service.QueryAsync(req);
|
||||
}
|
||||
}
|
@ -99,8 +99,8 @@ public sealed class UserCache(IDistributedCache cache, IUserService service, IVe
|
||||
public Task<IEnumerable<QueryUserRsp>> QueryAsync(QueryReq<QueryUserReq> req)
|
||||
{
|
||||
#if !DEBUG
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.GetHashCode().ToString(CultureInfo.InvariantCulture)) //
|
||||
return GetOrCreateAsync( //
|
||||
GetCacheKey(req.Json().Crc32().ToString(CultureInfo.InvariantCulture)) //
|
||||
, () => Service.QueryAsync(req), TimeSpan.FromSeconds(Numbers.SECS_CACHE_DEFAULT));
|
||||
#else
|
||||
return Service.QueryAsync(req);
|
||||
|
@ -119,7 +119,7 @@ public sealed class JobController(IJobCache cache) : ControllerBase<IJobCache, I
|
||||
/// <summary>
|
||||
/// 获取作业记录条形图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetRecordBarChartAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return Cache.GetRecordBarChartAsync(req);
|
||||
}
|
||||
@ -127,8 +127,7 @@ public sealed class JobController(IJobCache cache) : ControllerBase<IJobCache, I
|
||||
/// <summary>
|
||||
/// 状态码分组作业记录饼图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(
|
||||
QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByHttpStatusCodeAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return Cache.GetRecordPieChartByHttpStatusCodeAsync(req);
|
||||
}
|
||||
@ -136,7 +135,7 @@ public sealed class JobController(IJobCache cache) : ControllerBase<IJobCache, I
|
||||
/// <summary>
|
||||
/// 名称分组作业记录饼图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetRecordPieChartByNameAsync(QueryReq<QueryJobRecordReq> req)
|
||||
{
|
||||
return Cache.GetRecordPieChartByNameAsync(req);
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ public sealed class LogController(IRequestLogCache cache) : ControllerBase<IRequ
|
||||
/// <summary>
|
||||
/// 获取条形图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetBarChartRsp>> GetBarChartAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return Cache.GetBarChartAsync(req);
|
||||
}
|
||||
@ -90,7 +90,7 @@ public sealed class LogController(IRequestLogCache cache) : ControllerBase<IRequ
|
||||
/// <summary>
|
||||
/// 描述分组饼图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByApiSummaryAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return Cache.GetPieChartByApiSummaryAsync(req);
|
||||
}
|
||||
@ -98,7 +98,7 @@ public sealed class LogController(IRequestLogCache cache) : ControllerBase<IRequ
|
||||
/// <summary>
|
||||
/// 状态码分组饼图数据
|
||||
/// </summary>
|
||||
public Task<IOrderedEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
public Task<IEnumerable<GetPieChartRsp>> GetPieChartByHttpStatusCodeAsync(QueryReq<QueryRequestLogReq> req)
|
||||
{
|
||||
return Cache.GetPieChartByHttpStatusCodeAsync(req);
|
||||
}
|
||||
|
@ -66,7 +66,18 @@ public sealed class ScheduledJob : WorkBase<ScheduledJob>, IJob
|
||||
}
|
||||
|
||||
var request = BuildRequest(job);
|
||||
var sw = new Stopwatch();
|
||||
|
||||
// 随机延时
|
||||
if (job.RandomDelayBegin is > 0 && job.RandomDelayEnd is > 0) {
|
||||
var (start, end) = (job.RandomDelayBegin.Value, job.RandomDelayEnd.Value);
|
||||
if (start > end) {
|
||||
(start, end) = (end, start);
|
||||
}
|
||||
|
||||
await Task.Delay(new[] { start, end }.Rand(), CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var rsp = await request.SendAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
if (rsp.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden) {
|
||||
|
@ -18,13 +18,6 @@ public sealed class OperationLogger : IEventSubscriber
|
||||
return;
|
||||
}
|
||||
|
||||
// 跳过指定的请求
|
||||
if (Array.Exists( //
|
||||
GlobalStatic.LogSavingSkipApiIds
|
||||
, x => x.Equals(operationEvent.Data.ApiId, StringComparison.OrdinalIgnoreCase))) {
|
||||
return;
|
||||
}
|
||||
|
||||
operationEvent.Data.TruncateStrings();
|
||||
_ = await App.GetService<IRequestLogService>().CreateAsync(operationEvent.Data).ConfigureAwait(false);
|
||||
}
|
||||
|
Reference in New Issue
Block a user