2
2
using Microsoft . EntityFrameworkCore . ChangeTracking ;
3
3
using Microsoft . EntityFrameworkCore . Diagnostics ;
4
4
using System . Linq ;
5
+ using System . Text . Json ;
5
6
6
7
namespace Shiny . Auditing ;
7
8
8
9
9
10
public class AuditSaveChangesInterceptor ( IAuditInfoProvider provider ) : SaveChangesInterceptor
10
11
{
11
- public override int SavedChanges ( SaveChangesCompletedEventData eventData , int result )
12
+ public override ValueTask < InterceptionResult < int > > SavingChangesAsync ( DbContextEventData eventData , InterceptionResult < int > result , CancellationToken cancellationToken = default )
12
13
{
13
14
var entries = this . GetAuditEntries ( eventData ) ;
14
- eventData . Context ! . AddRange ( entries ) ;
15
-
16
- var actualResult = base . SavedChanges ( eventData , result ) ;
17
- return actualResult ;
15
+ eventData . Context ! . AddRange ( entries ) ;
16
+ return base . SavingChangesAsync ( eventData , result , cancellationToken ) ;
18
17
}
19
18
19
+ public override InterceptionResult < int > SavingChanges ( DbContextEventData eventData , InterceptionResult < int > result )
20
+ {
21
+ var entries = this . GetAuditEntries ( eventData ) ;
22
+ eventData . Context ! . AddRange ( entries ) ;
23
+ return base . SavingChanges ( eventData , result ) ;
24
+ }
20
25
21
26
static DbOperation ToOperation ( EntityState state )
22
27
{
@@ -29,11 +34,9 @@ static DbOperation ToOperation(EntityState state)
29
34
return DbOperation . Update ;
30
35
}
31
36
32
-
33
- protected virtual List < AuditEntry > GetAuditEntries ( SaveChangesCompletedEventData eventData )
37
+ protected virtual List < AuditEntry > GetAuditEntries ( DbContextEventData eventData )
34
38
{
35
39
var entries = new List < AuditEntry > ( ) ;
36
- var auditInfo = provider . GetAuditInfo ( ) ;
37
40
var changeTracker = eventData . Context ! . ChangeTracker ;
38
41
changeTracker . DetectChanges ( ) ;
39
42
@@ -44,19 +47,29 @@ protected virtual List<AuditEntry> GetAuditEntries(SaveChangesCompletedEventData
44
47
entry . State != EntityState . Unchanged &&
45
48
entry . Entity is IAuditable auditable )
46
49
{
47
- auditable . LastEditUserIdentifier = auditInfo . UserIdentifier ;
48
- if ( auditable . DateCreated == DateTimeOffset . MinValue )
49
- auditable . DateCreated = DateTimeOffset . UtcNow ;
50
+ if ( entry . State == EntityState . Modified )
51
+ {
52
+ entry . CurrentValues [ nameof ( IAuditable . DateUpdated ) ] = DateTimeOffset . UtcNow ;
53
+ }
54
+ else if ( entry . State == EntityState . Added )
55
+ {
56
+ entry . CurrentValues [ nameof ( IAuditable . DateUpdated ) ] = DateTimeOffset . UtcNow ;
57
+ entry . CurrentValues [ nameof ( IAuditable . DateCreated ) ] = DateTimeOffset . UtcNow ;
58
+ }
50
59
51
- entry . DetectChanges ( ) ;
60
+ entry . CurrentValues [ nameof ( IAuditable . LastEditUserIdentifier ) ] = provider . UserIdentifier ;
52
61
var auditEntry = new AuditEntry
53
62
{
54
63
Operation = ToOperation ( entry . State ) ,
55
64
EntityId = entry . Properties . Single ( p => p . Metadata . IsPrimaryKey ( ) ) . CurrentValue ! . ToString ( ) ! ,
56
65
EntityType = entry . Metadata . ClrType . Name ,
57
66
Timestamp = DateTime . UtcNow ,
58
- ChangeSet = this . CalculateChangeSet ( entry ) ,
59
- Info = auditInfo
67
+ ChangeSet = this . CalculateChangeSet ( entry ) , // TODO: NULL on add
68
+
69
+ UserIdentifier = provider . UserIdentifier ,
70
+ UserIpAddress = provider . UserIpAddress ,
71
+ Tenant = provider . Tenant ,
72
+ AppLocation = provider . AppLocation
60
73
} ;
61
74
entries . Add ( auditEntry ) ;
62
75
}
@@ -65,8 +78,9 @@ protected virtual List<AuditEntry> GetAuditEntries(SaveChangesCompletedEventData
65
78
}
66
79
67
80
68
- protected virtual Dictionary < string , object > CalculateChangeSet ( EntityEntry entry )
81
+ protected virtual JsonDocument CalculateChangeSet ( EntityEntry entry )
69
82
{
83
+ // TODO: if I'm deleting, I want all the original values (even ignored?)
70
84
var dict = new Dictionary < string , object > ( ) ;
71
85
foreach ( var property in entry . Properties )
72
86
{
@@ -75,7 +89,9 @@ protected virtual Dictionary<string, object> CalculateChangeSet(EntityEntry entr
75
89
dict . Add ( property . Metadata . Name , property . OriginalValue ?? "NULL" ) ;
76
90
}
77
91
}
78
- return dict ;
92
+
93
+ var json = JsonSerializer . SerializeToDocument ( dict ) ;
94
+ return json ;
79
95
}
80
96
81
97
@@ -93,10 +109,11 @@ protected virtual bool IsAuditedProperty(PropertyEntry entry)
93
109
return true ;
94
110
}
95
111
112
+
96
113
protected virtual bool IsPropertyIgnored ( string propertyName ) => propertyName switch
97
114
{
98
- nameof ( IAuditable . LastEditUserIdentifier ) => false ,
99
- nameof ( IAuditable . DateCreated ) => false ,
100
- _ => true
115
+ nameof ( IAuditable . LastEditUserIdentifier ) => true ,
116
+ nameof ( IAuditable . DateCreated ) => true ,
117
+ _ => false
101
118
} ;
102
119
}
0 commit comments