Skip to content

Commit

Permalink
Remove AutoMapper dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
vicosanz committed Nov 5, 2023
1 parent 0db1681 commit ddd52b2
Show file tree
Hide file tree
Showing 89 changed files with 75,163 additions and 43 deletions.
6 changes: 6 additions & 0 deletions Infoware.EntityFrameworkCore.AuditEntity.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApplication1", "WebApplication1\WebApplication1.csproj", "{B13051FA-BBD1-41A5-A7FB-C9C08733C4DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -21,6 +23,10 @@ Global
{32BBFD0E-4193-48D7-9CFB-241967D3D539}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32BBFD0E-4193-48D7-9CFB-241967D3D539}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32BBFD0E-4193-48D7-9CFB-241967D3D539}.Release|Any CPU.Build.0 = Release|Any CPU
{B13051FA-BBD1-41A5-A7FB-C9C08733C4DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B13051FA-BBD1-41A5-A7FB-C9C08733C4DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B13051FA-BBD1-41A5-A7FB-C9C08733C4DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B13051FA-BBD1-41A5-A7FB-C9C08733C4DE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using AutoMapper;
using Infoware.SensitiveDataLogger.Attributes;
using Infoware.SensitiveDataLogger.Attributes;
using Infoware.SensitiveDataLogger.JsonSerializer;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
Expand All @@ -9,75 +8,81 @@ namespace Infoware.EntityFrameworkCore.AuditEntity.Extensions
{
public static class DbContextExtensions
{
public static Task<int> SaveWithAuditsAsync(this DbContext context, IMapper mapper, ILogJsonSerializer logJsonSerializer,
internal static Task<IBaseAudit?> FactoryBase(Type source)
{
return Task.FromResult(Activator.CreateInstance(source) as IBaseAudit);
}

public static Task<int> SaveWithAuditsAsync(this DbContext context, ILogJsonSerializer logJsonSerializer,
Func<CancellationToken, Task<int>> baseSaveChangesAsync, CancellationToken cancellationToken = default)
{
return SaveWithAuditsAsync(context, mapper, logJsonSerializer, baseSaveChangesAsync, () => new BaseAudit(), cancellationToken);
return SaveWithAuditsAsync(context, logJsonSerializer, FactoryBase, baseSaveChangesAsync, cancellationToken);
}

public static async Task<int> SaveWithAuditsAsync<T>(this DbContext context, IMapper mapper, ILogJsonSerializer logJsonSerializer,
Func<CancellationToken, Task<int>> baseSaveChangesAsync, Func<T> factoryAudit, CancellationToken cancellationToken = default) where T : IBaseAudit
public static async Task<int> SaveWithAuditsAsync<T>(this DbContext context, ILogJsonSerializer logJsonSerializer,
Func<Type, Task<T?>> factoryAudit, Func<CancellationToken, Task<int>> baseSaveChangesAsync, CancellationToken cancellationToken = default) where T : IBaseAudit
{
var operationsUpdatesDeletes = context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Modified || e.State == EntityState.Deleted)
.AddEntries(mapper, logJsonSerializer, factoryAudit);
.AddEntriesAsync(logJsonSerializer, factoryAudit);

var entriesAdded = context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added).ToList();

var result = await baseSaveChangesAsync(cancellationToken);

var operationsAdds = entriesAdded.AddEntries(mapper, logJsonSerializer, factoryAudit, EntityState.Added);
var operationsAdds = entriesAdded.AddEntriesAsync(logJsonSerializer, factoryAudit, EntityState.Added);
context.AddRange(operationsUpdatesDeletes);
context.AddRange(operationsAdds);

await baseSaveChangesAsync(cancellationToken);
return result;
}

public static int SaveWithAudits(this DbContext context, IMapper mapper, ILogJsonSerializer logJsonSerializer, Func<int> baseSaveChanges)
public static int SaveWithAudits(this DbContext context, ILogJsonSerializer logJsonSerializer, Func<int> baseSaveChanges)
{
return SaveWithAudits(context, mapper, logJsonSerializer, baseSaveChanges, () => new BaseAudit());
return SaveWithAudits(context, logJsonSerializer, FactoryBase, baseSaveChanges);
}

public static int SaveWithAudits<T>(this DbContext context, IMapper mapper, ILogJsonSerializer logJsonSerializer, Func<int> baseSaveChanges, Func<T> factoryAudit) where T : IBaseAudit
public static int SaveWithAudits<T>(this DbContext context, ILogJsonSerializer logJsonSerializer,
Func<Type, Task<T?>> factoryAudit, Func<int> baseSaveChanges) where T : IBaseAudit
{
var operationsUpdatesDeletes = context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Modified || e.State == EntityState.Deleted)
.AddEntries(mapper, logJsonSerializer, factoryAudit);
.AddEntriesAsync(logJsonSerializer, factoryAudit);

var entriesAdded = context.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added).ToList();

var result = baseSaveChanges();

var operationsAdds = entriesAdded.AddEntries(mapper, logJsonSerializer, factoryAudit, EntityState.Added);
var operationsAdds = entriesAdded.AddEntriesAsync(logJsonSerializer, factoryAudit, EntityState.Added);
context.AddRange(operationsUpdatesDeletes);
context.AddRange(operationsAdds);

baseSaveChanges();
return result;
}

internal static List<IBaseAudit> AddEntries<T>(this IEnumerable<EntityEntry> entries, IMapper mapper, ILogJsonSerializer logJsonSerializer, Func<T> factoryAudit, EntityState? overrideState = null) where T : IBaseAudit
internal static async Task<List<IBaseAudit>> AddEntriesAsync<T>(this IEnumerable<EntityEntry> entries, ILogJsonSerializer logJsonSerializer,
Func<Type, Task<T?>> factoryAudit, EntityState? overrideState = null) where T : IBaseAudit
{
var result = new List<IBaseAudit>();
if (entries == null) return result;

foreach (var entry in entries)
{
var auditableEntityType = entry.Entity.GetType().GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IAuditable<>));
var auditableEntityType = entry.Entity.GetType().GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IAuditable<>));
if (auditableEntityType != null)
{
var keyName = entry.Metadata.FindPrimaryKey()!.Properties[0]!;
var keyValue = entry.Property(keyName.Name).CurrentValue;

Type entityAuditType = auditableEntityType.GenericTypeArguments.First();

var factory = factoryAudit();
factory.Operation = entry.State.ToString();

IBaseAudit objResult = (IBaseAudit) mapper.Map(factory, typeof(T), entityAuditType);
IBaseAudit? objResult = await factoryAudit(entityAuditType);
objResult!.Operation = entry.State.ToString();

PropertyInfo? prop = entityAuditType.GetProperty("TableId", BindingFlags.Public | BindingFlags.Instance);
if (null != prop && prop.CanWrite)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
Expand All @@ -9,13 +9,12 @@
<Description>Create an individual AuditEntity for selected tables to register changes</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/vicosanz/Infoware.EntityFrameworkCore.AuditEntity</RepositoryUrl>
<Version>1.0.0</Version>
<Version>1.0.1</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="11.0.1" />
<PackageReference Include="Infoware.SensitiveDataLogger" Version="1.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.24" />
</ItemGroup>

</Project>
45 changes: 25 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,6 @@
{
}

public class BlogAuditMapper : Profile
{
public BlogAuditMapper()
{
CreateMap<ExtendedBaseAudit, BlogAudit>();
}
}

```

- Insert Audit table to the DBContext
Expand All @@ -63,29 +55,44 @@
public class MyContext : DbContext
{
private readonly ISessionService _sessionService;
private readonly IMapper _mapper;
private readonly ILogJsonSerializer _logJsonSerializer;

public MyContext(DbContextOptions options, IMapper mapper, ILogJsonSerializer logJsonSerialize, ISessionService sessionService) : base(options)
public MyContext(DbContextOptions options, ILogJsonSerializer logJsonSerialize, ISessionService sessionService) : base(options)
{
_sessionService = sessionService;
_mapper = mapper;
_logJsonSerializer = logJsonSerializer;
}

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
var data = await _sessionService.GetSessionDataAsync();
return await this.SaveWithAuditsAsync(_mapper, _logJsonSerializer,
(cancellationToken) => base.SaveChangesAsync(cancellationToken),
() => new ExtendedBaseAudit()
{
UserId = data.UserId!,
UserName = data.UserName!,
},
return await this.SaveWithAuditsAsync(_logJsonSerializer,
FactoryBase,
(cancellationToken) => base.SaveChangesAsync(cancellationToken),
cancellationToken);
}

internal static Task<IBaseAudit?> FactoryBase(Type source)
{
var result = (IBaseAudit?)Activator.CreateInstance(source);
return Task.FromResult(result);
}


```

- If you extended a base audit with additional fields, you must filled manually

```csharp
internal static async Task<IBaseAudit?> FactoryBase(Type source)
{
var data = await _sessionService.GetSessionDataAsync();

var result = (ExtendedBaseAudit?)Activator.CreateInstance(source);
result!.UserId = data.UserId;
result!.UserName = data.UserName;
return result;
}
```

- Finally you must inject dependencies
Expand All @@ -97,8 +104,6 @@
services.AddTransient<ISessionService, YourSessionService>();

services.AddSingleton<ILogJsonSerializer, LogJsonSerializer>();
//"typeof(MyContext)" charge Mappers from project where context was created
services.AddAutoMapper(new[] { typeof(Program), typeof(MyContext) });

```
## Buy me a coofee
Expand Down
2 changes: 2 additions & 0 deletions Test/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
14 changes: 14 additions & 0 deletions Test/Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Infoware.EntityFrameworkCore.AuditEntity\Infoware.EntityFrameworkCore.AuditEntity.csproj" />
</ItemGroup>

</Project>
46 changes: 46 additions & 0 deletions WebApplication1/BlogContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Infoware.EntityFrameworkCore.AuditEntity;
using Infoware.EntityFrameworkCore.AuditEntity.Extensions;
using Infoware.SensitiveDataLogger.JsonSerializer;
using Microsoft.EntityFrameworkCore;
using Test.Models;

namespace Test
{
public class BlogContext : DbContext
{
public const string DEFAULT_SCHEMA = "blogs";
private readonly ILogJsonSerializer _logJsonSerializer;

public DbSet<Blog> Blogs => Set<Blog>();
public DbSet<BlogAudit> BlogAudits => Set<BlogAudit>();

public BlogContext(DbContextOptions options, ILogJsonSerializer logJsonSerializer) : base(options)
{
_logJsonSerializer = logJsonSerializer;
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}

public override int SaveChanges()
{
throw new NotImplementedException();
}

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
return await this.SaveWithAuditsAsync(_logJsonSerializer,
FactoryBase,
(cancellationToken) => base.SaveChangesAsync(cancellationToken),
cancellationToken);
}

internal static Task<IBaseAudit?> FactoryBase(Type source)
{
var result = (IBaseAudit?)Activator.CreateInstance(source);
return Task.FromResult(result);
}
}
}
25 changes: 25 additions & 0 deletions WebApplication1/CustomDbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Microsoft.EntityFrameworkCore;
using System.Reflection;
using Test;

namespace WebApplication1
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<BlogContext>(
options =>
{
options.UseSqlServer(configuration["ConnectionStrings:DocumentosElectronicosSRI"], sqlOptions =>
{
sqlOptions.MigrationsAssembly(typeof(Program).GetTypeInfo().Assembly.GetName().Name);
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), null);
});
},
ServiceLifetime.Singleton //Showing explicitly that the DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request)
);
return services;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ddd52b2

Please sign in to comment.