美文网首页Amazing .NET.NETdotNET
打造更好用的 EF 自动审计

打造更好用的 EF 自动审计

作者: 天天向上卡索 | 来源:发表于2020-05-02 21:47 被阅读0次

    打造更好用的 EF 自动审计

    Intro

    上次基于 EF Core 实现了一个自动审计的功能,详细可以参考 https://www.cnblogs.com/weihanli/p/auto-audit-for-entity-framework.html ,虽然说多数情况下可以适用,但是因为要显式继承于一个 AuditDbContextBaseAuditDbContext,所以对代码的侵入性比较强,对于已经无法修改的代码或者已经继承于某一个类了,就无法再继承 AuditDBContext 了,就没有办法实现自动审计了,在 WeihanLi.EntityFramework 1.7.0 新版本里引入了 AOP 的设计,结合 AOP 来实现就简单很多了,不再需要对原有的 DbContext 有任何修改就可以轻松实现自动审计了,下面来看如何做

    实例演示

    服务注册

    使用 AddProxyDbContext 代替 AddDbContextAddProxyDbContextPool 代替 AddDbContextPool,会自动注册代理服务,以实现 AOP 拦截

    var services = new ServiceCollection();
    // 使用内置的扩展注册 DbContext 代理服务
    //services.AddProxyDbContext<TestDbContext>(options =>
    //{
    //    options
    //        .UseLoggerFactory(loggerFactory)
    //        //.EnableDetailedErrors()
    //        //.EnableSensitiveDataLogging()
    //        // .UseInMemoryDatabase("Tests")
    //        .UseSqlServer(DbConnectionString)
    //        //.AddInterceptors(new QueryWithNoLockDbCommandInterceptor())
    //        ;
    //});
    
    // 使用内置的扩展注册 DbContextPool 代理服务,只是为了方便使用,只会代理 DbContext
    services.AddProxyDbContextPool<TestDbContext>(options =>
    {
        options
            .UseLoggerFactory(loggerFactory)
            //.EnableDetailedErrors()
            //.EnableSensitiveDataLogging()
            // .UseInMemoryDatabase("Tests")
            .UseSqlServer(DbConnectionString)
            //.AddInterceptors(new QueryWithNoLockDbCommandInterceptor())
            ;
    });
    // 注册 AOP 服务
    services.AddFluentAspects(options =>
    {
        // 配置使用 AuditDbContextInterceptor 拦截 DbContext 的 SaveChanges 和 SaveChangesAsync 方法
        options.InterceptMethod<DbContext>(m =>
                m.Name == nameof(DbContext.SaveChanges)
                || m.Name == nameof(DbContext.SaveChangesAsync))
            .With<AuditDbContextInterceptor>()
            ;
    });
    // 注册 serviceLocator(可选,根据自己需要
    DependencyResolver.SetDependencyResolver(services);
    

    审计配置

    AuditConfig.Configure(builder =>
    {
        builder
            // 配置操作用户获取方式
            .WithUserIdProvider(EnvironmentAuditUserIdProvider.Instance.Value)
            //.WithUnModifiedProperty() // 保存未修改的属性,默认只保存发生修改的属性
            // 保存更多属性
            .EnrichWithProperty("MachineName", Environment.MachineName)
            .EnrichWithProperty(nameof(ApplicationHelper.ApplicationName), ApplicationHelper.ApplicationName)
            // 保存到自定义的存储
            .WithStore<AuditFileStore>()
            .WithStore<AuditFileStore>("logs0.log")
            // 忽略指定实体
            .IgnoreEntity<AuditRecord>()
            // 忽略指定实体的某个属性
            .IgnoreProperty<TestEntity>(t => t.CreatedAt)
            // 忽略所有属性名称为 CreatedAt 的属性
            .IgnoreProperty("CreatedAt")
            ;
    });
    

    使用示例

    DependencyResolver.TryInvokeService<TestDbContext>(dbContext =>
    {
        dbContext.Database.EnsureDeleted();
        dbContext.Database.EnsureCreated();
        var testEntity = new TestEntity()
        {
            Extra = new { Name = "Tom" }.ToJson(),
            CreatedAt = DateTimeOffset.UtcNow,
        };
        dbContext.TestEntities.Add(testEntity);
        dbContext.SaveChanges();
    
        testEntity.CreatedAt = DateTimeOffset.Now;
        testEntity.Extra = new { Name = "Jerry" }.ToJson();
        dbContext.SaveChanges();
    
        dbContext.Remove(testEntity);
        dbContext.SaveChanges();
    
        var testEntity1 = new TestEntity()
        {
            Extra = new { Name = "Tom1" }.ToJson(),
            CreatedAt = DateTimeOffset.UtcNow,
        };
        dbContext.TestEntities.Add(testEntity1);
        var testEntity2 = new TestEntity()
        {
            Extra = new { Name = "Tom2" }.ToJson(),
            CreatedAt = DateTimeOffset.UtcNow,
        };
        dbContext.TestEntities.Add(testEntity2);
        dbContext.SaveChanges();
    });
    DependencyResolver.TryInvokeService<TestDbContext>(dbContext =>
    {
        dbContext.Remove(new TestEntity()
        {
            Id = 2
        });
        dbContext.SaveChanges();
    });
    // disable audit
    AuditConfig.DisableAudit();
    // enable audit
    // AuditConfig.EnableAudit();
    

    审计日志输出结果

    image image

    More

    这样以来就不需要修改原有代码了~,心情大好,哈哈

    如果应用多有多个 DbContext 有的需要审计,有的不需要审计,则可以在配置的时候指定具体的 DbContext类型如 TestDbContext,这样就只会启用 TestDbContext 的自动审计,别的 DbContext 比如 Test2DbContext 就不会自动审计了

    Reference

    相关文章

      网友评论

        本文标题:打造更好用的 EF 自动审计

        本文链接:https://www.haomeiwen.com/subject/smvlghtx.html