如何在Autofac中覆盖WebApi项目的IDbSessionManager注册行为?
遇到这种组件注册冲突的情况,最直接且有效的方式是利用Autofac的PreserveExistingDefaults(false)选项来覆盖DataAccess项目中已有的注册,而不是保留两个注册导致冲突。
具体实现步骤
在你的WebApi项目的Autofac注册代码中,添加PreserveExistingDefaults(false)即可让当前注册取代DataAccess中更早的注册:
builder.RegisterType<DbSessionManager>() .As<IDbSessionManager>() .InstancePerRequest() .PreserveExistingDefaults(false);
原理说明
Autofac默认的PreserveExistingDefaults值为true,这意味着当同一个服务类型(这里是IDbSessionManager)有多个注册时,先注册的组件会被保留优先级。而设置为false后,后续的注册会覆盖之前的,这样WebApi中InstancePerRequest的注册就会成为唯一有效的注册,避免了冲突。
为什么之前会报错?
当你同时保留两处注册时,Autofac会优先使用DataAccess中更早注册的无生命周期限制的DbSessionManager。但你在WebApi的请求上下文中尝试解析它时,因为该组件没有绑定到AutofacWebRequest作用域,就会抛出"No scope with a tag matching 'AutofacWebRequest'..."的异常——本质是组件的生命周期和解析环境不匹配。
备选方案:使用OnlyIf条件注册
如果你希望DataAccess中的注册只在非WebApi环境下生效,也可以在DataAccess的注册代码中添加条件判断,避免重复注册:
builder.RegisterType<DbSessionManager>() .As<IDbSessionManager>() .OnlyIf(regContext => // 仅当IDbSessionManager尚未被注册时才生效 !regContext.ComponentRegistry.IsRegistered(new TypedService(typeof(IDbSessionManager))) );
这种方式可以让DataAccess的注册成为“兜底”选项,当WebApi没有覆盖时才会生效。
内容的提问来源于stack exchange,提问作者demo

