Skip to content

Commit eddf320

Browse files
committed
Data hooks: New HookableAttribute for globally excluding entity types from hooking
1 parent 036ef2c commit eddf320

5 files changed

Lines changed: 67 additions & 7 deletions

File tree

src/Libraries/SmartStore.Core/Data/Hooks/DefaultHookHandler.cs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Diagnostics.CodeAnalysis;
45
using System.Linq;
@@ -18,6 +19,7 @@ public class DefaultHookHandler : IHookHandler
1819
// Prevents repetitive hooking of the same entity/state/[pre|post] combination within a single request
1920
private readonly HashSet<HookedEntityKey> _hookedEntities = new HashSet<HookedEntityKey>();
2021

22+
private readonly static ConcurrentDictionary<Type, bool> _hookableEntities = new ConcurrentDictionary<Type, bool>();
2123
private static HashSet<Type> _importantPreHookTypes;
2224
private static HashSet<Type> _importantPostHookTypes;
2325
private readonly static object _lock = new object();
@@ -74,7 +76,13 @@ public bool TriggerPreActionHooks(IEnumerable<HookedEntityEntry> entries, bool r
7476
{
7577
bool anyStateChanged = false;
7678

77-
if (entries == null || !_preHooks.Any() || (importantHooksOnly && !this.HasImportantPreHooks()))
79+
if (entries != null)
80+
{
81+
// Skip entities explicitly marked as unhookable
82+
entries = entries.Where(IsHookableEntry);
83+
}
84+
85+
if (entries == null || !entries.Any() || !_preHooks.Any() || (importantHooksOnly && !this.HasImportantPreHooks()))
7886
return false;
7987

8088
var processedHooks = new HashSet<IPreActionHook>();
@@ -83,7 +91,7 @@ public bool TriggerPreActionHooks(IEnumerable<HookedEntityEntry> entries, bool r
8391
{
8492
var e = entry; // Prevents access to modified closure
8593
var entity = e.Entry.Entity as BaseEntity;
86-
if (HookedAlready(entity, e.PreSaveState, false))
94+
if (HandledAlready(entity, e.PreSaveState, false))
8795
{
8896
// Prevent repetitive hooking of the same entity/state/pre combination within a single request
8997
continue;
@@ -154,7 +162,13 @@ private IEnumerable<IPreActionHook> GetPreHookInstancesFor(BaseEntity entity, bo
154162

155163
public void TriggerPostActionHooks(IEnumerable<HookedEntityEntry> entries, bool importantHooksOnly)
156164
{
157-
if (entries == null || !_postHooks.Any() || (importantHooksOnly && !this.HasImportantPostHooks()))
165+
if (entries != null)
166+
{
167+
// Skip entities explicitly marked as unhookable
168+
entries = entries.Where(IsHookableEntry);
169+
}
170+
171+
if (entries == null || !entries.Any() || !_postHooks.Any() || (importantHooksOnly && !this.HasImportantPostHooks()))
158172
return;
159173

160174
var processedHooks = new HashSet<IPostActionHook>();
@@ -163,7 +177,7 @@ public void TriggerPostActionHooks(IEnumerable<HookedEntityEntry> entries, bool
163177
{
164178
var e = entry; // Prevents access to modified closure
165179
var entity = e.Entry.Entity as BaseEntity;
166-
if (HookedAlready(entity, e.PreSaveState, true))
180+
if (HandledAlready(entity, e.PreSaveState, true))
167181
{
168182
// Prevent repetitive hooking of the same entity/state/post combination within a single request
169183
continue;
@@ -221,7 +235,30 @@ private IEnumerable<IPostActionHook> GetPostHookInstancesFor(BaseEntity entity,
221235
return hooks;
222236
}
223237

224-
private bool HookedAlready(BaseEntity entity, EntityState preSaveState, bool isPostActionHook)
238+
private bool IsHookableEntry(HookedEntityEntry entry)
239+
{
240+
var entity = entry.Entry.Entity as BaseEntity;
241+
if (entity == null)
242+
{
243+
return false;
244+
}
245+
246+
var isHookable = _hookableEntities.GetOrAdd(entity.GetUnproxiedType(), t =>
247+
{
248+
var attr = t.GetAttribute<HookableAttribute>(true);
249+
if (attr != null)
250+
{
251+
return attr.IsHookable;
252+
}
253+
254+
// Entities are hookable by default
255+
return true;
256+
});
257+
258+
return isHookable;
259+
}
260+
261+
private bool HandledAlready(BaseEntity entity, EntityState preSaveState, bool isPostActionHook)
225262
{
226263
if (entity.IsTransientRecord())
227264
return false;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
3+
namespace SmartStore.Core.Data.Hooks
4+
{
5+
/// <summary>
6+
/// Turns hooking for a specific entity type explicitly on or off.
7+
/// </summary>
8+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
9+
public sealed class HookableAttribute : Attribute
10+
{
11+
public HookableAttribute(bool isHookable)
12+
{
13+
IsHookable = IsHookable;
14+
}
15+
16+
public bool IsHookable
17+
{
18+
get;
19+
private set;
20+
}
21+
}
22+
}

src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
using System.ComponentModel.DataAnnotations;
44
using System.ComponentModel.DataAnnotations.Schema;
55
using System.Diagnostics;
6+
using SmartStore.Core.Data.Hooks;
67

78
namespace SmartStore.Core.Domain.Tasks
89
{
910
[DebuggerDisplay("{Name} (Type: {Type})")]
11+
[Hookable(false)]
1012
public class ScheduleTask : BaseEntity, ICloneable<ScheduleTask>
1113
{
1214
/// <summary>

src/Libraries/SmartStore.Core/Linq/PredicateBuilder.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System;
22
using System.Linq;
33
using System.Linq.Expressions;
4-
using System.Collections.Generic;
5-
using System.Reflection;
64

75
namespace SmartStore.Linq
86
{

src/Libraries/SmartStore.Core/SmartStore.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@
187187
<Compile Include="ComponentModel\TypeConversion\TypeConverterBase.cs" />
188188
<Compile Include="ComponentModel\TypeConversion\TypeConverterFactory.cs" />
189189
<Compile Include="Data\Hooks\DefaultHookHandler.cs" />
190+
<Compile Include="Data\Hooks\HookableAttribute.cs" />
190191
<Compile Include="Data\Hooks\IHookHandler.cs" />
191192
<Compile Include="Data\Hooks\ImportantAttribute.cs" />
192193
<Compile Include="Data\IDbContextExtensions.cs" />

0 commit comments

Comments
 (0)