Внедрение свойства / метода с использованием Autofac в атрибутах фильтра - PullRequest
0 голосов
/ 22 ноября 2018

Попытка использовать autofac для внедрения зависимости по свойству.

Экземпляр всегда нулевой, и зависимость не вводится.Ниже приведен класс, в который необходимо ввести свойство.

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 голосов
/ 22 ноября 2018

Используя метод 3, вам необходимо зарегистрировать AccountService, т. Е.

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

. При использовании UserAccount убедитесь, что он создан с использованием Autofac.

0 голосов
/ 22 ноября 2018

Вы должны запретить вашему контейнеру создавать объекты, ориентированные на данные, например, объект UserAccount.Это приводит к сложным сценариям, таким как тот, в котором вы сейчас находитесь.

В общем случае ваш DI-контейнер должен разрешать только компоненты - это классы в вашей системе, которые содержат поведение приложениябез какого-либо интересного состояния.Эти типы классов, как правило, долго живут или, по крайней мере.Объекты, ориентированные на данные, как и объекты, лучше всего создавать вручную.Невыполнение этого требования может привести к появлению сущностей с большими конструкторами, что легко вызывает запах кода избыточного внедрения конструктора.В качестве исправления вы можете прибегнуть к использованию Property Injection, но это вызывает собственный запах кода, вызывающий 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 должен внедрить эту зависимость и, следовательно, знать о существовании этой зависимости.Но так как этот потребитель был бы ориентированным на поведение классом, типичным решением является использование Constructor Injection на этом этапе:

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);
    }
}
...