尝试使用autofac按属性进行依赖项注入。
该实例始终为null,并且没有注入依赖项。 下面是需要注入属性的类。
public class UserAccount
{
public IAccountService AccountService { get; set; }
public string Message()
{
return AccountService.Message();
}
}
我尝试了三种不同的方式来注入财产,但没有一个成功
方法1:
builder.Register(c => {
var result = new UserAccount();
var dep = c.Resolve<IAccountService>();
result.SetDependency(dep);
return result;
});
方法2:
builder.RegisterType<UserAccount>().PropertiesAutowired();
方法3:
builder.Register(c => new UserAccount { AccountService = c.Resolve<IAccountService>()});
PS:欢迎使用上述方法。
答案 0 :(得分:1)
您应避免让容器创建以数据为中心的对象,例如UserAccount
实体。这会导致复杂的场景,例如您现在所处的场景。
通常,您的DI容器应仅解析组件-这些是系统中包含应用程序行为的类,没有任何有趣的状态。这些类型的类通常是长期存在的,或者至少是长期存在的。以数据为中心的对象(例如实体)最好由手工创建。不这样做会导致实体具有大型构造函数,这很容易导致构造函数注入过多的代码异味。作为补救措施,您可能会回过头来使用属性注入,但这会导致自身的代码异味,从而引起Temporal Coupling。
相反,更好的解决方案是:
使用方法注入,您的UserAccount
将如下:
// This answer assumes that this class is an domain entity.
public class UserAccount
{
public Guid Id { get; set; }
public byte[] PasswordHash { get; set; }
public string Message(IAccountService accountService)
{
if (accountService == null) throw new ArgumentNullException(nameof(accountService));
return accountService.Message();
}
}
这确实将将依赖项从Composition Root提供给实体的直接使用者的责任。但是如上所述,这是有意的,因为通常是“合成根”,尤其是DI容器不应该负责创建实体和其他以数据为中心的短期对象。
但是,这确实意味着UserAccount
的直接使用者应注入该依赖项,并由此知道该依赖项的存在。但是由于该使用者将是一个以行为为中心的类,所以典型的解决方案是在该阶段使用构造器注入:
public class UserService : IUserService
{
private readonly IAccountService accountService;
private readonly IUserAccountRepository repo;
public UserService(IAccountService accountService, IUserAccountRepository repo)
{
this.accountService = accountService;
this.repo = repo
}
public void DoSomething(Guid id)
{
UserAccount entity = this.repo.GetById(id);
var message = entity.Message(this.accountService);
}
}
答案 1 :(得分:0)
使用方法3,您需要注册AccountService,即
builder.RegisterType<AccountService>().As<IAccountService>();
builder.Register(c => new UserAccount { AccountService = c.Resolve<IAccountService>()});
并且当您使用UserAccount时,请确保使用Autofac创建。