You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#:如何为IDbConnection添加标识判断连接字符串是否已修改?

解决方案:避免连接字符串自定义关键字,给IDbConnection添加自定义标识

你遇到的问题本质是:数据库连接字符串的关键字由对应的数据库驱动(如SqlClient、OracleClient)严格校验,自定义的authenticated不在驱动支持的关键字列表中,因此赋值时会抛出异常。以下两种方案可以实现你的需求,且不会修改连接字符串本身:

方案1:使用扩展方法+ConditionalWeakTable存储自定义属性

这种方法不需要修改原有连接对象的结构,通过扩展方法为IDbConnection附加自定义状态,且不会导致内存泄漏(ConditionalWeakTable会在连接对象被回收时自动清理对应的元数据)。

扩展类代码

using System.Runtime.CompilerServices;

public static class DbConnectionExtensions
{
    // 用于存储每个连接的元数据
    private static readonly ConditionalWeakTable<IDbConnection, ConnectionMetadata> _connectionMetadata = new();

    // 内部类存储自定义属性
    private class ConnectionMetadata
    {
        public bool IsAuthenticated { get; set; }
    }

    // 设置已认证标记
    public static void MarkAsAuthenticated(this IDbConnection connection)
    {
        var metadata = _connectionMetadata.GetValue(connection, _ => new ConnectionMetadata());
        metadata.IsAuthenticated = true;
    }

    // 判断是否已认证
    public static bool IsAuthenticated(this IDbConnection connection)
    {
        return _connectionMetadata.TryGetValue(connection, out var metadata) && metadata.IsAuthenticated;
    }
}

修改你的方法并使用

// 修改原方法,不再添加自定义连接字符串关键字
public void SetUserAndPassword(IDbConnection dbConnection, string user, string password)
{
    DbConnectionStringBuilder sb = new DbConnectionStringBuilder();
    sb.ConnectionString = dbConnection.ConnectionString;
    sb["user id"] = user;
    sb["password"] = password;
    dbConnection.ConnectionString = sb.ConnectionString;
    // 标记连接已更新
    dbConnection.MarkAsAuthenticated();
}

// 使用时判断是否需要更新
if (!dbConnection.IsAuthenticated())
{
    vendor.SetUserAndPassword(dbConnection, dbCredentials.GetUser(), dbCredentials.GetPassword());
}
// 执行打开连接等操作

方案2:包装IDbConnection实现自定义属性

如果需要更明确的封装,可以自己实现一个IDbConnection的包装类,内部委托原始连接的所有操作,同时添加自定义属性。

包装类代码

public class TrackedDbConnection : IDbConnection
{
    private readonly IDbConnection _innerConnection;

    // 自定义属性:标记是否已更新用户名密码
    public bool IsAuthenticated { get; set; }

    public TrackedDbConnection(IDbConnection innerConnection)
    {
        _innerConnection = innerConnection ?? throw new ArgumentNullException(nameof(innerConnection));
    }

    // 实现IDbConnection的所有接口方法,委托给内部连接
    public string ConnectionString
    {
        get => _innerConnection.ConnectionString;
        set => _innerConnection.ConnectionString = value;
    }

    public int ConnectionTimeout => _innerConnection.ConnectionTimeout;

    public string Database => _innerConnection.Database;

    public ConnectionState State => _innerConnection.State;

    public IDbTransaction BeginTransaction() => _innerConnection.BeginTransaction();

    public IDbTransaction BeginTransaction(IsolationLevel il) => _innerConnection.BeginTransaction(il);

    public void ChangeDatabase(string databaseName) => _innerConnection.ChangeDatabase(databaseName);

    public void Close() => _innerConnection.Close();

    public IDbCommand CreateCommand() => _innerConnection.CreateCommand();

    public void Open() => _innerConnection.Open();

    public void Dispose() => _innerConnection.Dispose();
}

使用示例

// 包装原始连接
var trackedConn = new TrackedDbConnection(dbConnection);

if (!trackedConn.IsAuthenticated)
{
    vendor.SetUserAndPassword(trackedConn, dbCredentials.GetUser(), dbCredentials.GetPassword());
    trackedConn.IsAuthenticated = true;
}

// 使用trackedConn进行后续的数据库操作
trackedConn.Open();
// ...

为什么原方法会报错

数据库驱动(如SqlConnection对应的SqlClient)在解析连接字符串时,会严格校验每个关键字是否属于其支持的列表(比如user id、password、server等),自定义的authenticated不在列表中,因此会抛出ArgumentException。

内容的提问来源于stack exchange,提问作者Bar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 01:30:07