#c# #asp.net-mvc #dependency-injection #ninject
#c# #asp.net-mvc #внедрение зависимостей #ninject
Вопрос:
Для этого примера у меня есть класс «User», который должен получать доступ к моему EmailService. Всякий раз, когда создается новый экземпляр user ( var user = new User(emailServiceInstance);
), я не хочу, чтобы экземпляр EmailService включался в качестве параметра, потому что не все вызывающие пользователи будут знать об этом. Я хочу, чтобы Ninject ввел его. Поэтому обычно привязка для EmailService будет выглядеть примерно так:
kernel.Bind<IEmailService>().To<EmailService>().InSingletonScope();
Но я хотел бы включить больше параметров в свой конструктор пользовательского класса. Я хотел бы передать некоторые параметры и также ввести EmailService. Возможно ли это?
Из его вызывающих абонентов пользовательский класс будет создан с помощью чего-то вроде:
var user = new User(firstName,LastName, [notsure])
И тогда мой конструктор пользовательского класса будет выглядеть так:
public User(string firstName, stringLastName, EmailService emailService)
Будут переданы имя и фамилия, а служба электронной почты будет создана / введена с помощью Ninject.
Возможно ли это? Каким будет правильный синтаксис для создания этой привязки?
Комментарии:
1. Вместо инъекции конструктора вы можете использовать инъекцию свойств
2. Вы должны стараться избегать смешивания данных и поведения. Вводить поведение (известное во время разработки) через конструктор и передавать данные (известные во время выполнения) через аргументы метода.
User
Похоже, что ваш класс пытается быть и тем, и другим.
Ответ №1:
Ни внедрение конструктора, ни внедрение свойств не подходят для вашего сценария. В разделе 4.3 DIPP amp; P Марк Симанн и я заявляем, что:
Сущности, которые содержат поведение, помимо их обычного набора элементов данных, легко получат широкий спектр методов, каждый из которых требует своих собственных зависимостей. Хотя у вас может возникнуть соблазн использовать внедрение конструктора для внедрения таких зависимостей, это приводит к ситуации, когда каждый такой объект должен быть создан со всеми его зависимостями, хотя для данного варианта использования может потребоваться лишь несколько. Это усложняет тестирование логики объекта, поскольку все зависимости должны быть предоставлены конструктору, даже если тест может быть заинтересован только в нескольких зависимостях. Внедрение метода […] предлагает лучшую альтернативу.
Используя внедрение метода, ваша User
сущность станет чем-то следующим:
public class User
{
public string FirstName { get; }
public string LastName { get; }
public string PasswordHash { get; }
public User(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName;
}
public void ResetPassword(
IEmailService mailService, IPasswordGenerator generator)
{
var password = generator.Generate();
this.PasswordHash = generator.Hash(password);
// Warning: this is just an example, but not a good security practice.
// Mailing passwords is a good way to be shamed on plaintextoffenders.com
mailService.SendMail($@"
Hello {this.FirstName}
We have received new password request for your account.
Your new password is: {password}.");
}
}
Обратите внимание, что ResetPassword
метод не сохраняет свои входящие зависимости. Это сделано намеренно, и именно это отличает внедрение метода как от внедрения конструктора, так и от внедрения свойства. Когда зависимости применяются к классу после построения (что и происходит при внедрении свойств), это приводит к временной связи. Позволяя методу использовать зависимость, но не сохранять зависимость, он предотвращает возникновение временной связи.
Более подробное обсуждение внедрения метода и того, как применить его к таким классам, как entities, можно найти в разделе 4.3 «Принципы, практики и шаблоны внедрения зависимостей«.