打造更好用的 EF 自动审计
程序员文章站
2022-07-09 19:39:36
打造更好用的 EF 自动审计 Intro 上次基于 EF Core 实现了一个自动审计的功能,详细可以参考 ,虽然说多数情况下可以适用,但是因为要显式继承于一个 或 ,所以对代码的侵入性比较强,对于已经无法修改的代码或者已经继承于某一个类了,就无法再继承 了,就没有办法实现自动审计了,在 1.7.0 ......
打造更好用的 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
上一篇: 立秋吃啥蔬菜?这些蔬菜都可以吃
下一篇: 2020最新整理PHP面试题及答案