打造更好用的 EF 自动审计
- 作者: 我是老王的老婆i
- 来源: 51数据库
- 2021-08-16
打造更好用的 ef 自动审计
intro
上次基于 ef core 实现了一个自动审计的功能,详细可以参考 ,虽然说多数情况下可以适用,但是因为要显式继承于一个 auditdbcontextbase 或 auditdbcontext,所以对代码的侵入性比较强,对于已经无法修改的代码或者已经继承于某一个类了,就无法再继承 auditdbcontext 了,就没有办法实现自动审计了,在 weihanli.entityframework 1.7.0 新版本里引入了 aop 的设计,结合 aop 来实现就简单很多了,不再需要对原有的 dbcontext 有任何修改就可以轻松实现自动审计了,下面来看如何做
实例演示
服务注册
使用 addproxydbcontext 代替 adddbcontext,addproxydbcontextpool 代替 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();
审计日志输出结果


more
这样以来就不需要修改原有代码了~~,心情大好,哈哈~
如果应用多有多个 dbcontext 有的需要审计,有的不需要审计,则可以在配置的时候指定具体的 dbcontext类型如 testdbcontext,这样就只会启用 testdbcontext 的自动审计,别的 dbcontext 比如 test2dbcontext 就不会自动审计了
reference
- https://github.com/weihanli/weihanli.entityframework/blob/dev/samples/weihanli.entityframework.core3_0sample/program.cs
- https://www.nuget.org/packages/weihanli.entityframework/
推荐阅读
