Since we moved from an on premises SQL Server to SQL Azure we experienced a lot of timeouts. This is the exact errormessage:
Connection Timeout Expired. The timeout period elapsed while attempting to consume the pre-login handshake acknowledgement. This could be because the pre-login handshake failed or the server was unable to respond back in time. The duration spent while attempting to connect to this server was - [Pre-Login] initialization=3; handshake=29995;
After searching the web for a while it appeared that it is recommended to use the Microsoft Enterprise Library. Version 6 was released last April. So there are not so much code samples at the moment. But there is a free e-book! Developer's Guide to Microsoft Enterprise Library, 2nd Edition. You can download it for free from Microsoft's website or order a paperback from amazon.
I installed two nuget packages for the enterprise library.
My data access class required these two additions to the usings:
using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.SqlAzure; using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling;
And my function which returns a simple datatable looks like this now:
public static DataTable GetDatatable(SqlCommand com) { DataTable dt = new DataTable(); RetryStrategy retryStrategy = new Incremental("fixed", 5, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2)); RetryPolicy retryPolicy = new RetryPolicy<SqlDatabaseTransientErrorDetectionStrategy>(retryStrategy); retryPolicy.Retrying += new EventHandler<RetryingEventArgs>(retryPolicy_Retrying); List<RetryStrategy> retryStrategies = new List<RetryStrategy> { retryStrategy }; var manager = new RetryManager(retryStrategies, "fixed"); // this name must match the name of the incremental try { RetryManager.SetDefault(manager); // you have to set the default } catch { } // but you cannot check if it is already set, that's why I used a try, catch try { retryPolicy.ExecuteAction(() => { using (SqlConnection con = new SqlConnection(GetConStr())) { com.Connection = con; SqlDataAdapter da = new SqlDataAdapter(com); con.OpenWithRetry(); da.Fill(dt); } }); } catch (Exception e) { WriteDbError(e, com); } return dt; }
I know that you can configure the enterprise library to use settings from the web.config. I decided to use hardcoded “variables” because they do not change (much). Please let me know if you have more improvements for the code above. I have a simple GetConStr() method which just returns the connection string from the web.config file.
So this code will solve about 99% of your azure timeouts!
Good luck! Let me know your opinion in the comments!
ps. Happy new year!