首页 > 解决方案 > 实例化类时可以使用 Ninject 注入特定参数吗?

问题描述

就本示例而言,我有一个“用户”类,它需要接收对我的 EmailService 的访问权限。每当创建一个新的用户实例 ( var user = new User(emailServiceInstance);) 我不希望将 EmailService 实例作为参数包含在内,因为并非所有调用者都会知道它。我想让 Ninject 注入它。所以通常 EmailService 的绑定看起来像这样:

kernel.Bind<IEmailService>().To<EmailService>().InSingletonScope();

但我想在我的 User 类构造函数中包含更多参数。我想传递一些参数并注入 EmailService。这可能吗?从它的调用者那里,用户类将被实例化为:

var user = new User(firstName,LastName, [notsure])

然后我的 User 类构造函数将如下所示:

public User(string firstName, stringLastName, EmailService emailService)

First 和 Lastname 将被传入,电子邮件服务将使用 Ninject 实例化/注入。可能吗?创建此绑定的正确语法是什么?

标签: c#asp.net-mvcdependency-injectionninject

解决方案


构造函数注入和属性注入都不适合您的场景。在DIPP&P的第 4.3 节中,Mark Seemann 和我声明:

除了通常的数据成员集之外还包含行为的实体将很容易获得各种方法,每个方法都需要它们自己的依赖项。尽管您可能很想使用构造函数注入来注入此类依赖项,但这会导致需要创建每个此类实体及其所有依赖项的情况,即使对于给定的用例可能只需要少数几个。这使测试实体的逻辑变得复杂,因为所有依赖项都需要提供给构造函数,即使测试可能只对少数依赖项感兴趣。Method Injection [...] 提供了一个更好的选择。

使用方法注入,您的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方法不存储其传入的依赖项。这是故意的,这就是方法注入与构造函数注入和属性注入不同的原因。当在构造之后将依赖项应用于类时(这就是属性注入所发生的情况),它会导致Temporal Coupling。通过让方法使用依赖项,但不存储依赖项,它可以防止发生时间耦合。

有关方法注入以及如何将其应用于实体等类的更详细讨论可以在依赖注入原理、实践和模式的第 4.3 节中找到。


推荐阅读