c# - Autofac 模块顺序注册导致对象被注入其默认实例值 (default(T))
问题描述
我面临 Autofac 注册的问题。简而言之,如果我在配置之前注册模型,当我加载配置时,它可以顺利运行,但是,如果我在注册配置之后注册模型,配置模型将加载它们的默认类型(默认(T))。下面是重现问题的代码:
using System;
using System.IO;
using Autofac;
using Microsoft.Extensions.Configuration;
namespace AutofacConfigurationTest.CrossCutting
{
public class ModuleModel : Module
{
protected override void Load(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<Cache.Configuration>()
.As<Cache.IConfiguration>();
containerBuilder.RegisterType<Repository.Configuration>()
.As<Repository.IConfiguration>();
}
}
public class ModuleConfiguration : Module
{
protected override void Load(ContainerBuilder containerBuilder)
{
var configurationRoot = new Configuration.Container().ConfigurationRoot;
containerBuilder.RegisterInstance(configurationRoot).As<IConfigurationRoot>();
containerBuilder
.RegisterInstance(configurationRoot.GetSection(Cache.Configuration.Name)
.Get<Cache.Configuration>()).As<Cache.IConfiguration>();
containerBuilder
.RegisterInstance(configurationRoot.GetSection(Repository.Configuration.Name)
.Get<Repository.Configuration>()).As<Repository.IConfiguration>();
}
}
public class Container
{
public IContainer Kernel { get; }
public Container()
{
var containerBuilder = new ContainerBuilder();
// uncomment the line below to make it work //
containerBuilder.RegisterModule(new ModuleModel()); // if we register the models here, before the configuration, the configuration works properly //
containerBuilder.RegisterModule(new ModuleConfiguration());
// comment the line below to make it work //
containerBuilder.RegisterModule(new ModuleModel()); // if we register the models here, after the configuration, the configuration cannot load the data //
Kernel = containerBuilder.Build();
}
}
}
namespace AutofacConfigurationTest.Configuration
{
public class Container
{
private const string ConfigurationFile = "AppSettings.json";
public Container()
{
ConfigurationRoot = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(ConfigurationFile).Build();
}
public IConfigurationRoot ConfigurationRoot { get; }
}
}
namespace AutofacConfigurationTest.Cache
{
public enum Engine
{
None,
Default
}
public interface IConfiguration
{
Engine Engine { get; set; }
int Duration { get; set; }
string ConnectionString { get; set; }
}
public class Configuration : IConfiguration
{
public const string Name = "Cache";
public Engine Engine { get; set; }
public int Duration { get; set; }
public string ConnectionString { get; set; }
}
}
namespace AutofacConfigurationTest.Repository
{
public enum Engine
{
None,
LiteDb
}
public interface IConfiguration
{
Engine Engine { get; set; }
string ConnectionString { get; set; }
}
public class Configuration : IConfiguration
{
public const string Name = "Repository";
public Engine Engine { get; set; }
public string ConnectionString { get; set; }
}
}
namespace AutofacConfigurationTest
{
internal class Program
{
private static IContainer _container;
private static void RegisterServices() => _container = new CrossCutting.Container().Kernel;
private static void DisposeServices()
{
if (_container != null &&
_container is IDisposable disposable)
disposable.Dispose();
}
private static void Main(string[] args)
{
try
{
RegisterServices();
// the following objects will be have a default(T) instance
// if the in the Autofac modules the Model is registered AFTER the Configuration
var cacheConfiguration = _container.Resolve<Cache.IConfiguration>();
var repositoryConfiguration = _container.Resolve<Repository.IConfiguration>();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
DisposeServices();
}
}
}
}
我有第二个问题要问你:我使用接口来强制我的模型中的合同。简而言之,这些接口从来没有注入任何地方,只是为了让我更容易维护。我应该删除这些模型的 DI/IoC,还是有任何理由将模型注册保留在容器中?
解决方案
观察到的行为差异现在取决于模块注册的顺序,这是由于两个模块都在注册与Cache.IConfiguration
和键控的服务Repository.IConfiguration
。因此,最后注册的模块将“获胜”。
最后注册时ModuleModel
,它将覆盖两个配置接口的任何先前注册,并且解析将产生Cache.Configuration
和的实例Repository.Configuration
。
如果ModuleConfiguration
最后注册,解析将产生对象提供的实例configurationRoot
。
从这两个模块推断您的意图,因为ModuleConfiguration
注册实际上是在尝试解析Cache.Configuration
和Repository.Configuration
,ModuleModel
所以必须注册这些类型,这些类型键控到这些类型,而不是键控到接口。您使用.AsSelf()
而不是.As<some interface>()
. 阅读更多关于AsSelf
这里。
推荐阅读
- git - 尽管提供了所需的路径,如何修复“无法在您的路径中找到 Git”错误
- flutter - Flutter 获取库 - 未处理的异常:NoSuchMethodError:在 null 上调用了 getter 'overlay'。E/颤振(29207):接收器:空
- javascript - 检查 redux 存储中的数据更新
- python - 需要找到'$word;' 字符串中的模式
- python - 我可以做些什么来提高我的 CNN Keras 中的 96%(f 分数)?
- powershell - Powershell 中的 SVN 报告
- node.js - Node.js 应用程序可以在 heroku 上运行,但如果从 github 下载则不能
- apache - 如何诊断网络连接问题
- java - Java Stream 过滤器嵌套对象返回顶级字段
- python - 如何在python中找到最大值?