From 07a2087e85c9a8319f477e863d5996c3805f0563 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 23 Jan 2026 18:38:00 +0800 Subject: [PATCH 1/3] Add ambient auditing disable/enable support. --- .../Abp/Auditing/AuditingDisabledState.cs | 11 ++ .../Volo/Abp/Auditing/AuditingHelper.cs | 24 ++- .../Volo/Abp/Auditing/IAuditingHelper.cs | 4 + .../Volo/Abp/Auditing/AuditingHelper_Tests.cs | 139 ++++++++++++++++++ .../Pages/CmsKitPageRouteValueTransformer.cs | 11 +- 5 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingDisabledState.cs create mode 100644 framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingHelper_Tests.cs diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingDisabledState.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingDisabledState.cs new file mode 100644 index 0000000000..c4a2384316 --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingDisabledState.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.Auditing; + +public class AuditingDisabledState +{ + public bool IsDisabled { get; private set; } + + public AuditingDisabledState(bool isDisabled) + { + IsDisabled = isDisabled; + } +} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs index aadbeccabb..f37a6d7201 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.Clients; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; using Volo.Abp.Timing; using Volo.Abp.Tracing; using Volo.Abp.Users; @@ -26,6 +27,7 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency protected IAuditSerializer AuditSerializer; protected IServiceProvider ServiceProvider; protected ICorrelationIdProvider CorrelationIdProvider { get; } + protected IAmbientScopeProvider AuditingInterceptorState { get; } public AuditingHelper( IAuditSerializer auditSerializer, @@ -37,7 +39,8 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency IAuditingStore auditingStore, ILogger logger, IServiceProvider serviceProvider, - ICorrelationIdProvider correlationIdProvider) + ICorrelationIdProvider correlationIdProvider, + IAmbientScopeProvider auditingInterceptorState) { Options = options.Value; AuditSerializer = auditSerializer; @@ -50,6 +53,7 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency Logger = logger; ServiceProvider = serviceProvider; CorrelationIdProvider = correlationIdProvider; + AuditingInterceptorState = auditingInterceptorState; } public virtual bool ShouldSaveAudit(MethodInfo? methodInfo, bool defaultValue = false, bool ignoreIntegrationServiceAttribute = false) @@ -64,6 +68,11 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency return false; } + if (!IsAuditingEnabled()) + { + return false; + } + if (methodInfo.IsDefined(typeof(AuditedAttribute), true)) { return true; @@ -178,6 +187,19 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency return actionInfo; } + private const string AuditingDisabledScopeKey = "Volo.Abp.Auditing.DisabledScope"; + + public virtual IDisposable DisableAuditing() + { + return AuditingInterceptorState.BeginScope(AuditingDisabledScopeKey, new AuditingDisabledState(true)); + } + + public virtual bool IsAuditingEnabled() + { + var state = AuditingInterceptorState.GetValue(AuditingDisabledScopeKey); + return state == null || !state.IsDisabled; + } + protected virtual void ExecutePreContributors(AuditLogInfo auditLogInfo) { using (var scope = ServiceProvider.CreateScope()) diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs index e6fa20bc90..bbf6fe204a 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs @@ -26,4 +26,8 @@ public interface IAuditingHelper MethodInfo method, IDictionary arguments ); + + IDisposable DisableAuditing(); + + bool IsAuditingEnabled(); } diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingHelper_Tests.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingHelper_Tests.cs new file mode 100644 index 0000000000..f1f82a4459 --- /dev/null +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingHelper_Tests.cs @@ -0,0 +1,139 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using NSubstitute; +using Volo.Abp.DependencyInjection; +using Xunit; + +namespace Volo.Abp.Auditing; + +public class AuditingHelper_Tests : AbpAuditingTestBase +{ + private readonly IAuditingHelper _auditingHelper; + protected IAuditingStore AuditingStore; + + public AuditingHelper_Tests() + { + _auditingHelper = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + AuditingStore = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(AuditingStore)); + } + + [Fact] + public async Task Should_Write_AuditLog_Without_DisableAuditing() + { + var myAuditedObject = GetRequiredService(); + + await myAuditedObject.DoItAsync(); + + await AuditingStore.Received().SaveAsync(Arg.Any()); + } + + [Fact] + public async Task Should_Not_Write_AuditLog_With_DisableAuditing() + { + var myAuditedObject = GetRequiredService(); + + using (_auditingHelper.DisableAuditing()) + { + await myAuditedObject.DoItAsync(); + } + + await AuditingStore.DidNotReceive().SaveAsync(Arg.Any()); + } + + [Fact] + public async Task Should_Write_AuditLog_After_DisableAuditing_Scope_Disposed() + { + var myAuditedObject = GetRequiredService(); + + using (_auditingHelper.DisableAuditing()) + { + await myAuditedObject.DoItAsync(); + } + + AuditingStore.ClearReceivedCalls(); + + await myAuditedObject.DoItAsync(); + + await AuditingStore.Received().SaveAsync(Arg.Any()); + } + + [Fact] + public async Task Should_Not_Write_AuditLog_With_Nested_DisableAuditing() + { + var myAuditedObject = GetRequiredService(); + + using (_auditingHelper.DisableAuditing()) + { + await myAuditedObject.DoItAsync(); + + using (_auditingHelper.DisableAuditing()) + { + await myAuditedObject.DoItAsync(); + } + + await myAuditedObject.DoItAsync(); + } + + await AuditingStore.DidNotReceive().SaveAsync(Arg.Any()); + } + + [Fact] + public void Should_Return_True_When_Auditing_Is_Enabled() + { + Assert.True(_auditingHelper.IsAuditingEnabled()); + } + + [Fact] + public void Should_Return_False_When_Auditing_Is_Disabled() + { + using (_auditingHelper.DisableAuditing()) + { + Assert.False(_auditingHelper.IsAuditingEnabled()); + } + } + + [Fact] + public void Should_Return_True_After_DisableAuditing_Scope_Disposed() + { + using (_auditingHelper.DisableAuditing()) + { + Assert.False(_auditingHelper.IsAuditingEnabled()); + } + + Assert.True(_auditingHelper.IsAuditingEnabled()); + } + + [Fact] + public void Should_Return_False_With_Nested_DisableAuditing() + { + using (_auditingHelper.DisableAuditing()) + { + Assert.False(_auditingHelper.IsAuditingEnabled()); + + using (_auditingHelper.DisableAuditing()) + { + Assert.False(_auditingHelper.IsAuditingEnabled()); + } + + Assert.False(_auditingHelper.IsAuditingEnabled()); + } + } + + public interface IMyAuditedObject : ITransientDependency, IAuditingEnabled + { + } + + public class MyAuditedObject : IMyAuditedObject + { + public virtual Task DoItAsync() + { + return Task.CompletedTask; + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPageRouteValueTransformer.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPageRouteValueTransformer.cs index 996a449489..82750943c0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPageRouteValueTransformer.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPageRouteValueTransformer.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; +using Volo.Abp.Auditing; using Volo.Abp.Caching; using Volo.Abp.Features; using Volo.Abp.MultiTenancy; @@ -16,18 +17,21 @@ public class CmsKitPageRouteValueTransformer : CmsKitDynamicRouteValueTransforme protected IFeatureChecker FeatureChecker { get; } protected IPagePublicAppService PagePublicAppService { get; } protected IDistributedCache PageCache { get; } + protected IAuditingHelper AuditingHelper { get; } public CmsKitPageRouteValueTransformer( ICurrentTenant currentTenant, ITenantConfigurationProvider tenantConfigurationProvider, IFeatureChecker featureChecker, IPagePublicAppService pagePublicAppService, - IDistributedCache pageCache) + IDistributedCache pageCache, + IAuditingHelper auditingHelper) : base(currentTenant, tenantConfigurationProvider) { FeatureChecker = featureChecker; PagePublicAppService = pagePublicAppService; PageCache = pageCache; + AuditingHelper = auditingHelper; } protected async override ValueTask DoTransformAsync(HttpContext httpContext, RouteValueDictionary values) @@ -44,7 +48,10 @@ public class CmsKitPageRouteValueTransformer : CmsKitDynamicRouteValueTransforme var exist = await PageCache.GetAsync(PageCacheItem.GetKey(slug)) != null; if (!exist) { - exist = await PagePublicAppService.DoesSlugExistAsync(slug); + using (AuditingHelper.DisableAuditing()) + { + exist = await PagePublicAppService.DoesSlugExistAsync(slug); + } } if (exist) From 0590f5119ff4fdbe2947156a28611b8ce825cd77 Mon Sep 17 00:00:00 2001 From: Ma Liming Date: Fri, 23 Jan 2026 18:49:31 +0800 Subject: [PATCH 2/3] Update framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Volo/Abp/Auditing/IAuditingHelper.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs index bbf6fe204a..f0a36da5b4 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs @@ -27,7 +27,22 @@ public interface IAuditingHelper IDictionary arguments ); + /// + /// Creates a scope in which auditing is temporarily disabled. + /// + /// + /// An that restores the previous auditing state + /// when disposed. This method supports nested scopes; disposing a scope + /// restores the auditing state that was active before that scope was created. + /// IDisposable DisableAuditing(); + /// + /// Determines whether auditing is currently enabled. + /// + /// + /// true if auditing is enabled in the current context; otherwise, false. + /// This reflects any active scopes created by . + /// bool IsAuditingEnabled(); } From e3b06149a6233295ec27db83d4e9f98301ef2008 Mon Sep 17 00:00:00 2001 From: Ma Liming Date: Fri, 23 Jan 2026 18:50:10 +0800 Subject: [PATCH 3/3] Update AuditingHelper.cs --- .../Volo/Abp/Auditing/AuditingHelper.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs index f37a6d7201..028096d0ac 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs @@ -27,7 +27,7 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency protected IAuditSerializer AuditSerializer; protected IServiceProvider ServiceProvider; protected ICorrelationIdProvider CorrelationIdProvider { get; } - protected IAmbientScopeProvider AuditingInterceptorState { get; } + protected IAmbientScopeProvider AuditingDisabledState { get; } public AuditingHelper( IAuditSerializer auditSerializer, @@ -40,7 +40,7 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency ILogger logger, IServiceProvider serviceProvider, ICorrelationIdProvider correlationIdProvider, - IAmbientScopeProvider auditingInterceptorState) + IAmbientScopeProvider auditingDisabledState) { Options = options.Value; AuditSerializer = auditSerializer; @@ -53,7 +53,7 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency Logger = logger; ServiceProvider = serviceProvider; CorrelationIdProvider = correlationIdProvider; - AuditingInterceptorState = auditingInterceptorState; + AuditingDisabledState = auditingDisabledState; } public virtual bool ShouldSaveAudit(MethodInfo? methodInfo, bool defaultValue = false, bool ignoreIntegrationServiceAttribute = false) @@ -191,12 +191,12 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency public virtual IDisposable DisableAuditing() { - return AuditingInterceptorState.BeginScope(AuditingDisabledScopeKey, new AuditingDisabledState(true)); + return AuditingDisabledState.BeginScope(AuditingDisabledScopeKey, new AuditingDisabledState(true)); } public virtual bool IsAuditingEnabled() { - var state = AuditingInterceptorState.GetValue(AuditingDisabledScopeKey); + var state = AuditingDisabledState.GetValue(AuditingDisabledScopeKey); return state == null || !state.IsDisabled; }