当我转向依赖注入时,使用语句会发生什么

时间:2012-09-10 22:23:24

标签: c# dependency-injection ninject

我目前正在使用以下代码:

public class MyProvider
{
    public MyProvider()
    {
    }

    public void Fetch()
    {
        using (PopClient popClient = new PopClient())
        {
            ....
        }
    }
}

因为我希望能够对Fetch方法进行单元测试,并且由于我无法模拟PopClient,所以我创建了一个接口和一个调用PopClient的包装类。我的更新代码如下:

public class MyProvider
{
    private readonly IPopClient popClient;

    public MyProvider(IPopClient popClient)
    {
        this.popClient = popClient;
    }

    public void Fetch()
    {
        using (var pop3 = popClient)
        {
            ....
        }
    }
}

我正在使用Ninject进行依赖注入,我不太确定using语句在更新的代码中会产生什么样的影响,因为Ninject已经创建了一个PopClient实例并将其注入到构造函数中。

using语句是否会处理pop3对象并将popClient对象单独保留,以便Ninject可以处理它或者using语句是否会干扰Ninject?

在这种情况下,正确的方法是什么?任何见解都会非常有用。

3 个答案:

答案 0 :(得分:14)

pop3变量将被赋予与IPopClient所拥有的popClient对象相同的引用,因此当using语句结束时,两者引用的对象本地变量和实例变量将是Dispose()d,可能会将其置于不一致的状态以供进一步使用。

如果你想使用IPopClient的多个实例,每个Fetch()调用一个,你应该做的是注入“工厂方法”:

public class MyProvider
{
    private readonly Func<IPopClient> createPopClient;

    public MyProvider(Func<IPopClient> popClientFactory)
    {
        this.createPopClient = popClientFactory;
    }

    public void Fetch()
    {
        using (var pop3 = createPopClient())
        {
            ....
        }
    }
}

现在,当您调用Fetch()时,它将执行工厂方法,该方法将返回对IPopClient的新引用,该引用可以在不影响对该方法的任何其他调用的情况下使用然后处理

AutoFac支持为注册类型注入工厂方法,无需任何额外设置(因此,我认为它的名称);我相信在配置Ninject容器时,您需要显式注册“getter”作为给定返回类型的工厂方法(可以像lambda ()=>new PopClient()一样简单,或者它可以使用对容器分辨率的调用法)。

答案 1 :(得分:1)

设置绑定时,请声明范围:

https://github.com/ninject/ninject/wiki/Object-Scopes

Ninject将对它为您创建的对象调用dispose,因此请确保将您的dispose方法写入您为Ninject提供的任何对象中。

答案 2 :(得分:0)

我喜欢@KeithS 的回答,但我想添加一些更新,包括 tools:ignore="UselessParent"、.NET Core 依赖注入和 ConfigureServices

https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection

给定以下类:

MailKit.Net.Smtp

可以像这样添加到public class MailService { private readonly SmtpSettings _settings; private readonly Func<ISmtpClient> _smtpClientFactory; public MailService(SmtpSettings settings, Func<ISmtpClient> smtpClientFactory) { _settings = settings; _smtpClientFactory = smtpClientFactory; } public async Task SendEmailAsync(string to, string subject, MimeEntity body, CancellationToken cancellationToken = default) { var message = new MimeMessage(); message.From.Add(MailboxAddress.Parse(_settings.UserName)); message.To.Add(MailboxAddress.Parse(to)); message.Subject = subject; message.Body = body; using (var smtpClient = _smtpClientFactory()) { await smtpClient.ConnectAsync(_settings.Server, _settings.Port, SecureSocketOptions.StartTls, cancellationToken); await smtpClient.AuthenticateAsync(_settings.UserName, _settings.Password, cancellationToken); await smtpClient.SendAsync(message, cancellationToken); await smtpClient.DisconnectAsync(true, cancellationToken); } } }

ConfigureServices(IServiceCollection services)

Azure 函数的完整 services.AddTransient<ISmtpClient, SmtpClient>(); services.AddSingleton(provider => new Func<ISmtpClient>(() => provider.GetService<ISmtpClient>())); 示例:

Program.cs

获取 public static void Main() { var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults() .ConfigureAppConfiguration((hostContext, builder) => { if (hostContext.HostingEnvironment.IsDevelopment()) { builder.AddJsonFile("local.settings.json"); //This will override any values added to local.settings.json - We will however follow the recommended approach for keeping secrets in dev //https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-5.0&tabs=windows#register-the-user-secrets-configuration-source //builder.AddJsonFile("secret.settings.json"); builder.AddUserSecrets<Program>(); } }) .ConfigureServices((hostContext, services) => { var connectionString = hostContext.Configuration.GetConnectionString("DefaultConnection"); services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer( connectionString, sqlServerOptions => sqlServerOptions.CommandTimeout(600))); services.AddHttpClient(); var configuration = hostContext.Configuration; var smtpSettings = new SmtpSettings(); configuration.Bind("Smtp", smtpSettings); services.AddSingleton(smtpSettings); services.AddTransient<ISmtpClient, SmtpClient>(); services.AddSingleton(provider => new Func<ISmtpClient>(() => provider.GetService<ISmtpClient>())); services.AddTransient<MailService>(); }) .Build(); host.Run(); } 注册和解析的来源:

https://stackoverflow.com/a/43763284/3850405