SQL Connection timeout not working as expected - sql

I made following function to check whether connection is established or not.
Here I have made timeout = 15 seconds.
It works most of the time.
But sometime it throws exception before time.
So if I give same connectionstring, sometimes it works as per timeout and sometime it expires before time.
What is wrong with timeout?
Public Function IsDBExist(ByVal strConnectionString As String) As Boolean
Try
Using connection As New SqlConnection
Dim str As New SqlConnectionStringBuilder(strConnectionString)
str.ConnectTimeout = 15
connection.ConnectionString = str.ToString()
connection.Open()
End Using
Return True
Catch ex As Exception
Return False
End Try
End Function

Generally it means the connection string provided allowed the client to reach an sql-server instance but then something went wrong. For example, database name specified doesn't exist or the user has no privileges to see it.

Related

ADODB Connection Timeout in VBA for Excel 2016 - how to check if a connection is still active?

I have developed a small Excel addin using VBA which connects directly to a database. I set up the connection via a DSN. The addin works wonderfully when opening it and going right at it. However, after a while the connection to the database seems to timeout. More precisely, a perfectly valid query returns an error when trying to open the recordset.
My code is something like this:
'Check Connection
If Not MakeConnectionToDB Then
'Connection failed
[do something]
Exit Function
End If
'Active connection - run the query!
If Rs Is Nothing Then Set Rs = New ADODB.Recordset 'make sure its an active object
If Not Rs.State = adStateClosed Then Rs.Close 'make sure its not full (throws error if a query was called before)
Rs.Open strSQLQuery, CON 'Run query
the rs.open statement fails if the application was open but not used for a while. This is despite the MakeConnectionToDB UDF, which looks something like this:
If Not ConIsActive Then 'If there is no active connection, make it so
If CON Is Nothing Then 'Connection may be inactive because the object dropped, or because it timed out, or any other reason - Only recreate the object if the former is the case
Set CON = New ADODB.Connection
End If
On Error Resume Next
CON.Open strCon 'Try to connect - on error resume statement in order to ignore a connection error, that will be caught below
On Error GoTo 0
Err.Clear
MakeConnectionToDB = ConIsActive 'This is where a connection error will be caught if it occurred
Else
MakeConnectionToDB = True 'connection is active already
End If
and ConIsActive looks like:
Private Function ConIsActive() As Boolean
'return TRUE if there is an active connection, false otherwise
Dim blnTemp As Boolean
blnTemp = False
If (Not (CON Is Nothing)) And (Not (CON = "")) Then If CON.State = adStateOpen Then blnTemp = True
ConIsActive = blnTemp
End Function
Basically, I check if the connection is open. My problem: All these checks return TRUE, but the connection isn't open at all. If I connect, then leave the application for a while, then get back to it, all the above will return that the connection is active, but when trying to open the recordset with a new query it will fail, presumably because the server closed the connection or something. I need to find a way to check if the connection is actually able to open a recordset.
Can I ping the server or something? How can I check if the database actually returns a result to my queries? Is there a way that has a higher performance than just sending a test query to the server combined with error handling on the recordset? I suppose that would work, but I need a high performance solution and I don't think doubling the number of queries for a simple connection check is a superior solution...
Any help is appreciated!
Your CON object seems to be globally-scoped, opened once, and then used everywhere in your code, and possibly closed at some point... or not.
Like every single object in any code base written in any language that supports objects, a database connection should be as short-lived as possible.
You open it, you do what you need to do with it, and then you close it. If you don't know what the next command is going to be executed against it and when, then the connection has no business remaining open.
Delete your global-scope CON. Kill it, with fire. A connection should be local to the function or procedure that uses it - it begins in that scope, and ends in that scope.
Or you can encapsulate it in your own object, if that makes things easier for you.
'#Folder("Data.SqlConnection")
Option Explicit
Private Const CONNECTION_STRING As String = "{CONNECTION STRING}"
Private mConnection As ADODB.Connection
Private Sub Class_Initialize()
Set mConnection = New ADODB.Connection
mConnection.Open
End Sub
Private Sub Class_Terminate()
mConnection.Close
Set mConnection = Nothing
End Sub
Public Sub ExecuteNonQuery(ByVal sql As String, ParamArray params())
With New ADODB.Command
Set .ActiveConnection = mConnection
Dim p As ADODB.Parameter
For Each p In params
.Paramaters.Append p
Next
.Execute
End With
End Sub
'...
An instance of that SqlConnection class should also be as short-lived as possible, but now most of the plumbing is abstracted away so your calling code can look like this:
Const sql As String = "exec dbo.LogUserIn #userName=?, #password=?;"
With New SqlConnection
Dim userName As ADODB.Parameter
Set userName = .CreateStringParameter(Environ$("USERNAME"))
Dim password As ADODB.Parameter
Set password = .CreateStringParameter(PromptForPassword)
.ExecuteNonQuery sql, userName, password
End With
The connection begins at New SqlConnection, cleanly ends at End With, and you can tweak that SqlClass as you need, to support transactions, and/or as illustrated above, to abstract away the parameter-creating boilerplate.
But the idea remains: you don't create a database connection and leave it dangling in global scope, not knowing whether some code somewhere might have set it to Nothing, or closed it, or started a transaction that was never committed, or God knows what.
Create
Open
Execute
Close
Always. As tightly-scoped as possible. Then you won't have any object lifetime issues.

Preventing exception from lack of internet connectivity

I have a simple Windows Form application. I have used a Timer and on Timer interval I am checking online database for values and updating it on the form.
Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer.Tick
Try
String ConnectionString = globalConnString
Dim SQL As String = "SELECT AnnouncementID, AnnoucementText FROM tblAnnouncements"
Dim conn As SqlConnection = New SqlConnection(ConnectionString)
conn.Open()
Dim adapter As SqlDataAdapter = New SqlDataAdapter(SQL, conn)
Dim ds As DataSet = New DataSet("Announcements")
adapter.Fill(ds)
UpdateForm(ds)
Catch ex As Exception
LogError("Timer_Tick", ex)
End Try
End Sub
Now sometimes the internet is disconnected or there is very slow internet. For that I have created a function as below,
Public Function CheckInternetConnection() As Boolean
Try
If My.Computer.Network.IsAvailable = True Then
Return My.Computer.Network.Ping("8.8.8.8")
Else
Return False
End If
Catch ex As Exception
Return False
End Try
End Function
This function is pinging google public DNS but in my application this is the IP address of my database server. I have wrapped the functionality inside Timer_Tick inside CheckInternetConnection so that when there is internet connection only then the database operation is made.
Now problem I am facing is that when I switch internet (using two different wifi conenctions) and when I turn on and off the internet then very rarely the code is broken and exception is created for line adapter.Fill(ds). My guess is that it is because at the start of function there is internet connectivity available and the condition for internet check is passed. When program starts to execute database operation then at that point rarely internet is gone so the program raises exception.
The example I have given is for one function and the actual application (which is quite big and written long time ago) is like this and I have to fix the connectivity issue within the same code. How can I make this fool proof that no database code is ever reached when there is no internet connectivity?
Use a loop to try multiple times. E.g.
int numTries = 3;
while (numTries > 0) {
numTries--;
try {
// open connection, fill
// your code
break; // got here means success
} catch {
if (numTries == 0)
throw; // propagate exception to next level
Thread.Sleep(500); // optional sleep
}
}

"KeepAlive" for TCPClient connection to keep connection open?

Is there a way to keep a TcpClient connection open constantly? I have an application which lets our users scan a carton, some database updates are performed, and a shipping label is sent to and printed from a wireless hip printer (model of printer is Zebra QLn420) which the user is using.
The application attempts to keep a connection to the wireless printer via the TcpClient connection, and multiple checks are made throughout processing to make sure the connection is good, before sending a generated ZPL to the printer for printing.
We have been having an issue with an occasional label missing, and it seems to be whenever the user stops scanning for a few minutes, then resumes. However, it is a semi-rare occurrence when a label is skipped, and as such is rather hard to reproduce (I haven't been able to replicate it myself, but I have seen it happen out in the warehouse).
I would like to know either if there is a way to make sure that the connection is always open (by "pinging" the device every so often), or if there is a way to get feedback that the data has been received and printed.
This is the code I'm calling to ensure a connection:
Public Function Connect(strIP As String, intPort As Integer) As Boolean
Try
'connect to printer via TcpClient, need ip address and port number
'connects without thread, hangs program for 10-20 seconds if printer is not turned on, replaced with code below to thread the connection and set timeout
For i As Integer = 1 To 2
If Not (client IsNot Nothing AndAlso client.Connected) Then
'uses ClientSocketParameters structure to pass to recursive function ConnectionReturned()
clntSockParams = New ClientSocketParameters
clntSockParams.addrs = strIP
clntSockParams.prt = intPort
'create client and call BeginConnect (attempts to connect on separate thread until TimeoutTime has elapsed)
client = New System.Net.Sockets.TcpClient
client.SendTimeout = 5000
client.ReceiveTimeout = 5000
'setup timer with timeout length and start, if timer goes past intTimeoutLength, the Timeout() function is called which closes everything and leaves client = Nothing
AddHandler TimeoutTime.Elapsed, AddressOf Timeout
TimeoutTime.Interval = intTimeoutLength
TimeoutTime.Start()
client.BeginConnect(strIP, intPort, New AsyncCallback(AddressOf ConnectionReturned), clntSockParams)
'keeps the program from doing anything else until BeginConnect either succeeds or fails (due to connect on separate thread)
Do While TimeoutTime.Enabled
System.Threading.Thread.Sleep(500)
Loop
End If
'if TimeoutTime is elapsed and client is Nothing, connection didn't happen, throw an error
If client Is Nothing Then
blnConnected = False
Else
blnConnected = True
Exit For
End If
Next
Catch ex As Exception
blnConnected = False
End Try
Return blnConnected
End Function
Private Sub ConnectionReturned(ByVal ar As System.IAsyncResult)
'this method is called from the client.BeginConnect line in Connect(), make sure timer is running
If TimeoutTime.Enabled Then
'ensure client is initialized
If client Is Nothing Then client = New System.Net.Sockets.TcpClient
'keep calling ConnectionReturned until client.Connected is true
If client.Connected Then
TimeoutTime.Stop()
Else
Dim actualParameters As ClientSocketParameters = DirectCast(ar.AsyncState, ClientSocketParameters)
client.BeginConnect(actualParameters.addrs, actualParameters.prt, New AsyncCallback(AddressOf ConnectionReturned), clntSockParams)
End If
End If
End Sub
Private Sub Timeout(ByVal sender As Object, ByVal e As EventArgs)
'this method is only called if TimeoutTime elapsed, which means no connection was made. close the client object if needed, set to Nothing, and stop TimeoutTime
If TimeoutTime.Enabled Then
Try
client.Close()
Catch ex As Exception
End Try
client = Nothing
TimeoutTime.Stop()
End If
End Sub
According to this question:
tcp client in vb.net not receiving the entire data response data from server
TcpClient is not always guaranteed to deliver all data to the other end of a connection, so if a more reliable connection method is available, that would be worth a try as well.
Please let me know if more information is needed. Thank you!
Originally I got the code for connecting via this link. I've modified it since because it would hang the application for 10-20 seconds if it took longer to connect. Code here is in C# and I translated to VB:
Send ZPL Commands via TCP/IP in C#
This is the link to the docs for the class:
TcpClient Class
Zebra printers have a timeout setting on TCP that I think has a 3 or 5 minute default. The first thing to do is to turn that timeout off. There will still be other reasons that the printer would disconnect so you will need to handle that as well.
embed this into your program:
! U1 setvar "wlan.ip.timeout.enable" "off"
Make sure you send a CR/LF before and after that line.
if you send a query after your format you can know that the whole format made it to the printer. Something like the following would work:
! U1 getvar "device.uptime"
That's not a sane solution. A sane solution is this: If a label isn't completely sent to the printer because the connection failed, make a new connection and send the label.

RetryPolicy.Retrying event not firing during Transient Error Handling for SQL Azure?

I've got website hosted in azure (as a web service) that is using sql azure as it's backend.
My error logs have been heavily populated with what looks to be transient network and sql connection errors.
As such I've implemented the Enterprise Library Transient Error Handling Block. In tests it would seem that its operating correctly.
The issue I'm encountering is that I would like to log instances where this retry logic is occurring. From the documentation RetryPolicy.Retrying looks to be the event I'm after but in tests it doesn't fire. There's plenty of examples in C# that follow the following pattern to fire this event:
var retryPolicy = new RetryPolicy<SqlAzureTransientErrorDetectionStrategy>(retryStrategy);
// Receive notifications about retries.
retryPolicy.Retrying += (sender, args) =>
{
// Log details of the retry.
var msg = String.Format("Retry - Count:{0}, Delay:{1}, Exception:{2}",
args.CurrentRetryCount, args.Delay, args.LastException);
Trace.WriteLine(msg, "Information");
};
I thought I'd adapted this correctly but in short, what's wrong with the code below?!
Private RetryManager As RetryManager
Private WithEvents RetryPolicy As RetryPolicy
Private Sub RetryPolicy_Retrying(ByVal sender As Object, ByVal args As RetryingEventArgs)
' Log details of the retry.
Dim msg = String.Format("Retry - Count:{0}, Delay:{1}, Exception:{2}", args.CurrentRetryCount, args.Delay, args.LastException)
Trace.TraceInformation(msg)
End Sub
Private Sub SetupRetryPolicy()
'If its already set then lets not do it again
If RetryPolicy Is Nothing Then
RetryManager = EnterpriseLibraryContainer.Current.GetInstance(Of RetryManager)()
RetryPolicy = RetryManager.GetRetryPolicy(Of SqlAzureTransientErrorDetectionStrategy)("Exponential Backoff Retry Strategy")
' connect sub as handler to event when retry occurs
AddHandler RetryPolicy.Retrying, AddressOf RetryPolicy_Retrying
End If
End Sub
Public Sub ExecuteAndDoStuff(ByVal connString As String, ByVal cmdText As String)
SetupRetryPolicy()
'get a connection with retry
Using conn As New ReliableSqlConnection(connString, RetryPolicy, RetryPolicy)
conn.Open()
Using cmd As SqlCommand = conn.CreateCommand
Try
cmd.CommandText = cmdText
' this might be overkill, do I need to pass the retry policy in again for the command?
Dim dr As SqlDataReader = cmd.ExecuteReaderWithRetry(RetryPolicy, RetryPolicy)
'... do something with this datareader
Catch ex As Exception
'log error
Trace.TraceError("Query failed to execute despite retry logic: " & ex.ToString)
'continue to throw the error (picked up higher up the chain)
Throw ex
End Try
End Using
End Using
End Sub
I'm totally new to at least half of what's going on in this block of code but before anyone thows a rtfm at me - I tried!
It's hard to tell if anything is wrong in your code; it could be that there are no transient errors being detected at all. How are you making the determination that there are transient errors? The first thing I would do is to make sure you have a repeatable way of creating a transient error.
The way I would setup the test is to have a 1GB database in Azure SQL Database, fill it up with data up until it has reached its storage limit, and then try to add more data (which will generate a transient error everytime).
There are two things to keep in mind with Azure SQL transient errors:
1) They are very hard to test because many of them depend on variables that are outside of your control; one of the easiest transient error to replicate is out of space (the suggestion above)
2) There are a few other types of errors that can be fired, such as router swicthing conditions in Azure, that are not considered transient; for example IOException errors are not captured by the SQL Transient Strategy. As a result, you either need to account for those kinds of errors seperately, or customize the strategy to include these errors. Your catch block should trap these errors in your current implementation.

ObjectDisposedException obtaining user name in SignalR event

I'm logging current SignalR connections in a sql server database. Records are added via the OnConnected and OnReconnected events and removed via the OnDisconnected event.
On deploying to our staging server I am now experiencing an intermittent issue fetching the username of the disconnected user.
This is using SignalR v2.0.3
Public Overrides Function OnDisconnected() As Threading.Tasks.Task
Try
Dim username As String = String.Empty
Try
username = Me.Context.User.Identity.Name ' this is where the error occurs
Catch ex As Exception
_logger.LogWarning(ex, EventLogEntryType.Warning)
End Try
Dim connId = Me.Context.ConnectionId
Dim referer = Me.Context.Headers("Referer")
_connService.RemoveConnection(connId)
Dim msg = New With {.username = username, .connectionId = connId, .referer = referer}
Dim hub = GlobalHost.ConnectionManager.GetHubContext(Of IncidentsHub)()
hub.Clients.All.disconnectionEvent(msg)
Catch ex As Exception
_logger.LogWarning(ex, EventLogEntryType.Error)
End Try
Return MyBase.OnDisconnected()
End Function
I have had to wrap the offending line in an additional try/catch and accept that sometimes there will be no username returned.
The exception seen is:
MOAE - System.ObjectDisposedException: Safe handle has been closed
at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)
at Microsoft.Win32.Win32Native.GetTokenInformation(SafeTokenHandle TokenHandle, UInt32 TokenInformationClass, SafeLocalAllocHandle TokenInformation, UInt32 TokenInformationLength, UInt32& ReturnLength)
at System.Security.Principal.WindowsIdentity.GetTokenInformation(SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass)
at System.Security.Principal.WindowsIdentity.get_User()
at System.Security.Principal.WindowsIdentity.GetName()
at System.Security.Principal.WindowsIdentity.get_Name()
at MyProject.IncidentsHub.OnDisconnected() in C:\Projects\...\IncidentsHub.vb:line 95
Can anyone tell me why this is occurring and if there is a more reliable way to obtain this information?