3

尝试使用 autofac 通过属性进行依赖注入。

该实例始终为空,并且没有注入依赖项。下面是需要注入属性的类。

public class UserAccount
{
    public IAccountService AccountService { get; set; }

    public string Message()
    {
        return AccountService.Message();
    }
}

我尝试了三种不同的方法来注入属性,但没有一个成功

方法一:

builder.Register(c => {
                var result = new UserAccount();
                var dep = c.Resolve<IAccountService>();
                result.SetDependency(dep);
                return result;
            });

方法二:

builder.RegisterType<UserAccount>().PropertiesAutowired();

方法3:

builder.Register(c => new UserAccount { AccountService = c.Resolve<IAccountService>()});

PS:欢迎上述方法注入。

4

2 回答 2

1

您应该防止让您的容器创建以数据为中心的对象,例如您的UserAccount实体。这会导致复杂的场景,例如您现在所处的场景。

一般来说,你的 DI 容器应该只解析组件——那些是你系统中包含应用程序行为的类,没有任何有趣的状态。这些类型的类通常寿命长,或者至少比以数据为中心的对象寿命更长。

以数据为中心的对象(如实体)最好手动创建。不这样做会导致实体具有大型构造函数,这很容易导致构造函数过度注入代码异味。作为补救措施,您可能会重新使用属性注入,但这会导致其自身的代码异味,导致Temporal Coupling

相反,更好的解决方案是:

  1. 手动创建实体,而不是使用 DI 容器
  2. 使用方法注入向实体提供依赖项,而不是使用属性注入

使用方法注入,您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 Container,不应该负责创建实体和其他以数据为中心的短期对象。

但是,这确实意味着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);
    }
}
于 2018-11-22T09:05:50.557 回答
0

使用方法3,需要注册AccountService,即

        builder.RegisterType<AccountService>().As<IAccountService>();
        builder.Register(c => new UserAccount { AccountService = c.Resolve<IAccountService>()});

当您使用 UserAccount 时,请确保它是使用 Autofac 创建的。

于 2018-11-22T09:22:22.440 回答