Null Reference Exception when using an ADDRESS_LIST within an ADRESSS_LIST
maksym-bondarchuk opened this issue · 12 comments
Oracle.ManagedDataAccess.Core
versions 3.21.1
, 2.19.110
and 2.19.70
(only these were tested)
System.NullReferenceException: Object reference not set to an instance of an object.
at OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, OracleConnection connRefForCriteria, String instanceName, List`1 switchFailedInstNames)
at OracleInternal.ConnectionPool.OraclePoolManager.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, OracleConnection connRefForCriteria, String instanceName, List`1 switchFailedInstNames)
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at System.Data.Common.DbConnection.OpenAsync(CancellationToken cancellationToken)
--- End of stack trace from previous location ---
Code:
await using var connection = new OracleConnection(connectionString);
await connection.OpenAsync();
var command = new OracleCommand(queryString, connection);
Console.WriteLine(await command.ExecuteScalarAsync());
Connection string:
"Data Source=(DESCRIPTION=(RETRY_COUNT=20)(ADDRESS_LIST=(SOURCE_ROUTE=YES)(ADDRESS_LIST=(FAILOVER=ON)(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=tcp)(HOST=<hidden>)(PORT=1650))(ADDRESS=(PROTOCOL=tcp)(HOST=<hidden>)(PORT=1650)))(ADDRESS_LIST=(FAILOVER=ON)(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=tcp)(HOST=<hidden>)(port=1530))(ADDRESS=(PROTOCOL=tcp)(HOST=<hidden>)(port=1530))))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=<hidden>)(FAILOVER_MODE = (TYPE = SELECT)(METHOD = BASIC)(RETRIES = 180)(DELAY = 5))));User Id=<hidden>;Password=<hidden>;"
I can connect with the same connection string (in tnsnames.ora
) but not with the code. Trying to connect from PC with no network access to hosts in connection string gives the same error
I was able to reproduce your error. It appears that ODP.NET Core has a problem with using an ADDRESS_LIST embedded with another ADDRESS_LIST. Unmanaged ODP.NET does not have this issue. I filed Bug 32812583 to have the dev team diagnose the root cause and create a fix.
@alexkeh, thanks for your help! Replacing
"DataSource=DHUB_PROD2=(DESCRIPTION=(RETRY_COUNT=20)(ADDRESS_LIST=(SOURCE_ROUTE=YES)(ADDRESS_LIST=(FAILOVER=ON)(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=tcp)(HOST=<ip address 1>)(PORT=1650))(ADDRESS=(PROTOCOL=tcp)(HOST=<ip address 2>)(PORT=1650)))(ADDRESS_LIST=(FAILOVER=ON)(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=tcp)(HOST=<dns address 1>)(port=1530))(ADDRESS=(PROTOCOL=tcp)(HOST=<dns address 2>)(port=1530))))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=<service name>)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=180)(DELAY=5))));UserId=<user>;Password=<password>"
to
"DataSource=(DESCRIPTION=(FAILOVER=ON)(LOAD_BALANCE=ON)(ADDRESS_LIST=(SOURCE_ROUTE=YES)(ADDRESS=(PROTOCOL=TCP)(HOST=<ip address 1>)(PORT=1650))(ADDRESS=(PROTOCOL=TCP)(HOST=<dns address 1>)(PORT=1530)))(ADDRESS_LIST=(SOURCE_ROUTE=YES)(ADDRESS=(PROTOCOL=TCP)(HOST=<ip address 2>)(PORT=1650))(ADDRESS=(PROTOCOL=TCP)(HOST=<dns address 2>)(PORT=1530)))(CONNECT_DATA=(SERVICE_NAME=<service name>)));UserId=<user>;Password=<password>"
solved the issue.
tnsnames.ora
from connection strings:
WRONG=
(DESCRIPTION=
(RETRY_COUNT=20)
(ADDRESS_LIST=
(SOURCE_ROUTE=YES)
(ADDRESS_LIST=
(FAILOVER=ON)
(LOAD_BALANCE=ON)
(ADDRESS=(PROTOCOL=tcp)(HOST=<ip address 1>)(PORT=1650))
(ADDRESS=(PROTOCOL=tcp)(HOST=<ip address 2>)(PORT=1650))
)
(ADDRESS_LIST=
(FAILOVER=ON)
(LOAD_BALANCE=ON)
(ADDRESS=(PROTOCOL=tcp)(HOST=<dns address 1>)(port=1530))
(ADDRESS=(PROTOCOL=tcp)(HOST=<dns address 2>)(port=1530))
)
)
(CONNECT_DATA=
(SERVER=DEDICATED)(SERVICE_NAME=<service name>)
(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=180)(DELAY=5))
)
)
CORRECT=
(DESCRIPTION=
(FAILOVER=ON)
(LOAD_BALANCE=ON)
(ADDRESS_LIST=
(SOURCE_ROUTE=YES)
(ADDRESS=(PROTOCOL=TCP)(HOST=<ip address 1>)(PORT=1650))
(ADDRESS=(PROTOCOL=TCP)(HOST=<dns address 1>)(PORT=1530))
)
(ADDRESS_LIST=
(SOURCE_ROUTE=YES)
(ADDRESS=(PROTOCOL=TCP)(HOST=<ip address 2>)(PORT=1650))
(ADDRESS=(PROTOCOL=TCP)(HOST=<dns address 2>)(PORT=1530))
)
(CONNECT_DATA=(SERVICE_NAME=<service name>))
)
@maksym-bondarchuk I'm glad you were able to work around the issue for now.
Hi @alexkeh,
Do we have any news on this.
we are being hit by the same issue.
But using the workaround has it's own drawbacks since 2 instances which are not paired together might be taken down.
Something we got hit recently.
We had to change the connection string such that the 2 working instances are paired together.
@lBilali
There isn't a fix yet. Since there's a workaround and until today only one customer has reported hitting it, this bug was not given a high priority to address.
From what my .NET team understands, you are using the connect string below. You are using a top level address_list, followed by two internal address lists. You are then setting source_route on the outside address_list, which means you are source routing across the two internal address lists. Thus, the first internal address_list is to have some HA (failover) across two CMANs? And the second internal address_list is to have HA (failover) across two instances. Is that correct?
If that is the case, then the example you have is a client side source_route with HA on the CMAN. However, source_routing for a modern CMAN is done internal to the CMAN. The client source_routing is not needed. Thus, only a single address_list is required, to provide the initial HA across the two CMAN.
(DESCRIPTION=(RETRY_COUNT=20)(ADDRESS_LIST=(SOURCE_ROUTE=YES)
(ADDRESS_LIST=(FAILOVER=ON)(LOAD_BALANCE=ON)
(ADDRESS=(PROTOCOL=tcp)(HOST=<hidden>)(PORT=1650))
(ADDRESS=(PROTOCOL=tcp)(HOST=<hidden>)(PORT=1650)))
(ADDRESS_LIST=(FAILOVER=ON)(LOAD_BALANCE=ON)
(ADDRESS=(PROTOCOL=tcp)(HOST=<hidden>)(port=1530))
(ADDRESS=(PROTOCOL=tcp)(HOST=<hidden>)(port=1530))))
(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=<hidden>)(FAILOVER_MODE =
(TYPE = SELECT)(METHOD = BASIC)(RETRIES = 180)(DELAY = 5)))
For the CMAN to handle the source routing, make sure you register the back end instances with the CMAN. Add the CMAN address to the remote_listener's in the init.ora.
Hopefully, that should resolve your issue. If not, let me know why.
Hi @alexkeh,
If I understand you right your solution requires changes on the server side?
In that case we don't have control over that since the Oracle server is owned and managed by a different company
@lBilali
How is your setup configured? The recommended practice is to configure the service with CMAN.
The link directs pointing the init.ora file's remote_listener to CMAN. If the init.ora is already set up like that, just change the client connect string.
We can't change configurations for CMAN since that is out of our organisation. (We have to ask them if they can do it)
All we have is the connection string which is given to us.
That works fine when we connect let's say via Oracle SQL Developer but it does not work on dotnet
Here is some example code I used to test
using System;
using Oracle.ManagedDataAccess.Client;
// This sample demonstrates how to use ODP.NET Core Configuration API
// Add connect descriptors and net service names entries.
OracleConfiguration.OracleDataSources.Add("cs1", @"(DESCRIPTION=
(RETRY_COUNT=20)
(ADDRESS_LIST=
(SOURCE_ROUTE=YES)
(ADDRESS_LIST=
(FAILOVER=ON)
(LOAD_BALANCE=ON)
(ADDRESS=(PROTOCOL=tcp)(HOST=<IP Address 1>)(PORT=<port>))
(ADDRESS=(PROTOCOL=tcp)(HOST=<IP Address 2>)(PORT=<port>))
)
(ADDRESS_LIST=
(FAILOVER=ON)
(LOAD_BALANCE=ON)
(ADDRESS=(PROTOCOL=tcp)(HOST=<Host name 1>)(port=<port>))
(ADDRESS=(PROTOCOL=tcp)(HOST=<Host name 2>)(port=<port>))
)
)
(CONNECT_DATA=
(SERVER=DEDICATED)(SERVICE_NAME=<Service Name>)
(FAILOVER_MODE = (TYPE = SELECT)(METHOD = BASIC)(RETRIES = 180)(DELAY = 5))
)
)");
OracleConfiguration.OracleDataSources.Add("cs2", @"(DESCRIPTION=
(RETRY_COUNT=20)
(FAILOVER=ON)
(LOAD_BALANCE=ON)
(ADDRESS_LIST=
(SOURCE_ROUTE=YES)
(ADDRESS=(PROTOCOL=TCP)(HOST=<IP Address 1>)(PORT=<port>))
(ADDRESS=(PROTOCOL=TCP)(HOST=<Host name 1>)(PORT=<port>))
)
(ADDRESS_LIST=
(SOURCE_ROUTE=YES)
(ADDRESS=(PROTOCOL=TCP)(HOST=<IP Address 2>)(PORT=<port>))
(ADDRESS=(PROTOCOL=TCP)(HOST=<Host name 2>)(PORT=<port>))
)
(ADDRESS_LIST=
(SOURCE_ROUTE=YES)
(ADDRESS=(PROTOCOL=TCP)(HOST=<IP Address 1>)(PORT=<port>))
(ADDRESS=(PROTOCOL=TCP)(HOST=<Host name 2>)(PORT=<port>))
)
(ADDRESS_LIST=
(SOURCE_ROUTE=YES)
(ADDRESS=(PROTOCOL=TCP)(HOST=<IP Address 2>)(PORT=<port>))
(ADDRESS=(PROTOCOL=TCP)(HOST=<Host name 1>)(PORT=<port>))
)
(CONNECT_DATA=
(SERVER=DEDICATED)(SERVICE_NAME=<Service Name>)
(FAILOVER_MODE = (TYPE = SELECT)(METHOD = BASIC)(RETRIES = 180)(DELAY = 5))
)
)");
OracleConfiguration.OracleDataSources.Add("cs3", @"(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = <IP Address>)(PORT = <port>))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = <Service name>)
)
)");
// Open a connection
using (OracleConnection orclCon = new OracleConnection("user id=user_name; password=password; data source=cs1"))
//using (OracleConnection orclCon = new OracleConnection("user id=user_name; password=password; data source=cs2"))
//using (OracleConnection orclCon = new OracleConnection("user id=user_name; password=password; data source=cs3"))
{
using (OracleCommand cmd = orclCon.CreateCommand())
{
try
{
orclCon.Open();
cmd.CommandText = "select 'Hello there!' from dual";
OracleDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr.GetString(0));
}
rdr.Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
cs1
is the original connection provided to us
cs2
is cs1
changed such that nested ADDRESS_LISTs are paired and there is no need for nesting
cs3
is a different oracle instance with a simple connection used as base to check that the code works fine
Test results: (Done with a .net7 console application)
Oracle.ManagedDataAccess.Core
Version: 2.18.15
cs1: Fail
System.NullReferenceException: Object reference not set to an instance of an object.
at OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, OracleConnection connRefForCriteria, String instanceName, List`1 switchFailedInstNames)
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at Program.<Main>$(String[] args) in Program.cs:line 80
cs2: OK
cs3: OK
Version: 2.19.3
cs1: Fail
System.NullReferenceException: Object reference not set to an instance of an object.
at OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, OracleConnection connRefForCriteria, String instanceName, List`1 switchFailedInstNames)
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at Program.<Main>$(String[] args) in Program.cs:line 80
cs2: Fail
Oracle.ManagedDataAccess.Client.OracleException (0x80004005): Connection request timed out
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at Program.<Main>$(String[] args) in Program.cs:line 80
cs3: OK
Version: 2.19.170 & 3.21.80
cs1: Fail
Oracle.ManagedDataAccess.Client.OracleException (0x80004005): Oracle Communication: Failed to connect to server or failed to parse connect string
---> OracleInternal.Network.NetworkException (0xFFFFE88F): Oracle Communication: Failed to connect to server or failed to parse connect string
at OracleInternal.Network.OracleCommunication.DoConnect(String tnsDescriptor)
at OracleInternal.Network.OracleCommunication.Connect(String tnsDescriptor, Boolean doNAHandshake, String IName, ConnectionOption CO)
at OracleInternal.ServiceObjects.OracleConnectionImpl.Connect(ConnectionString cs, Boolean bOpenEndUserSession, OracleConnection connRefForCriteria, String instanceName)
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at Program.<Main>$(String[] args) in Program.cs:line 80
cs2: Fail
Oracle.ManagedDataAccess.Client.OracleException (0x80004005): Connection request timed out
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at Program.<Main>$(String[] args) in Program.cs:line 80
cs3: OK
Same with me: connection string is provided by another [Oracle] team and it works fine in SQL Developer but not with Oracle.ManagedDataAccess.Core
Bug is fixed in 21.10.