Skip to content

Commit

Permalink
Adding wrapper providers for lazy instantiation of the data provider.…
Browse files Browse the repository at this point in the history
… Lazy, Deferred and Conditional DataProviders.
  • Loading branch information
thepirat000 committed Feb 11, 2024
1 parent e002829 commit f0bc497
Show file tree
Hide file tree
Showing 33 changed files with 1,364 additions and 130 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ All notable changes to Audit.NET and its extensions will be documented in this f

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).

## [24.0.0] - 2024-:
- Audit.NET: Adding wrapper providers to allow lazy instantiation of the data provider. LazyDataProvider, DeferredDataProvider and ConditionalDataProvider.

## [23.0.0] - 2023-12-13:
- Beginning with version 23.0.0, this library and its extensions has discontinued support for older .NET Framework and Entity Framework (versions that lost Microsoft support before 2023).
New minimum supported .NET framework versions are net462, netstandard2.0 & net6.0. (#637)
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>23.0.0</Version>
<Version>24.0.0</Version>
<PackageReleaseNotes></PackageReleaseNotes>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
</PropertyGroup>
Expand Down
128 changes: 92 additions & 36 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public AmazonQldbDataProvider(Action<IAmazonQldbProviderConfigurator> config)
}
}

public override object Serialize<T>(T value)
public override object CloneValue<T>(T value, AuditEvent auditEvent)
{
if (value == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public AzureCosmosDataProvider(Action<IAzureCosmosProviderConfigurator> config)
IdBuilder = cosmosDbConfig._idBuilder;
}

public override object Serialize<T>(T value)
public override object CloneValue<T>(T value, AuditEvent auditEvent)
{
if (value == null)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Audit.NET.MongoDB/Providers/MongoDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,11 @@ private void SerializeExtraFields(AuditEvent auditEvent)
{
foreach(var k in auditEvent.CustomFields.Keys.ToList())
{
auditEvent.CustomFields[k] = Serialize(auditEvent.CustomFields[k]);
auditEvent.CustomFields[k] = CloneValue(auditEvent.CustomFields[k], auditEvent);
}
}

public override object Serialize<T>(T value)
public override object CloneValue<T>(T value, AuditEvent auditEvent)
{
if (value == null || value is string)
{
Expand All @@ -199,7 +199,7 @@ public override object Serialize<T>(T value)
return value.ToBsonDocument(typeof(object));
}

return base.Serialize(value);
return base.CloneValue(value, auditEvent);
}

protected virtual BsonDocument ParseBson(AuditEvent auditEvent)
Expand Down
2 changes: 1 addition & 1 deletion src/Audit.NET.RavenDB/Providers/RavenDbDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public RavenDbDataProvider(Action<IRavenDbProviderConfigurator> config)
_documentStore.Initialize();
}

public override object Serialize<T>(T value)
public override object CloneValue<T>(T value, AuditEvent auditEvent)
{
if (value == null)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Audit.NET/Audit.NET.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

<ItemGroup>
<None Include="..\..\LICENSE" Pack="true" PackagePath="LICENSE" />
<None Include="..\..\README.md" Pack="true" PackagePath="\"/>
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>

<ItemGroup>
Expand All @@ -45,7 +45,7 @@
</ItemGroup>

<ItemGroup>
<None Include="images\icon.png" Pack="true" PackagePath="\"/>
<None Include="images\icon.png" Pack="true" PackagePath="\" />
</ItemGroup>

</Project>
7 changes: 5 additions & 2 deletions src/Audit.NET/AuditDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ namespace Audit.Core
public abstract class AuditDataProvider
{
/// <summary>
/// Override this method to provide a different serialization method for the values that need to be serialized before saving.
/// Override this method to provide a different cloning method for the values that need to be pre-serialized before saving.
/// (old target value and custom fields)
/// </summary>
public virtual object Serialize<T>(T value)
/// <param name="value">The value to clone</param>
/// <param name="auditEvent">The audit event associated to the value being serialized</param>
public virtual object CloneValue<T>(T value, AuditEvent auditEvent)
{
if (value == null)
{
return null;
}

if (value is string)
{
return value;
Expand Down
14 changes: 8 additions & 6 deletions src/Audit.NET/AuditScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,18 @@ internal AuditScope(AuditScopeOptions options)
{
_event.CustomFields = new Dictionary<string, object>();
}

ProcessExtraFields(options.ExtraFields);

if (options.TargetGetter != null)
{
var targetValue = options.TargetGetter.Invoke();
_event.Target = new AuditTarget
{
Old = _dataProvider.Serialize(targetValue),
Old = _dataProvider.CloneValue(targetValue, _event),
Type = targetValue?.GetType().GetFullTypeName() ?? "Object"
};
}
ProcessExtraFields(options.ExtraFields);
}
#endregion

Expand Down Expand Up @@ -140,7 +142,7 @@ public void SetTargetGetter(Func<object> targetGetter)
var targetValue = targetGetter.Invoke();
_event.Target = new AuditTarget
{
Old = _dataProvider.Serialize(targetValue),
Old = _dataProvider.CloneValue(targetValue, _event),
Type = targetValue?.GetType().GetFullTypeName() ?? "Object"
};
}
Expand Down Expand Up @@ -175,10 +177,10 @@ public void Comment(string format, params object[] args)
/// <typeparam name="TC">The type of the value.</typeparam>
/// <param name="fieldName">Name of the field.</param>
/// <param name="value">The value object.</param>
/// <param name="serialize">if set to <c>true</c> the field is serialized immediately.</param>
/// <param name="serialize">if set to <c>true</c> the value will be serialized immediately.</param>
public void SetCustomField<TC>(string fieldName, TC value, bool serialize = false)
{
_event.CustomFields[fieldName] = serialize ? _dataProvider.Serialize(value) : value;
_event.CustomFields[fieldName] = serialize ? _dataProvider.CloneValue(value, _event) : value;
}

/// <summary>
Expand Down Expand Up @@ -477,7 +479,7 @@ private void EndEvent()
_event.Duration = Convert.ToInt32((_event.EndDate.Value - _event.StartDate).TotalMilliseconds);
if (_targetGetter != null)
{
_event.Target.New = _dataProvider.Serialize(_targetGetter.Invoke());
_event.Target.New = _dataProvider.CloneValue(_targetGetter.Invoke(), _event);
}
}

Expand Down
16 changes: 10 additions & 6 deletions src/Audit.NET/AuditScopeOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Reflection;
using Audit.Core.Providers.Wrappers;

namespace Audit.Core
{
Expand All @@ -24,14 +25,17 @@ public class AuditScopeOptions
public object ExtraFields { get; set; }

/// <summary>
/// Gets or Sets the data provider builder.
/// Sets the data provider as a factory method that will be invoked the first time it's needed and only once. This is a shortcut to set a LazyDataProvider.
/// </summary>
public Func<AuditDataProvider> DataProviderFactory { get; set; }

public Func<AuditDataProvider> DataProviderFactory
{
set => DataProvider = new LazyDataProvider(value);
}

/// <summary>
/// Gets or sets the data provider to use.
/// </summary>
public AuditDataProvider DataProvider { get { return DataProviderFactory?.Invoke(); } set { DataProviderFactory = () => value; } }
public AuditDataProvider DataProvider { get; set; }

/// <summary>
/// Gets or sets the event creation policy to use.
Expand Down Expand Up @@ -97,7 +101,7 @@ public AuditScopeOptions(
TargetGetter = targetGetter;
ExtraFields = extraFields;
CreationPolicy = creationPolicy ?? Configuration.CreationPolicy;
DataProviderFactory = dataProvider != null ? () => dataProvider : Configuration.DataProviderFactory;
DataProvider = dataProvider ?? Configuration.DataProvider;
IsCreateAndSave = isCreateAndSave;
AuditEvent = auditEvent;
SkipExtraFrames = skipExtraFrames;
Expand Down Expand Up @@ -126,7 +130,7 @@ public AuditScopeOptions(Action<IAuditScopeOptionsConfigurator> config)
TargetGetter = scopeConfig._options.TargetGetter;
ExtraFields = scopeConfig._options.ExtraFields;
CreationPolicy = scopeConfig._options.CreationPolicy;
DataProviderFactory = scopeConfig._options.DataProviderFactory;
DataProvider = scopeConfig._options.DataProvider;
IsCreateAndSave = scopeConfig._options.IsCreateAndSave;
AuditEvent = scopeConfig._options.AuditEvent;
SkipExtraFrames = scopeConfig._options.SkipExtraFrames;
Expand Down
9 changes: 8 additions & 1 deletion src/Audit.NET/AuditScopeOptionsConfigurator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Reflection;
using Audit.Core.Providers.Wrappers;

namespace Audit.Core
{
Expand Down Expand Up @@ -31,12 +32,18 @@ public IAuditScopeOptionsConfigurator DataProvider(AuditDataProvider dataProvide
return this;
}

public IAuditScopeOptionsConfigurator DataProvider(Func<AuditDataProvider> dataProviderFactory)
public IAuditScopeOptionsConfigurator DataProviderLazyFactory(Func<AuditDataProvider> dataProviderFactory)
{
_options.DataProviderFactory = dataProviderFactory;
return this;
}

public IAuditScopeOptionsConfigurator DataProviderDeferredFactory(Func<AuditEvent, AuditDataProvider> dataProviderFactory)
{
_options.DataProvider = new DeferredDataProvider(dataProviderFactory);
return this;
}

public IAuditScopeOptionsConfigurator EventType(string eventType)
{
_options.EventType = eventType;
Expand Down
12 changes: 8 additions & 4 deletions src/Audit.NET/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading.Tasks;
using System.Text.Json;
using System.Text.Json.Serialization;
using Audit.Core.Providers.Wrappers;

namespace Audit.Core
{
Expand All @@ -26,20 +27,23 @@ public static class Configuration
public static EventCreationPolicy CreationPolicy { get; set; }

/// <summary>
/// Gets or Sets the Default data provider factory.
/// Sets the Default data provider as a factory method that will be invoked the first time it's needed and only once. This is a shortcut to set a LazyDataProvider.
/// </summary>
public static Func<AuditDataProvider> DataProviderFactory { get; set; }
public static Func<AuditDataProvider> DataProviderFactory
{
set => DataProvider = new LazyDataProvider(value);
}

/// <summary>
/// Gets or Sets the Default data provider instance.
/// </summary>
public static AuditDataProvider DataProvider { get { return DataProviderFactory?.Invoke(); } set { DataProviderFactory = () => value; } }
public static AuditDataProvider DataProvider { get; set; }

/// <summary>
/// Gets the Default data provider instance as the specified type. Returns null if the data provider is not of the given type.
/// </summary>
/// <typeparam name="T">The AuditDataProvider type</typeparam>
public static T DataProviderAs<T>() where T : AuditDataProvider { return DataProviderFactory?.Invoke() as T; }
public static T DataProviderAs<T>() where T : AuditDataProvider { return DataProvider as T; }

/// <summary>
/// Gets or Sets a value that indicates if the logged Type Names should include the namespace. Default is false.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using Audit.Core.Providers.Wrappers;

namespace Audit.Core.ConfigurationApi
{
public class ConditionalDataProviderConfigurator : IConditionalDataProviderConfigurator
{
internal List<ConditionalDataProvider.GuardCondition> _guardConditions = new List<ConditionalDataProvider.GuardCondition>();

/// <inheritdoc />
public IConditionalDataProviderConfigurator When(Func<AuditEvent, bool> guardCondition, Func<AuditEvent, AuditDataProvider> dataProviderFactory)
{
_guardConditions.Add(new ConditionalDataProvider.GuardCondition()
{
Guard = guardCondition,
DataProvider = new DeferredDataProvider(dataProviderFactory)
});

return this;
}

/// <inheritdoc />
public IConditionalDataProviderConfigurator When(Func<AuditEvent, bool> guardCondition, Func<AuditDataProvider> dataProviderInitializer)
{
_guardConditions.Add(new ConditionalDataProvider.GuardCondition()
{
Guard = guardCondition,
DataProvider = new LazyDataProvider(dataProviderInitializer)
});

return this;
}

/// <inheritdoc />
public IConditionalDataProviderConfigurator When(Func<AuditEvent, bool> guardCondition, AuditDataProvider dataProvider)
{
_guardConditions.Add(new ConditionalDataProvider.GuardCondition()
{
Guard = guardCondition,
DataProvider = dataProvider
});

return this;
}

/// <inheritdoc />
public void Otherwise(Func<AuditEvent, AuditDataProvider> dataProviderFactory)
{
_guardConditions.Add(new ConditionalDataProvider.GuardCondition()
{
Guard = _ => true,
DataProvider = new DeferredDataProvider(dataProviderFactory)
});
}

/// <inheritdoc />
public void Otherwise(Func<AuditDataProvider> dataProviderInitializer)
{
_guardConditions.Add(new ConditionalDataProvider.GuardCondition()
{
Guard = _ => true,
DataProvider = new LazyDataProvider(dataProviderInitializer)
});
}

/// <inheritdoc />
public void Otherwise(AuditDataProvider dataProvider)
{
_guardConditions.Add(new ConditionalDataProvider.GuardCondition()
{
Guard = _ => true,
DataProvider = dataProvider
});
}
}
}
17 changes: 13 additions & 4 deletions src/Audit.NET/ConfigurationApi/Configurator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Audit.Core.Providers;
using Audit.Core.Providers.Wrappers;

namespace Audit.Core.ConfigurationApi
{
Expand Down Expand Up @@ -45,15 +46,23 @@ public ICreationPolicyConfigurator Use(Action<IDynamicDataProviderConfigurator>
{
return UseDynamicProvider(config);
}
public ICreationPolicyConfigurator UseFactory(Func<AuditDataProvider> dataProviderFactory)
public ICreationPolicyConfigurator UseDeferredFactory(Func<AuditEvent, AuditDataProvider> dataProviderFactory)
{
Configuration.DataProviderFactory = dataProviderFactory;
Configuration.DataProvider = new DeferredDataProvider(dataProviderFactory);
return new CreationPolicyConfigurator();
}
public ICreationPolicyConfigurator Use(Func<AuditDataProvider> dataProviderFactory)
public ICreationPolicyConfigurator UseLazyFactory(Func<AuditDataProvider> dataProviderInitializer)
{
return UseFactory(dataProviderFactory);
Configuration.DataProvider = new LazyDataProvider(dataProviderInitializer);
return new CreationPolicyConfigurator();
}

public ICreationPolicyConfigurator UseConditional(Action<IConditionalDataProviderConfigurator> config)
{
Configuration.DataProvider = new ConditionalDataProvider(config);
return new CreationPolicyConfigurator();
}

public ICreationPolicyConfigurator Use(AuditDataProvider provider)
{
return UseCustomProvider(provider);
Expand Down
Loading

0 comments on commit f0bc497

Please sign in to comment.