ABP框架默认提供审计日志功能,只需实现并重写IAuditingStore接口即可
1.创建自定义审计日志的model,可以自定义字段内容以及字段类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | public class AuditLog : AuditedEntity< long > { /// <summary> /// Maximum length of <see cref="ServiceName"/> property. /// </summary> public const int MaxServiceNameLength = 256; /// <summary> /// Maximum length of <see cref="MethodName"/> property. /// </summary> public const int MaxMethodNameLength = 256; /// <summary> /// Maximum length of <see cref="Parameters"/> property. /// </summary> public const int MaxParametersLength = 1024; /// <summary> /// Maximum length of <see cref="ReturnValue"/> property. /// </summary> public const int MaxReturnValueLength = 1024; /// <summary> /// Maximum length of <see cref="ClientIpAddress"/> property. /// </summary> public const int MaxClientIpAddressLength = 64; /// <summary> /// Maximum length of <see cref="ClientName"/> property. /// </summary> public const int MaxClientNameLength = 128; /// <summary> /// Maximum length of <see cref="BrowserInfo"/> property. /// </summary> public const int MaxBrowserInfoLength = 512; /// <summary> /// Maximum length of <see cref="Exception"/> property. /// </summary> public const int MaxExceptionLength = 2048; /// <summary> /// Maximum length of <see cref="CustomData"/> property. /// </summary> public const int MaxCustomDataLength = 2048; /// <summary> /// Service (class/interface) name. /// </summary> [StringLength(MaxServiceNameLength)] public virtual string ServiceName { get ; set ; } /// <summary> /// Executed method name. /// </summary> [StringLength(MaxMethodNameLength)] public virtual string MethodName { get ; set ; } /// <summary> /// Calling parameters. /// </summary> [StringLength(MaxParametersLength)] public virtual string Parameters { get ; set ; } /// <summary> /// Return values. /// </summary> [StringLength(MaxReturnValueLength)] public virtual string ReturnValue { get ; set ; } /// <summary> /// Start time of the method execution. /// </summary> public virtual DateTime ExecutionTime { get ; set ; } /// <summary> /// Total duration of the method call as milliseconds. /// </summary> public virtual int ExecutionDuration { get ; set ; } /// <summary> /// IP address of the client. /// </summary> [StringLength(MaxClientIpAddressLength)] public virtual string ClientIpAddress { get ; set ; } /// <summary> /// Name (generally computer name) of the client. /// </summary> [StringLength(MaxClientNameLength)] public virtual string ClientName { get ; set ; } /// <summary> /// Browser information if this method is called in a web request. /// </summary> [StringLength(MaxBrowserInfoLength)] public virtual string BrowserInfo { get ; set ; } /// <summary> /// Exception object, if an exception occured during execution of the method. /// </summary> [StringLength(MaxExceptionLength)] public virtual string Exception { get ; set ; } /// <summary> /// <see cref="AuditInfo.CustomData"/>. /// </summary> [StringLength(MaxCustomDataLength)] public virtual string CustomData { get ; set ; } /// <summary> /// Creates a new CreateFromAuditInfo from given <paramref name="auditInfo"/>. /// </summary> /// <param name="auditInfo">Source <see cref="AuditInfo"/> object</param> /// <param name="account">Source <see cref="IAccountInfo"/> object</param> /// <returns>The <see cref="AuditLog"/> object that is created using <paramref name="auditInfo"/></returns> public static AuditLog CreateFromAuditInfo(AuditInfo auditInfo) { var exceptionMessage = GetAbpClearException(auditInfo.Exception); return new AuditLog { ServiceName = auditInfo.ServiceName.TruncateWithPostfix(MaxServiceNameLength), MethodName = auditInfo.MethodName.TruncateWithPostfix(MaxMethodNameLength), Parameters = auditInfo.Parameters.TruncateWithPostfix(MaxParametersLength), ReturnValue = auditInfo.ReturnValue.TruncateWithPostfix(MaxReturnValueLength), ExecutionTime = auditInfo.ExecutionTime, ExecutionDuration = auditInfo.ExecutionDuration, ClientIpAddress = auditInfo.ClientIpAddress.TruncateWithPostfix(MaxClientIpAddressLength), ClientName = auditInfo.ClientName.TruncateWithPostfix(MaxClientNameLength), BrowserInfo = auditInfo.BrowserInfo.TruncateWithPostfix(MaxBrowserInfoLength), Exception = exceptionMessage.TruncateWithPostfix(MaxExceptionLength), CustomData = auditInfo.CustomData.TruncateWithPostfix(MaxCustomDataLength) }; } public static string GetAbpClearException(Exception exception) { var clearMessage = "" ; switch (exception) { case null : return null ; case AbpValidationException abpValidationException: clearMessage = "There are " + abpValidationException.ValidationErrors.Count + " validation errors:" ; foreach ( var validationResult in abpValidationException.ValidationErrors) { var memberNames = "" ; if (validationResult.MemberNames != null && validationResult.MemberNames.Any()) { memberNames = " (" + string .Join( ", " , validationResult.MemberNames) + ")" ; } clearMessage += "\r\n" + validationResult.ErrorMessage + memberNames; } break ; case UserFriendlyException userFriendlyException: clearMessage = $ "UserFriendlyException.Code:{userFriendlyException.Code}\r\nUserFriendlyException.Details:{userFriendlyException.Details}" ; break ; } return exception + (clearMessage.IsNullOrWhiteSpace() ? "" : "\r\n\r\n" + clearMessage); } } |
2.在对应的DBContext中添加对应的model 并生成迁移文件,完成迁移
1 | public virtual DbSet<AuditLog> AuditLog { get ; set ; } |
Add-Migration test
Update-Database
3.自定义AuditStore实现Abp的IAuditingStore,重写对应方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class AuditingStoreTest : IAuditingStore, ITransientDependency { private readonly IRepository<AuditLog, long > _auditLogRepository; /// <summary> /// Creates a new <see cref="AuditingStore"/>. /// </summary> public AuditingStoreTest(IRepository<AuditLog, long > auditLogRepository) { _auditLogRepository = auditLogRepository; } public virtual Task SaveAsync(AuditInfo auditInfo) { return _auditLogRepository.InsertAsync(AuditLog.CreateFromAuditInfo(auditInfo)); } public virtual void Save(AuditInfo auditInfo) { _auditLogRepository.Insert(AuditLog.CreateFromAuditInfo(auditInfo)); } } |
4.找一个实现AbpModule模块的类中将原有的审计日志替换为自定义的
1 2 3 4 5 6 7 8 | Configuration.ReplaceService( typeof (IAuditingStore), () => { IocManager.IocContainer.Register( Component.For<IAuditingStore>() .ImplementedBy<AuditingStoreTest>() .LifestyleTransient() ); }); |
根据以上四步即可完成对abp审计日志的自定义扩展
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构