Autofac程序集扫描级ExternallyOwned不生效,如何批量设置?
Autofac批量设置ExternallyOwned问题
定义的类型(AutofacDotMemory程序集)
public interface IOutput : IDisposable { void Write(string content); } public class ConsoleOutput : IOutput { public void Write(string content) { Console.WriteLine(content); } public void Dispose() { // TODO release managed resources here } } public interface IDateWriter : IDisposable { void WriteDate(); } public class TodayWriter : IDateWriter { private IOutput _output; public TodayWriter(IOutput output) { this._output = output; } public void WriteDate() { this._output.Write(DateTime.Today.ToShortDateString()); } public void Dispose() { // TODO release managed resources here } }
失败的测试代码
尝试通过程序集扫描批量设置ExternallyOwned,但测试失败:
[Test] public void ExternallyOwnedTest() { var builder = new ContainerBuilder(); builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly) .ExternallyOwned(); builder.RegisterType<ConsoleOutput>().As<IOutput>(); builder.RegisterType<TodayWriter>().As<IDateWriter>(); var container = builder.Build(); var registration = container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDateWriter)), out var foundRegistration); TestContext.WriteLine(registration); var isExternallyOwned = registration && foundRegistration.Ownership == InstanceOwnership.ExternallyOwned; Assert.IsTrue(isExternallyOwned, $"{nameof(TodayWriter)} is not externally owned"); container.Dispose(); }
测试失败原因:TodayWriter未被设置为ExternallyOwned。
生效的单个注册代码
针对单个类型添加ExternallyOwned后测试通过:
[Test] public void ExternallyOwnedTest() { var builder = new ContainerBuilder(); builder.RegisterType<ConsoleOutput>().As<IOutput>(); builder.RegisterType<TodayWriter>().As<IDateWriter>().ExternallyOwned(); // 此处生效 var container = builder.Build(); var registration = container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDateWriter)), out var foundRegistration); TestContext.WriteLine(registration); var isExternallyOwned = registration && foundRegistration.Ownership == InstanceOwnership.ExternallyOwned; Assert.IsTrue(isExternallyOwned, $"{nameof(TodayWriter)} is not externally owned"); container.Dispose(); }
疑问
如何确保指定程序集内的所有类型(或通过Where过滤后的多数类型)都被注册为ExternallyOwned,无需逐个添加该配置?
解决方案
问题核心是程序集扫描的注册和后续手动RegisterType注册是独立的,后注册的会覆盖先注册的配置——你先通过程序集扫描给类型加了ExternallyOwned,但之后又手动注册了TodayWriter和ConsoleOutput,覆盖了之前的配置,导致批量设置失效。
要实现批量配置,正确做法是完全通过程序集扫描注册目标类型,避免重复手动注册,以下是几种可行方案:
方案1:全程序集扫描自动匹配接口
扫描目标程序集,过滤出非接口的实现类,自动注册为它们实现的所有接口,并统一设置ExternallyOwned:
[Test] public void ExternallyOwnedTest() { var builder = new ContainerBuilder(); // 扫描目标程序集,排除接口,只注册实现类,自动匹配所有实现的接口 builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly) .Where(t => !t.IsInterface && typeof(IDisposable).IsAssignableFrom(t)) .AsImplementedInterfaces() .ExternallyOwned(); var container = builder.Build(); var registration = container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDateWriter)), out var foundRegistration); TestContext.WriteLine(registration); var isExternallyOwned = registration && foundRegistration.Ownership == InstanceOwnership.ExternallyOwned; Assert.IsTrue(isExternallyOwned, $"{nameof(TodayWriter)} is not externally owned"); container.Dispose(); }
方案2:扫描时过滤特定类型
如果只需要给程序集中的部分类型批量设置,可以通过Where精准筛选:
builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly) .Where(t => t == typeof(TodayWriter) || t == typeof(ConsoleOutput)) .AsImplementedInterfaces() .ExternallyOwned();
方案3:自定义模块统一配置
对于复杂场景,可创建Autofac模块封装批量注册逻辑,方便复用:
public class ExternallyOwnedModule : Module { protected override void Load(ContainerBuilder builder) { // 在这里定义批量注册规则 builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly) .Where(t => typeof(IDateWriter).IsAssignableFrom(t) || typeof(IOutput).IsAssignableFrom(t)) .AsImplementedInterfaces() .ExternallyOwned(); } } // 测试中使用模块 [Test] public void ExternallyOwnedTest() { var builder = new ContainerBuilder(); builder.RegisterModule<ExternallyOwnedModule>(); var container = builder.Build(); // 后续测试逻辑不变 }
只要避免对同一类型重复注册,批量设置ExternallyOwned就能生效。
内容的提问来源于stack exchange,提问作者Graviton
相关产品推荐
相关产品推荐

