How to reuse code that reopens connection?

后端 未结 4 1714
旧时难觅i
旧时难觅i 2020-12-22 00:36

Our production server kills inactive connections, so our API needs to restore them when they are needed. The following code works, but it is very repetitive:



        
相关标签:
4条回答
  • 2020-12-22 01:00

    There's a few things I'm not loving in the code sample. But, to explicitly answer your question on removing duplication - extract out the common code to a method that takes a delegate.

    private TReturn RestoreConnectionAndExecute<T>(SqlCommand command, Func<SqlCommand, TReturn> execute) 
    {
       int retryCount = 0;
       while (retryCount++ < MaxRetryCount)
       {
           try
           {
              if (command.Connection.State == ConnectionState.Close) 
                  command.Connection.Open();
              return execute(command);
           } 
           catch(Exception e)
           {
              ...
       }
    }
    
    public SqlDataReader RestoreConnectionAndExecuteReader(SqlCommand command) 
    {
       return this.RestoreConnectionAndExecute(command, c => c.ExecuteReader());
    }
    
    public void RestoreConnectionAndExecuteNonQuery(SqlCommand command)
    {
       // Ignore return
       this.RestoreConnectionAndExecute(command, c => c.ExecuteNonQuery());
    }
    

    You should really rethink a few things, though. Including:

    • Catching specific exceptions
    • Using Exception.Number or ErrorCode instead of the message (which will change in localized versions, and possibly in updated FX versions)
    • Using statements for IDisposable resources
    • Throwing specific exceptions
    0 讨论(0)
  • 2020-12-22 01:07
    private const int MaxRetryCount = 3;
    
            public static SqlDataReader RestoreConnectionAndExecuteReader(SqlCommand command)
            {
                return RestoreConnectionAndExecuteQueryHelper(command, true);
            }
    
            public static void RestoreConnectionAndExecuteNonQuery(SqlCommand command)
            {
                RestoreConnectionAndExecuteQueryHelper(command, false);
            }
    
            private static SqlDataReader RestoreConnectionAndExecuteQueryHelper(SqlCommand command, bool returnReader)
            {
                var retryCount = 0;
                while (retryCount++ < MaxRetryCount)
                {
                    try
                    {
                        if (command.Connection.State == ConnectionState.Closed)
                            command.Connection.Open();
                        if (returnReader)
                        {
                            return command.ExecuteReader();
                        }
                        else
                        {
                            command.ExecuteNonQuery();
                            return null;
                        }
                    }
                    catch (Exception e)
                    {
                        if (!e.Message.ToLower().Contains("transport-level error has occurred"))
                        {
                            throw;
                        }
                    }
                }
                throw new Exception("Failed to restore connection for command:" + command.CommandText);
            }
    
    0 讨论(0)
  • 2020-12-22 01:13

    The common part for those method is the connection retrieving process. You could create a new static method that is responsible for that called for example retrieve connection that take command as argument and return it if connection is established in other cases throws an exception.

    0 讨论(0)
  • 2020-12-22 01:18
    private const int MaxRetryCount = 3;
    
    public static T RestoreConnectionAndExecute<T>(SqlCommand command, Func<SqlCommand, T> func)
    {
        int retryCount = 0;
    
        while (retryCount++ < MaxRetryCount)
        {
            try
            {
                if (command.Connection.State == ConnectionState.Closed)
                    command.Connection.Open();
                return func(command);
            }
            catch(Exception e)
            {
                if(!e.Message.ToLower().Contains("transport-level error has occurred"))
                {
                    throw;
                }
            }
        }
        throw new Exception("Failed to restore connection for command:"+command.CommandText);
    
    } 
    
    public static SqlDataReader RestoreConnectionAndExecuteReader(SqlCommand command)
    {
        return RestoreConnectionAndExecute(command, c => c.ExecuteReader());
    }
    
    public static int RestoreConnectionAndExecuteNonQuery(SqlCommand command)
    {
        return RestoreConnectionAndExecute(command, c => c.ExecuteNonQuery());
    }
    
    0 讨论(0)
提交回复
热议问题