question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Saving incoming data to sql server with audit.mvc

See original GitHub issue

I want to save every request in database, but I could not succeed. I did not understand the documentation, thanks for your help.

mysetting class


            Configuration.JsonSettings.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
             
            Audit.EntityFramework.Configuration.Setup()
                .ForContext<DataListContext>(config => config
                    .AuditEventType("{context}:{database}")
                    .ForEntity<MyInternetHatlari>(x => x
                        .Ignore(list => list.MyBirim)
                        .Ignore(list => list.MyBasvuruDurumu)
                        .Ignore(list => list.MyBaglantiTuru)
                        .Ignore(list => list.MyOperator)
                        .Ignore(list => list.CheckDateTime)
                        .Ignore(list => list.Ping)))
                .UseOptOut()
                .IgnoreAny(t => t.Name.StartsWith("MyAudit_")); ;


            Configuration.Setup()
                .UseEntityFramework(ef =>
                {
                    ef.UseDbContext<DataListContext>()
                        .AuditTypeNameMapper(typeName => nameof(MyAudit_MyInternetHatlari))
                        .AuditEntityAction<MyAudit_MyInternetHatlari>((ev, entry, entity) =>
                        {
                            var httpContext = httpContextAccessor.HttpContext;
                            var action = entry.Action;

                            entity.AuditUserName = httpContext.User.Identity.Name;
                            entity.UserId = int.Parse(httpContext.User.Claims
                                .FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value);
                            entity.AuditDate = DateTime.Now;
                            entity.TableName = entry.Table;
                            entity.TableId = (int)entry.PrimaryKey.First().Value;
                            entity.Action = action;


                            if (action is "Update")
                            {
                                entity.AuditData = JsonSerializer.Serialize(entry.Changes,
                                    new JsonSerializerOptions
                                    {
                                        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                                    });
                            }
                            else
                            {
                                entity.AuditData = JsonSerializer.Serialize(entry.ColumnValues,
                                    new JsonSerializerOptions
                                    {
                                        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                                    });
                            }
                        }).IgnoreMatchedProperties();
                });

my dbcontext class

public partial class DataListContext : AuditIdentityDbContext<AspNetUser, AspNetRole, int>
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyAudit_Mvc>(entity =>
        {
            entity.ToTable("MyAudit_Mvc");

            entity.HasKey(x => x.Id);

            entity.Property(x => x.AuditUserName)
            .HasMaxLength(50);

            entity.Property(x => x.Action)
            .HasMaxLength(10);

        });

        base.OnModelCreating(modelBuilder);
    }

}

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
mansurdegirmencicommented, Sep 30, 2021

it works, thank you for everything.


            _ = Audit.Core.Configuration.Setup()
                .UseCustomProvider(new CustomDataProvider(mvc => mvc.ConnectionString(connectionstring)
                        .Schema("dbo")
                        .TableName("MyAudit_MVCCore")
                        .IdColumnName("Id")
                        .CustomColumn("UserName", x => x.GetMvcAuditAction().UserName)
                        .JsonColumnName("AuditData")
                        .CustomColumn("Action", ev => ev.EventType)
                        .CustomColumn("AuditDate", e => DateTime.Now)
                        .CustomColumn("IpAdress", e => e.GetMvcAuditAction().IpAddress),
                    ef => ef
                        .ConnectionString(connectionstring)
                        .Schema("dbo")
                        .TableName("MyAudit_EFCore")
                        .IdColumnName("Id")
                        .CustomColumn("TableName", ev => ev.GetEntityFrameworkEvent().Entries[0].Table)
                        .CustomColumn("TableId",
                            ev => Convert.ToInt32(ev.GetEntityFrameworkEvent().Entries[0].PrimaryKey.FirstOrDefault()
                                .Value))
                        .CustomColumn("UserName", x => "UserName")
                        .CustomColumn("AuditData", delegate(AuditEvent e)
                        {
                            var entries = e.GetEntityFrameworkEvent().Entries[0];

                            object data = entries.Action == "Update" ? entries.Changes : entries.ColumnValues;

                            return JsonSerializer.Serialize(data, new JsonSerializerOptions
                            {
                                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                            });

                        })
                        .CustomColumn("Action", ev => ev.GetEntityFrameworkEvent().Entries[0].Action)
                        .CustomColumn("AuditDate", e => DateTime.Now)));
1reaction
thepirat000commented, Sep 29, 2021

Currently, there is no way to dynamically set up Custom Columns on the SqlDataProvider; all the custom columns are added to the final INSERT/UPDATE.

However, it could be supported in a future version, by providing a new overload to CustomColumn() that accepts a predicate as a function of the audit event, to indicate whether the column should be included or not. So one could do something like this:

Audit.Core.Configuration.Setup()
    .UseSqlServer(cfg => cfg
        .ConnectionString("...")
        .CustomColumn(ev => ev is AuditEventEntityFramework, "EF_Database", ev => ev.GetEntityFrameworkEvent().Database)
        .CustomColumn(ev => ev is AuditEventMvcAction, "MVC_Action", ev => ev.GetMvcAuditAction().ActionName));

But at this time I think the only workaround is to implement a custom Data Provider that encapsulates two different SqlDataProviders, i.e.:

public class CustomDataProvider : AuditDataProvider
{
    private SqlDataProvider _mvcEventsDataProvider;
    private SqlDataProvider _efEventsDataProvider;

    public CustomDataProvider(Action<ISqlServerProviderConfigurator> mvcConfig, Action<ISqlServerProviderConfigurator> efConfig)
    {
        _mvcEventsDataProvider = new SqlDataProvider(mvcConfig);
        _efEventsDataProvider = new SqlDataProvider(efConfig);
    }
    public override object InsertEvent(AuditEvent auditEvent)
    {
        return GetDataProvider(auditEvent).InsertEvent(auditEvent);
    }
    public override async Task<object> InsertEventAsync(AuditEvent auditEvent)
    {
        return await GetDataProvider(auditEvent).InsertEventAsync(auditEvent);
    }
    private SqlDataProvider GetDataProvider(AuditEvent auditEvent)
    {
        return auditEvent switch
        {
            AuditEventEntityFramework _ => _efEventsDataProvider,
            AuditEventMvcAction _ => _mvcEventsDataProvider,
            _ => throw new ArgumentException()
        };
    }
}

So then you can configure separately, like this:

Audit.Core.Configuration.Setup()
    .UseCustomProvider(new CustomDataProvider(
        mvc => mvc
        .ConnectionString(cnnString)
        .TableName("MVC_Events")
        .CustomColumn("MVC_Action", ev => ev.GetMvcAuditAction().ActionName), // Column for MVC events
            ef => ef
            .ConnectionString(cnnString)
            .TableName("EF_Events")
            .CustomColumn("EF_Database", ev => ev.GetEntityFrameworkEvent().Database))); // Column for EF events
Read more comments on GitHub >

github_iconTop Results From Across the Web

How To create Audit table in sql server ? i need to ...
SaveChanges() method and get all the ChangeTracker.Entries().Where(e=>e.State != EntityState.Unchanged) items and create your audit data using ...
Read more >
Various techniques to audit SQL Server databases
Using SQL Server triggers · Connect to the database to audit · In the Columns pane, select the column(s) to audit.
Read more >
Audit Trail And Data Versioning With C# And MVC
Audit Trail C# MVC ... To setup and test, we create two database tables. ... SaveChanges(); // save first so we get back...
Read more >
SQL Server Audit (Database Engine)
SQL Server Audit provides the tools and processes you must have to enable, store, and view audits on various server and database objects....
Read more >
Create ASP.NET Core Web Application With SQL Server ...
Create Read Update Delete data from SQL Server Database using ASP. ... SQL Queries to create the clients table and to insert rows:...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found