在过滤器属性中使用Autofac进行属性/方法注入

时间:2018-11-22 06:22:01

标签: c# dependency-injection autofac property-injection

尝试使用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:欢迎使用上述方法。

2 个答案:

答案 0 :(得分: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容器不应该负责创建实体和其他以数据为中心的短期对象。

但是,这确实意味着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创建。