Вы не должны позволять контейнеру создавать объекты, ориентированные на данные, такие как ваша сущность UserAccount
. Это приводит к сложным сценариям, таким как тот, в котором вы находитесь сейчас.
Как правило, ваш DI-контейнер должен разрешать только компоненты — это классы в вашей системе, которые содержат поведение приложения, но не имеют какого-либо интересного состояния. Эти типы классов обычно живут долго или, по крайней мере, дольше, чем объекты, ориентированные на данные.
Ориентированные на данные объекты, такие как сущности, лучше всего создавать вручную. Несоблюдение этого требования либо привело бы к сущностям с большими конструкторами, что легко вызывает запах кода чрезмерной инъекции конструктора. В качестве исправления вы можете вернуться к внедрению свойств, но это вызывает собственный запах кода, вызванный Временная связь.
Вместо этого лучшим решением является:
- Создание объектов вручную вместо использования контейнера внедрения зависимостей
- Предоставление зависимостей объекту с помощью внедрения методов, а не внедрения свойств.
С внедрением методов ваш 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 для прямого потребителя сущности. Но, как обсуждалось выше, это делается намеренно, поскольку корень композиции в целом и контейнер внедрения зависимостей в частности не должны нести ответственность за создание сущностей и других недолговечных объектов, ориентированных на данные.
Однако это означает, что непосредственный потребитель 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);
}
}
person
Steven
schedule
22.11.2018
UserAccount
тоже создан Autofac? Если вы создадите его вручную (используя операторnew
), он не будет работать, потому что Autofac не участвует в создании объекта. - person KBO   schedule 22.11.2018UserAccount
. - person Steven   schedule 22.11.2018