我目前使用的代码如下:
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对象吗?还是说using语句会干扰Ninject?
在这种情况下,正确的方法是什么?任何洞察力都会非常有帮助。
发布于 2012-09-10 22:31:27
pop3
变量将被赋予与popClient
相同的对IPopClient
对象的引用,因此当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支持为注册类型注入工厂方法,而不需要任何额外的设置(我想,这就是它的名字的由来);我相信在配置一个()=>new PopClient()
容器时,你需要显式地注册一个"getter“作为给定返回类型的工厂方法(这可以是一个简单的lambda解析方法,也可以使用对容器解析方法的调用)。
发布于 2012-09-10 22:26:04
在设置绑定时,声明作用域:
https://github.com/ninject/ninject/wiki/Object-Scopes
Ninject会在它为你创建的对象上调用dispose,所以确保你把dispose方法写在你给Ninject去处理的任何对象中。
发布于 2021-07-30 07:43:20
我喜欢@KeithS的回答,但我想用ConfigureServices
、.NET核心依赖注入和MailKit.Net.Smtp
添加一些更新。
https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection
给定下面的类:
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)
中
services.AddTransient<ISmtpClient, SmtpClient>();
services.AddSingleton(provider =>
new Func<ISmtpClient>(() => provider.GetService<ISmtpClient>()));
Azure函数的完整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();
}
用于注册和解析Func<T>
的源代码:
https://stackoverflow.com/questions/12360271
复制