1

I am setting up Audit.NET using the below configuration

Configuration.Setup()
.UseEntityFramework(_ => _
    .AuditTypeMapper(t => typeof(AuditLog))
    .AuditEntityAction<AuditLog>((ev, entry, entity) =>
    {
        entity.AuditData = entry.ToJson();
        entity.TableName = entry.EntityType.Name;
        entity.CreatedDate = DateTime.Now;
        entity.CreatedBy = Environment.UserName;
        entity.TablePK = entry.PrimaryKey.First().Value.ToString();
    })
.IgnoreMatchedProperties(true));

However here Environment.UserName is giving windows user name and not the logged in username.

Elsewhere in the application I am able to get the logged in user name like

User.FindFirstValue(ClaimTypes.Name)

How can I acheive this?

Aishwarya
  • 242
  • 1
  • 2
  • 13

1 Answers1

0

There are some ways this can be accomplished, but ultimately it will depend on your specific use case.

If you can't (or don't want to) change your DbContext, you can have a custom action to resolve the HTTP context accessor from the DbContext.

For example, in your program.cs:

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

var app = builder.Build();

// Create the custom action to override the UserName 
Audit.Core.Configuration.AddOnCreatedAction(scope =>
{
    // Get the HTTP context accessor
    var ctxAccessor = scope.GetEntityFrameworkEvent().GetDbContext().GetService<IHttpContextAccessor>();
    // Get the user name
    var userName = ctxAccessor.HttpContext.User.FindFirst(ClaimTypes.Name)?.Value;
    // Override the environment's user name 
    scope.Event.Environment.UserName = userName;
    // Or set a custom field with it
    scope.SetCustomField("UserName", userName);
});

app.Run();

Another way, assuming your audited DbContext inherits from AuditDbContext, is to Inject the IHttpContextAccessor to your DbContext constructor (or use the GetService extension method) to retrieve the user and set a custom audit field with the username.

For example:

public class YourDbContext : AuditDbContext
{
    public YourDbContext(DbContextOptions<YourDbContext> options, IHttpContextAccessor contextAccessor) : base(options)
    {
        var user = contextAccessor.HttpContext.User.FindFirst(ClaimTypes.Name);

        this.AddAuditCustomField("UserName", user);
    }
    // ...
}

or just:

public class YourDbContext : AuditDbContext
{
    public YourDbContext(DbContextOptions<YourDbContext> options) : base(options)
    {
        var ctxAccessor = this.GetService<IHttpContextAccessor>();
        var user = ctxAccessor.HttpContext.User.FindFirst(ClaimTypes.Name);

        this.AddAuditCustomField("UserName", user);
    }
    // ...
}
thepirat000
  • 12,362
  • 4
  • 46
  • 72
  • Thnx, I used your third code, and got error Microsoft.AspNetCore.Http.IHttpContextAccessor.HttpContext.get returned null. in the var user line.. – Aishwarya Mar 17 '23 at 10:23