必须使用 Oracle.ManagedDataAccess 5.24.1+(非Core包),连接字符串需含 Encrypt=true、SERVICE_NAME、TrustServerCertificate=false,调用REF CURSOR须设CommandType.StoredProcedure并显式声明OracleDbType.RefCursor输出参数。

必须用 Oracle.ManagedDataAccess 5.24.x+,别碰 Core 包
在 .NET 8 下连 Oracle 19c,Oracle.ManagedDataAccess 是唯一可用的 NuGet 包;Oracle.ManagedDataAccess.Core 已归档、不更新,装了会直接报 System.IO.FileNotFoundException: Could not load file or assembly 'Oracle.ManagedDataAccess.Core' 或类型找不到。
项目文件中只保留这一行:
<PackageReference Include="Oracle.ManagedDataAccess" Version="5.24.1" />
检查已安装 DLL 的版本:右键 Oracle.ManagedDataAccess.dll → 属性 → 详细信息 → “产品版本” 必须是 5.24.1 或更高。5.23.x 虽能编译通过,但运行时大概率抛 System.MissingMethodException,现象是连接成功、Open() 不报错,但查不出任何数据。
如果旧项目还引用着 Core 包,必须手动删掉,否则两个包的类型会冲突,OracleConnection 构造函数都可能无法解析。
连接字符串里 Encrypt=true 和 SERVICE_NAME 是硬性要求
Oracle 19c 默认启用 TLS 1.2+ 和强密码策略,裸写 Data Source=your_host:1521/your_sid 几乎必败——常见错误是卡住、超时,或直接报 ORA-28759: failure to open file(本质是 TLS 握手失败)。
最小可用连接字符串必须包含:
-
Encrypt=true:强制加密,设为false会被服务端拒绝 -
TrustServerCertificate=false:启用证书链校验;测试环境若用自签名证书,可临时改为true,但生产环境必须配可信 CA - 用
SERVICE_NAME,不用SID:写成(SERVICE_NAME=ORCLPDB1),否则容易触发ORA-12514: TNS listener does not currently know of service requested - 去掉
Pooling=true调试:连接池会掩盖认证失败、用户名密码错等底层问题;先确保单次连接能通,再开池
推荐格式(替换占位符后直接可用):
data source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=your_host)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=your_service)));user id=your_user;password=your_pass;Connection Timeout=30;Encrypt=true;TrustServerCertificate=false;
调用存储过程返回 REF CURSOR 必须显式声明参数
ODP.NET 不自动绑定 REF CURSOR 输出参数。如果直接写 cmd.CommandText = "GET_EMPLOYEES"; cmd.ExecuteNonQuery();,会报 ORA-06550: PLS-00306: wrong number or types of arguments——不是存储过程写错了,而是没告诉驱动“这个参数是游标”。
正确做法:
-
cmd.CommandType必须设为CommandType.StoredProcedure,不能是Text - 输出参数必须用
OracleDbType.RefCursor类型,并明确指定Direction = ParameterDirection.Output - 执行必须用
ExecuteReader(),不能用ExecuteScalar()或ExecuteNonQuery()
示例关键片段:
cmd.CommandText = "GET_EMPLOYEES";
cmd.CommandType = CommandType.StoredProcedure;
var refCursorParam = cmd.Parameters.Add("p_result", OracleDbType.RefCursor);
refCursorParam.Direction = ParameterDirection.Output;
using (var reader = cmd.ExecuteReader()) // ← 游标在此真正打开
{
while (reader.Read())
{
Console.WriteLine(reader["employee_id"]);
}
}
OracleConnectionStringBuilder 比手拼更安全,尤其带 Wallet 时
手动拼接连接字符串极易漏掉空格、括号不匹配、特殊字符未转义,尤其在使用 Oracle Wallet 时,DataSource 字段稍有格式错误就会导致 ORA-12154: TNS could not resolve the connect identifier。
用 OracleConnectionStringBuilder 可自动处理格式和编码:
- 基础用法:
builder.DataSource填完整 TNS 描述,不要加换行或多余空格 - 用 Wallet 时:
builder.UserID和builder.Password必须清空,设builder.IntegratedSecurity = true - 若依赖
tnsnames.ora,确保TNS_ADMIN环境变量指向含sqlnet.ora和tnsnames.ora的目录
Wallet 场景示例:
var builder = new OracleConnectionStringBuilder
{
DataSource = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=mywalletdb.example.com)(PORT=2484))(CONNECT_DATA=(SERVICE_NAME=mydb)))",
IntegratedSecurity = true
};
// builder.UserID 和 builder.Password 留空,否则 Wallet 认证失效
真正容易被忽略的是:Wallet 连接必须搭配 Connection Timeout=15(默认 30 秒不够),且服务端必须开启 TCPS 协议和对应证书配置——这点不验证,Open() 就会静默卡住。


















