我正在开发一个 ASP.NET Core 项目,其中使用
SqlCredential
进行数据库身份验证,由 SqlCredentialProvider
提供,它被设计为单例,以确保整个应用程序中的单个实例。以下是我如何设置 DI 容器并配置服务:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// SqlCredentialProvider is a singleton to provide consistent SqlCredential instances
services.AddSingleton<SqlCredentialProvider>();
// SqlConnection is registered as transient and constructed with SqlCredential
services.AddTransient<SqlConnection>(serviceProvider =>
{
var sqlCredentialProvider = serviceProvider.GetRequiredService<SqlCredentialProvider>();
var sqlCredential = sqlCredentialProvider.GetCredential();
return new SqlConnection("ConnectionString", sqlCredential);
});
// ApplicationDbContext is configured to use the injected SqlConnection
services.AddDbContext<ApplicationDbContext>((serviceProvider, options) =>
{
var sqlConnection = serviceProvider.GetRequiredService<SqlConnection>();
options.UseSqlServer(sqlConnection);
});
}
}
鉴于此配置:
SqlConnection
构建的 SqlCredential
实例由 EF Core 正确管理和处置的正确方法吗?SqlConnection
和 SqlCredential
?
我特别关心SqlConnection
的正确处置,以防止任何潜在的资源泄漏。任何建议或指导将不胜感激。这是原始代码:
services.AddScoped<SqlCredential>(_ =>
{
//ToSecureString is an extension method for converting a string to a SecureString.
return new SqlCredential("sa", "password".ToSecureString());
});
services.AddScoped(serviceProvider =>
{
var sqlCredentialProvider = serviceProvider.GetRequiredService<SqlCredentialProvider>();
var sqlCredential = sqlCredentialProvider.GetCredential();
return new SqlConnection(configuration.GetConnectionString("MyApplicationConnectionStr"), sqlCredential);
});
// ApplicationDbContext is configured to use the injected SqlConnection
services.AddDbContext<ApplicationDbContext>((serviceProvider, options) =>
{
var sqlConnection = serviceProvider.GetRequiredService<SqlConnection>();
options.UseSqlServer(sqlConnection);
});
在并发测试的时候,我发现数据库的用户连接数超过一万,怀疑是
SqlConnection
实例没有被正确处置。然后我将代码修改为上面的代码,现在看起来工作正常
正确,它需要是一个
Scoped
服务,否则每次调用它时都会得到一个新对象,并且在作用域结束之前它们都不会被释放。
但是,理想情况下,您只需更改实际的连接字符串以包含正确的凭据,而不是自己创建连接。
如果您确实想更改连接的创建方式,另一个选择是替换
ISqlServerConnection
服务。
services.Replace(ServiceDescriptor.Scoped<ISqlServerConnection, SqlServerConnectionWithCreds>())
public class SqlServerConnectionWithCreds : SqlServerConnection
{
public SqlCredentialProvider CredentialProvider { get; }
public SqlServerConnectionWithCreds(RelationalConnectionDependencies dependencies, SqlCredentialProvider credentialProvider)
: base(dependencies)
{
CredentialProvider = credentialProvider;
}
protected override DbConnection CreateDbConnection()
{
var sqlCredential = CredentialProvider.GetCredential();
return new SqlConnection(GetValidatedConnectionString(), sqlCredential);
}
}