Skip to content

Commit

Permalink
Updating WebApi template
Browse files Browse the repository at this point in the history
  • Loading branch information
thepirat000 committed Sep 4, 2024
1 parent f468e8b commit c39591a
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 40 deletions.
2 changes: 1 addition & 1 deletion src/Audit.NET.PostgreSql/Audit.NET.PostgreSql.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="npgsql" Version="8.0.1" />
<PackageReference Include="npgsql" Version="8.0.3" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/Audit.NET.SqlServer/Audit.NET.SqlServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.2" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net7.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.14" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.2" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.25" />
Expand Down
2 changes: 1 addition & 1 deletion templates/WebApi/Audit.WebApi.Template.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata>
<id>Audit.WebApi.Template</id>
<version>7.0.0</version>
<version>8.0.0</version>
<title>Audited AspNetCore Web API</title>
<authors>Federico Colombo</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
Expand Down
58 changes: 35 additions & 23 deletions templates/WebApi/content/Audit.WebApi.Template/AuditSetup.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using Audit.Core.Providers;
using Microsoft.AspNetCore.Mvc;

namespace Audit.WebApi.Template
{
Expand All @@ -9,8 +10,10 @@ public static class AuditSetup
{
/// <summary>Event type to identify the MVC audit logs</summary>
private const string EventTypeMvc = "MVC";

/// <summary>Event type to identify the HTTP audit logs from the middleware</summary>
private const string EventTypeHttp = "HTTP";

#if EnableEntityFramework
/// <summary>Event type to identify the Entity Framework audit logs</summary>
private const string EventTypeEntityFramework = "EF";
Expand All @@ -22,27 +25,34 @@ public static class AuditSetup

#if ServiceInterception
/// <summary>
/// Adds an audited service to the service collection
/// Adds an audited service to the service collection. The service will be intercepted to log the calls to its methods.
/// </summary>
public static IServiceCollection AddAuditedTransient<TService, TImplementation>(this IServiceCollection services)
public static IServiceCollection AddScopedAuditedService<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
return services.AddTransient<TService>(s =>
return services.AddScoped<TService>(s =>
{
var svc = (TService)ActivatorUtilities.CreateInstance<TImplementation>(s);
return AuditProxy.Create(svc, new InterceptionSettings()
// AuditProxy lacks awareness of the service provider, defaulting to the globally configured ScopeFactory and DataProvider.
// To prevent this, we retrieve the ScopeFactory and DataProvider from the service provider and set them in the InterceptionSettings.
var interceptionSettings = new InterceptionSettings()
{
EventType = EventTypeServiceInterception
});
EventType = EventTypeServiceInterception,
AuditScopeFactory = s.GetRequiredService<IAuditScopeFactory>(),
AuditDataProvider = s.GetRequiredService<AuditDataProvider>()
};

var service = (TService)ActivatorUtilities.CreateInstance<TImplementation>(s);

return AuditProxy.Create(service, interceptionSettings);
});
}
#endif

/// <summary>
/// Add the global audit filter to the MVC pipeline
/// </summary>
public static MvcOptions AuditSetupFilter(this MvcOptions mvcOptions)
public static MvcOptions AuditSetupMvcFilter(this MvcOptions mvcOptions)
{
// Add the global MVC Action Filter to the filter chain
mvcOptions.AddAuditFilter(a => a
Expand Down Expand Up @@ -85,25 +95,27 @@ public static void AuditSetupDbContext(this IApplicationBuilder app)
#endif

/// <summary>
/// Setups the audit output
/// Setups the audit scope creation
/// </summary>
public static void AuditSetupOutput(this WebApplication app)
public static IServiceCollection AddAuditScopeFactory(this IServiceCollection services)
{
// TODO: Configure the audit output.
// For more info, see https://github.com/thepirat000/Audit.NET#data-providers.
Audit.Core.Configuration.Setup()
.UseFileLogProvider(_ => _
.Directory(@"C:\Logs")
.FilenameBuilder(ev => $"{ev.StartDate:yyyyMMddHHmmssffff}_{ev.EventType}.json"));
services.AddScoped<IAuditScopeFactory, MyAuditScopeFactory>();

return services;
}

/// <summary>
/// Setups the audit output
/// </summary>
public static IServiceCollection AddAuditDataProvider(this IServiceCollection services)
{
Audit.Core.Configuration.JsonSettings.WriteIndented = true;

// Include the trace identifier in the audit events
var httpContextAccessor = app.Services.GetRequiredService<IHttpContextAccessor>();
Audit.Core.Configuration.AddCustomAction(ActionType.OnScopeCreated, scope =>
{
scope.SetCustomField("TraceId", httpContextAccessor.HttpContext?.TraceIdentifier);
});
services.AddSingleton<AuditDataProvider>(new FileDataProvider(cfg => cfg
.Directory(@"C:\Logs")
.FilenameBuilder(ev => $"{ev.StartDate:yyyyMMddHHmmssffff}_{ev.EventType}.json")));

return services;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Audit.WebApi.Template
{
/// <summary>
/// Custom Audit Scope Factory that includes information to the audit events from the HttpContext
/// </summary>
public class MyAuditScopeFactory : AuditScopeFactory
{
private readonly IHttpContextAccessor _httpContextAccessor;

public MyAuditScopeFactory(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}

/// <inheritdoc />
public override void OnConfiguring(AuditScopeOptions options)
{
}

/// <inheritdoc />
public override void OnScopeCreated(AuditScope auditScope)
{
auditScope.SetCustomField("TraceId", _httpContextAccessor.HttpContext?.TraceIdentifier);
auditScope.SetCustomField("UserName", _httpContextAccessor.HttpContext?.User.Identity?.Name);
}
}
}
20 changes: 10 additions & 10 deletions templates/WebApi/content/Audit.WebApi.Template/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

var builder = WebApplication.CreateBuilder(args);
var builder = WebApplication.CreateBuilder(args);

// Add services to the container and configure the audit global filter
builder.Services.AddControllers(mvc =>
{
mvc.AuditSetupFilter();
mvc.AuditSetupMvcFilter();
});

// Swagger
Expand All @@ -14,16 +13,20 @@
// HTTP context accessor
builder.Services.AddHttpContextAccessor();

// Configure a custom scope factory and data provider
builder.Services.AddAuditScopeFactory();
builder.Services.AddAuditDataProvider();

// TODO: Configure your services
#if ServiceInterception
builder.Services.AddAuditedTransient<IValuesService, ValuesService>();
builder.Services.AddScopedAuditedService<IValuesService, ValuesService>();
#else
builder.Services.AddTransient<IValuesService, ValuesService>();
builder.Services.AddScoped<IValuesService, ValuesService>();
#endif

#if EnableEntityFramework
// TODO: Configure your context connection
builder.Services.AddDbContext<MyContext>(_ => _.UseInMemoryDatabase("default"));
builder.Services.AddDbContextFactory<MyContext>(_ => _.UseInMemoryDatabase("default"), ServiceLifetime.Scoped);
#endif

var app = builder.Build();
Expand Down Expand Up @@ -53,7 +56,4 @@
app.AuditSetupDbContext();
#endif

// Configure the audit output.
app.AuditSetupOutput();

app.Run();
await app.RunAsync();
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Audit.WebApi.Template.Services
{
public interface IValuesService
{
IEnumerable<string?> GetValues();
List<string?> GetValues();
Task<string?> GetAsync(int id);
Task<int> InsertAsync(string value);
Task ReplaceAsync(int id, string value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public ValuesService(MyContext dbContext)
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
}

public IEnumerable<string?> GetValues()
public List<string?> GetValues()
{
return _dbContext.Values.Select(x => x.Value);
return _dbContext.Values.Select(x => x.Value).ToList();
}

public async Task<string?> GetAsync(int id)
Expand Down

0 comments on commit c39591a

Please sign in to comment.