如何使用依赖注入在 EF Core 中正确管理和处置 SqlConnection 和 SqlCredential?

问题描述 投票:0回答:1

我正在开发一个 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);
        });
    }
}

鉴于此配置:

  1. 这是确保使用来自单例提供商的
    SqlConnection
    构建的
    SqlCredential
    实例由 EF Core 正确管理和处置的正确方法吗?
  2. 是否有更好的实践或模式来使用依赖注入在 ASP.NET 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
实例没有被正确处置。然后我将代码修改为上面的代码,现在看起来工作正常

c# sql sql-server asp.net-core entity-framework-core
1个回答
0
投票

正确,它需要是一个

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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.