2

I have many controllers like this:

public class EntityController : Controller
{
    private readonly IEntityRepository _entity;

    public EntityController(IEntityRepository entity)
    {
        _entity = entity;
    }

    [Authorize]
    [HttpPut("{id}")]
    public async ValueTask<IActionResult> Put(int id, [FromBody] Entity entity)
    {
        if (entity == null || entity.Id != id) return BadRequest();
        var updated = await _entity.Update(entity);
        if (updated == null) return NotFound();
        return Ok(updated);
    }
}

I need to implement entities editing (audit) history.

And, since the method is marked as [Authorize], I need to log by which user it was edited. I'm looking at Audit.NET, but I didn't find a way to do it.

A N
  • 209
  • 5
  • 16
Nick Nick
  • 147
  • 2
  • 16
  • 1
    One way would be to use an action filter, either in OnActionExecuting or OnActionExecuted. Something like https://gist.github.com/mgroves/1832983 should get you started. – Mark G Apr 12 '18 at 18:43
  • But how can I save (oldvalue, newvalue, username)? Its just a trigger – Nick Nick Apr 13 '18 at 13:02
  • You get username from context, i.e. ```context.HttpContext.User.Identity.Name``` and parameters from ```context.ActionArguments```. Assuming you have the PK in the model you can lookup the old values. – Mark G Apr 13 '18 at 16:42
  • I haven't tried it, but maybe try the [audit](https://www.nuget.org/packages/Z.EntityFramework.Plus.Audit.EFCore/) component of Entity Framework Plus instead which has some good [examples](http://entityframework-plus.net/audit). – Mark G Apr 13 '18 at 16:47

2 Answers2

5

The Audit.NET EF Provider allows to customize the audit entity before saving it. This has to be done at the startup with a so-called AuditEntity Action: an action that is triggered for each entity being modified.

So, you can make this action retrieve the user name from the current HttpContext and store it in a UserName property on your audit entities.

On your asp net startup code, setup a way to obtain the current HttpContext and configure the action to retrieve the username from the context:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Add the HttpContextAccessor if needed.
        services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

        // Get the service provider to access the http context
        var svcProvider = services.BuildServiceProvider();

        // Configure Audit.NET
        Audit.Core.Configuration.Setup()
            .UseEntityFramework(x => x
                .AuditTypeNameMapper(typeName => "Audit_" + typeName)
                .AuditEntityAction((evt, ent, auditEntity) =>
                {
                    // Get the current HttpContext 
                    var httpContext = svcProvider.GetService<IHttpContextAccessor>().HttpContext;
                    // Store the identity name on the "UserName" property of the audit entity
                    ((dynamic)auditEntity).UserName = httpContext.User?.Identity.Name;
                }));
    }
}

This is assuming your audit entities have a common UserName property.

If your Audit Entities already inherits from an interface or base class including the UserName, you can use the generic AuditEntityAction<T> instead.

Audit.Core.Configuration.Setup()
    .UseEntityFramework(x => x
        .AuditTypeNameMapper(typeName => "Audit_" + typeName)
        .AuditEntityAction<IUserName>((evt, ent, auditEntity) =>
        {
            var httpContext = svcProvider.GetService<IHttpContextAccessor>().HttpContext;
            auditEntity.UserName = httpContext.User?.Identity.Name;
        }));
thepirat000
  • 10,774
  • 4
  • 38
  • 63
0

To get UserID in IOC :

var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value 

how-get-current-user-in-asp-net-core

JohnFI
  • 35
  • 4