Skip to content

Commit 255efbf

Browse files
authored
Merge pull request #24718 from abpframework/AuditingDisabledState
Add ambient auditing disable/enable support.
2 parents 2c303a6 + e3b0614 commit 255efbf

File tree

5 files changed

+201
-3
lines changed

5 files changed

+201
-3
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Volo.Abp.Auditing;
2+
3+
public class AuditingDisabledState
4+
{
5+
public bool IsDisabled { get; private set; }
6+
7+
public AuditingDisabledState(bool isDisabled)
8+
{
9+
IsDisabled = isDisabled;
10+
}
11+
}

framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Volo.Abp.Clients;
99
using Volo.Abp.DependencyInjection;
1010
using Volo.Abp.MultiTenancy;
11+
using Volo.Abp.Threading;
1112
using Volo.Abp.Timing;
1213
using Volo.Abp.Tracing;
1314
using Volo.Abp.Users;
@@ -26,6 +27,7 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency
2627
protected IAuditSerializer AuditSerializer;
2728
protected IServiceProvider ServiceProvider;
2829
protected ICorrelationIdProvider CorrelationIdProvider { get; }
30+
protected IAmbientScopeProvider<AuditingDisabledState> AuditingDisabledState { get; }
2931

3032
public AuditingHelper(
3133
IAuditSerializer auditSerializer,
@@ -37,7 +39,8 @@ public AuditingHelper(
3739
IAuditingStore auditingStore,
3840
ILogger<AuditingHelper> logger,
3941
IServiceProvider serviceProvider,
40-
ICorrelationIdProvider correlationIdProvider)
42+
ICorrelationIdProvider correlationIdProvider,
43+
IAmbientScopeProvider<AuditingDisabledState> auditingDisabledState)
4144
{
4245
Options = options.Value;
4346
AuditSerializer = auditSerializer;
@@ -50,6 +53,7 @@ public AuditingHelper(
5053
Logger = logger;
5154
ServiceProvider = serviceProvider;
5255
CorrelationIdProvider = correlationIdProvider;
56+
AuditingDisabledState = auditingDisabledState;
5357
}
5458

5559
public virtual bool ShouldSaveAudit(MethodInfo? methodInfo, bool defaultValue = false, bool ignoreIntegrationServiceAttribute = false)
@@ -64,6 +68,11 @@ public virtual bool ShouldSaveAudit(MethodInfo? methodInfo, bool defaultValue =
6468
return false;
6569
}
6670

71+
if (!IsAuditingEnabled())
72+
{
73+
return false;
74+
}
75+
6776
if (methodInfo.IsDefined(typeof(AuditedAttribute), true))
6877
{
6978
return true;
@@ -178,6 +187,19 @@ public virtual AuditLogActionInfo CreateAuditLogAction(
178187
return actionInfo;
179188
}
180189

190+
private const string AuditingDisabledScopeKey = "Volo.Abp.Auditing.DisabledScope";
191+
192+
public virtual IDisposable DisableAuditing()
193+
{
194+
return AuditingDisabledState.BeginScope(AuditingDisabledScopeKey, new AuditingDisabledState(true));
195+
}
196+
197+
public virtual bool IsAuditingEnabled()
198+
{
199+
var state = AuditingDisabledState.GetValue(AuditingDisabledScopeKey);
200+
return state == null || !state.IsDisabled;
201+
}
202+
181203
protected virtual void ExecutePreContributors(AuditLogInfo auditLogInfo)
182204
{
183205
using (var scope = ServiceProvider.CreateScope())

framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,23 @@ AuditLogActionInfo CreateAuditLogAction(
2626
MethodInfo method,
2727
IDictionary<string, object?> arguments
2828
);
29+
30+
/// <summary>
31+
/// Creates a scope in which auditing is temporarily disabled.
32+
/// </summary>
33+
/// <returns>
34+
/// An <see cref="IDisposable"/> that restores the previous auditing state
35+
/// when disposed. This method supports nested scopes; disposing a scope
36+
/// restores the auditing state that was active before that scope was created.
37+
/// </returns>
38+
IDisposable DisableAuditing();
39+
40+
/// <summary>
41+
/// Determines whether auditing is currently enabled.
42+
/// </summary>
43+
/// <returns>
44+
/// <c>true</c> if auditing is enabled in the current context; otherwise, <c>false</c>.
45+
/// This reflects any active scopes created by <see cref="DisableAuditing"/>.
46+
/// </returns>
47+
bool IsAuditingEnabled();
2948
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
using System.Threading.Tasks;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.DependencyInjection.Extensions;
4+
using NSubstitute;
5+
using Volo.Abp.DependencyInjection;
6+
using Xunit;
7+
8+
namespace Volo.Abp.Auditing;
9+
10+
public class AuditingHelper_Tests : AbpAuditingTestBase
11+
{
12+
private readonly IAuditingHelper _auditingHelper;
13+
protected IAuditingStore AuditingStore;
14+
15+
public AuditingHelper_Tests()
16+
{
17+
_auditingHelper = GetRequiredService<IAuditingHelper>();
18+
}
19+
20+
protected override void AfterAddApplication(IServiceCollection services)
21+
{
22+
AuditingStore = Substitute.For<IAuditingStore>();
23+
services.Replace(ServiceDescriptor.Singleton(AuditingStore));
24+
}
25+
26+
[Fact]
27+
public async Task Should_Write_AuditLog_Without_DisableAuditing()
28+
{
29+
var myAuditedObject = GetRequiredService<MyAuditedObject>();
30+
31+
await myAuditedObject.DoItAsync();
32+
33+
await AuditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
34+
}
35+
36+
[Fact]
37+
public async Task Should_Not_Write_AuditLog_With_DisableAuditing()
38+
{
39+
var myAuditedObject = GetRequiredService<MyAuditedObject>();
40+
41+
using (_auditingHelper.DisableAuditing())
42+
{
43+
await myAuditedObject.DoItAsync();
44+
}
45+
46+
await AuditingStore.DidNotReceive().SaveAsync(Arg.Any<AuditLogInfo>());
47+
}
48+
49+
[Fact]
50+
public async Task Should_Write_AuditLog_After_DisableAuditing_Scope_Disposed()
51+
{
52+
var myAuditedObject = GetRequiredService<MyAuditedObject>();
53+
54+
using (_auditingHelper.DisableAuditing())
55+
{
56+
await myAuditedObject.DoItAsync();
57+
}
58+
59+
AuditingStore.ClearReceivedCalls();
60+
61+
await myAuditedObject.DoItAsync();
62+
63+
await AuditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
64+
}
65+
66+
[Fact]
67+
public async Task Should_Not_Write_AuditLog_With_Nested_DisableAuditing()
68+
{
69+
var myAuditedObject = GetRequiredService<MyAuditedObject>();
70+
71+
using (_auditingHelper.DisableAuditing())
72+
{
73+
await myAuditedObject.DoItAsync();
74+
75+
using (_auditingHelper.DisableAuditing())
76+
{
77+
await myAuditedObject.DoItAsync();
78+
}
79+
80+
await myAuditedObject.DoItAsync();
81+
}
82+
83+
await AuditingStore.DidNotReceive().SaveAsync(Arg.Any<AuditLogInfo>());
84+
}
85+
86+
[Fact]
87+
public void Should_Return_True_When_Auditing_Is_Enabled()
88+
{
89+
Assert.True(_auditingHelper.IsAuditingEnabled());
90+
}
91+
92+
[Fact]
93+
public void Should_Return_False_When_Auditing_Is_Disabled()
94+
{
95+
using (_auditingHelper.DisableAuditing())
96+
{
97+
Assert.False(_auditingHelper.IsAuditingEnabled());
98+
}
99+
}
100+
101+
[Fact]
102+
public void Should_Return_True_After_DisableAuditing_Scope_Disposed()
103+
{
104+
using (_auditingHelper.DisableAuditing())
105+
{
106+
Assert.False(_auditingHelper.IsAuditingEnabled());
107+
}
108+
109+
Assert.True(_auditingHelper.IsAuditingEnabled());
110+
}
111+
112+
[Fact]
113+
public void Should_Return_False_With_Nested_DisableAuditing()
114+
{
115+
using (_auditingHelper.DisableAuditing())
116+
{
117+
Assert.False(_auditingHelper.IsAuditingEnabled());
118+
119+
using (_auditingHelper.DisableAuditing())
120+
{
121+
Assert.False(_auditingHelper.IsAuditingEnabled());
122+
}
123+
124+
Assert.False(_auditingHelper.IsAuditingEnabled());
125+
}
126+
}
127+
128+
public interface IMyAuditedObject : ITransientDependency, IAuditingEnabled
129+
{
130+
}
131+
132+
public class MyAuditedObject : IMyAuditedObject
133+
{
134+
public virtual Task DoItAsync()
135+
{
136+
return Task.CompletedTask;
137+
}
138+
}
139+
}

modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKitPageRouteValueTransformer.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Threading.Tasks;
22
using Microsoft.AspNetCore.Http;
33
using Microsoft.AspNetCore.Routing;
4+
using Volo.Abp.Auditing;
45
using Volo.Abp.Caching;
56
using Volo.Abp.Features;
67
using Volo.Abp.MultiTenancy;
@@ -16,18 +17,21 @@ public class CmsKitPageRouteValueTransformer : CmsKitDynamicRouteValueTransforme
1617
protected IFeatureChecker FeatureChecker { get; }
1718
protected IPagePublicAppService PagePublicAppService { get; }
1819
protected IDistributedCache<PageCacheItem> PageCache { get; }
20+
protected IAuditingHelper AuditingHelper { get; }
1921

2022
public CmsKitPageRouteValueTransformer(
2123
ICurrentTenant currentTenant,
2224
ITenantConfigurationProvider tenantConfigurationProvider,
2325
IFeatureChecker featureChecker,
2426
IPagePublicAppService pagePublicAppService,
25-
IDistributedCache<PageCacheItem> pageCache)
27+
IDistributedCache<PageCacheItem> pageCache,
28+
IAuditingHelper auditingHelper)
2629
: base(currentTenant, tenantConfigurationProvider)
2730
{
2831
FeatureChecker = featureChecker;
2932
PagePublicAppService = pagePublicAppService;
3033
PageCache = pageCache;
34+
AuditingHelper = auditingHelper;
3135
}
3236

3337
protected async override ValueTask<RouteValueDictionary> DoTransformAsync(HttpContext httpContext, RouteValueDictionary values)
@@ -44,7 +48,10 @@ protected async override ValueTask<RouteValueDictionary> DoTransformAsync(HttpCo
4448
var exist = await PageCache.GetAsync(PageCacheItem.GetKey(slug)) != null;
4549
if (!exist)
4650
{
47-
exist = await PagePublicAppService.DoesSlugExistAsync(slug);
51+
using (AuditingHelper.DisableAuditing())
52+
{
53+
exist = await PagePublicAppService.DoesSlugExistAsync(slug);
54+
}
4855
}
4956

5057
if (exist)

0 commit comments

Comments
 (0)