1

My WCF service need to check is connection available now and can we work with it. We have many remote dbs. Their connection are weird sometimes and can't be used to query data or smth else. So, for example this is regular connection string used:

User Id=user;Password=P@ssw0rd;Data Source=NVDB1;Connection Timeout=30

Here is service method, used for getting

    public List<string> GetAliveDBs(string city)
    {
        if (String.IsNullOrEmpty(city))
            return null;                        

        List<string> cityDbs = (from l in alldbs where !String.IsNullOrEmpty(l.Value.city) && l.Value.city.ToUpper() == city.ToUpper() select l.Value.connString).ToList();            

        // There is no such city databases
        if (cityDbs.Count == 0)
            return null;

        ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

        Parallel.ForEach(cityDbs, p =>
        {
            if (!IsConnectionActive(p.connString))
            {
                locker.EnterWriteLock();
                try
                {
                    cityDbs.RemoveAt(cityDbs.IndexOf(p));
                }
                finally
                {
                    locker.ExitWriteLock();
                }
            }
        });

        return cityDbs;
    }

    static public bool IsConnectionAlive(string connectionString)
    {
        using (OracleConnection c = new OracleConnection(connectionString))
        {
            try
            {                    
                c.Open();
                if ((c.State == ConnectionState.Open) && (c.Ping()))
                    return true;
                else
                    return false;
            }
            catch (Exception exc)
            {
                return false;                 
            }
        }
    }

I use devart components to communicate with Oracle DB. Hope for your help, guys! Thanks in advance!

kseen
  • 359
  • 8
  • 56
  • 104
  • 1
    If you're asking how to determine if your Oracle connection string is valid, try to connect to it, and if it fails it isn't valid. If you're after something else, you should probably include a question in your *question*. – M.Babcock Feb 15 '12 at 03:26
  • @M.Babcock The issue is that connection checking you proposed very slow and it can't be used for fast checking. Btw, the question is in title of the question. – kseen Feb 15 '12 at 03:32
  • I must have missed the question mark. If you want a lightweight way of pre-checking if the server is there, then open a telnet connection to its port. – M.Babcock Feb 15 '12 at 03:36
  • @M.Babcock Is this way enough robust to check connection? Is it faster than Eric J. provided? – kseen Feb 15 '12 at 03:49
  • 1
    If the goal is to see if a server is available then it would generally be good enough. It doesn't provide any guarantees beyond knowing that there is *something* listening on the port (the Oracle port is pretty well known though) and would absolutely be faster. It would be enough to be able to tell the user that their connection string is wrong (if that is what you're after). Provide some context to your question and I'll be able to tell you whether it is enough. – M.Babcock Feb 15 '12 at 03:54
  • @M.Babcock I feel we are going to right direction. Another one my trouble is that some connections are slow and we should give some timeout to port checking try. I think even pinging the host is enough to ensure the everything is ok. What do you think about it and I'm very thankful to you for your assistance. – kseen Feb 15 '12 at 04:00
  • Are you trying to check more than one at a time or just one? – M.Babcock Feb 15 '12 at 04:03
  • @M.Babcock I trying to check all connections from config file. To get it faster I use parallel tasks. – kseen Feb 15 '12 at 04:09
  • You aren't going to get much faster than that. – M.Babcock Feb 15 '12 at 04:19
  • @M.Babcock Do you mean to connect to port or ping host? – kseen Feb 15 '12 at 04:21
  • Ping is going to be faster (it avoids the 3 way handshake and requires less cleanup). If you only want to prove that something lives at the IP/hostname a ping is good enough so go with it, but if you need to prove that there is something there to connect to I'd recommend opening a Tcp connection to the port and basing it on that. You can get slightly faster by managing the TCP communication yourself and only relying on a two-way handshake but you're already talking subsecond response time, so it wouldn't be worth the effort. – M.Babcock Feb 15 '12 at 04:24
  • @M.Babcock OK, thanks for your explanation. Could you please form it into answer with some code sample and I will accept it. – kseen Feb 15 '12 at 04:38

3 Answers3

2

Try just executing a very low cost operation that should work no matter what schema you are connected to, e.g.

SELECT 1

(that statement works on MS SQL and MySQL... should work on Oracle too but I can't confirm that).

If you get the result you expect (in this case one row, with one column, containing a "1") then the connection is valid.

At least one connection pool manager uses this strategy to validate connections periodically.

UPDATE:

Here's a SQL Server version of your method. You can probably just replace "Sql" with "Oracle".

static public bool IsConnectionAlive(string connectionString)
{
    try
    {
        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("SELECT 1", conn))
            {
                int result = (int)cmd.ExecuteScalar();
                return (result == 1);
            }

        }
    }
    catch (Exception ex)
    {
        // You need to decide what to do here... e.g. does a malformed connection string mean the "connection isn't alive"?
        // Maybe return false, maybe log the error and re-throw the exception?
        throw;
    }
}
Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • It's really interesting way. Could you provide some code sample on that, please? – kseen Feb 15 '12 at 03:33
  • 1
    Code sample on what? `SELECT 1`? – John Saunders Feb 15 '12 at 03:42
  • No, I'm asking for whole my `IsConnectionActive` method rewrited? How should it test connection? Just connect to it and then try execute query? Does this method faster than M.Babcock has proposed, what do you think? – kseen Feb 15 '12 at 03:47
  • @EricJ. OK, thanks. I'm clear about your method at the moment. – kseen Feb 15 '12 at 04:10
  • @kseen: M. Babcock's suggestion to open a "telnet session" to the port (really, to open a TCP/IP connection to the port) would be a fast pre-check that something is listening on the other end, but in my opinion what I have coded will be more than fast enough for almost any requirement. To do that, you would have to know the port that the Oracle server is listening on. It's been ages since I did Oracle, but I seem to recall that the port information can be in a TNS name file or some such and may not be the default Oracle port, and may not be in the connection string. I would not do that. – Eric J. Feb 15 '12 at 04:13
  • @EricJ. - Provided the OP is talking about basing the connection on a connection string, the information would have to be there (or based on a default value) anyway so it would in any case be discoverable. I agree that your approach would generally be *fast enough* but it still requires a connection to be established with the server (which they are trying to avoid based on their response to my first comment) in which case even the slowest of my recommendations would cover. – M.Babcock Feb 15 '12 at 04:30
  • @M.Babcock: Oracle can use a TNS names file to store the port information, though I don't know if that's the case for the OP http://www.orafaq.com/wiki/Tnsnames.ora – Eric J. Feb 15 '12 at 04:50
  • @M.Babcock: Just being able to establish a TCP connection does not guarantee that an Oracle instance is listening and running correctly (e.g. it could be in a semi-crashed state, or something else entirely could be listening on the port you think Oracle is on). Even if a TCP connection succeeds, it's probably necessary to validate that it's a functioning Oracle server on the other end (but whether that's really true is up to the OP, and I agree his comments don't necessarily support my conclusion). – Eric J. Feb 15 '12 at 04:52
  • @EricJ. - This is a multi-tiered issue and which tier they care about was not clearly defined by their question. If they only want to know that the server *exists* ping is enough. If they want to know that there is *something* living on the server, then a TCP connection is enough. If they want to know that **Oracle** is listening on their server, then the `OracleConnection` class (or your solution) is enough (though I question the value of sending a select when the server connection has been established). I never said your answer was wrong; just that the question was poorly defined. – M.Babcock Feb 15 '12 at 05:00
  • In Oracle you would write `SELECT 1 FROM DUAL` – Adam Hawkes Feb 15 '12 at 13:37
1

If the goal is to simply determine if a server lives at the IP Address or host name then I'd recommend Ping (no 3 way handshake and has less overhead than a UDP message). You can use the System.Net.NetworkInformation.Ping class (see its documentation for an example) for this.

If you're looking to prove that there is actually something listening on the common Oracle port, I would suggest using either the System.Net.Sockets.TcpClient or System.Net.Sockets.Socket class (their documentation also provides examples) to provide this.

The simplest way to do this (by far) is to just open a connection using the Oracle API for C#. There is a very good tutorial that includes code here. It covers more than just the connection but you should be able to strip out the connection portion from the rest to fit your needs.

M.Babcock
  • 18,753
  • 6
  • 54
  • 84
0

Oracle has products and software specifically for helping maintain high availability that can allow you to have dead connections removed from you connection pool through a setting called HA Events=true on the connection string. Your Oracle DBA will need to determine if your installation supports it.

Jared Shaver
  • 1,339
  • 8
  • 12