I have developed winform application using VB.NET. The application is deployed in the machine which is connected to wireless network. The machine is in the car(moving object).
The application has DataGridView loaded with the data get from MSSQL Server(in Remote machine). The data is refreshed for every 5 seconds.
I have used the NetworkAvailabilityChanged event to detect the network status. If the Network is available, then I retrieve the data from the table.
Code:
AddHandler NetworkChange.NetworkAvailabilityChanged, AddressOf NetworkStateChangeHandler
Public Sub NetworkStateChangeHandler(ByVal sender As Object,
ByVal e As NetworkAvailabilityEventArgs)
If e.IsAvailable = True Then
g_bNetworkAlive = True
Else
g_bNetworkAlive = False
End If
End Sub
private Sub GetData()
If g_bNetworkAlive = True
'code to get the data from table
End If
End Sub
Issue:
If the car movers out of the out of the network, the NetworkAvailabilityChanged event is not fired. so it throws the following error for every 5 seconds and application gets crashed.
A network-related or instance-specific error occurred while establishing
a connection to SQL Server. The server was not found or was not accessible.
Temporary fix: I have made Ping request to the SQL server machine for every 5 seconds to detect the network status. It affects the application's performance.
Note: If I manually switch off the Wifi, the NetworkAvailabilityChanged event is fired. The issue is only when the car moves out of the network.
Is there any some other feasible solution to detect the wireless network status?
Indeed there is.
Why send http request to some dummy website when you can check if you are connected to wifi or not locally.
Use ManagedWifi APIs, This will eliminate the slowdown you are facing.
//Create object at the beginning of your application
WlanClient wlanClient = new WlanClient();
//You this code to check wifi availability wherever you need
foreach (WlanInterface _interface in wlanClient.Interfaces)
{
If (_interface.CurrentConnection.wlanAssociationAttributes.dot11Ssid.SSID!=null)
{
// You are connected to wifi
}
}
EDIT: In case you you are not finding dll, direct link. Just reference the Dll and Voila! you are done.
Change your code as
Private Sub GetData()
If My.Computer.Network.IsAvailable AndAlso g_bNetworkAlive
' code to get the data from table
End If
End Sub
You also can check if you have an internet connection by using WebRequest like this:
Private Sub GetData()
If HasInternet AndAlso g_bNetworkAlive Then
'code to get the data from table
End If
End Sub
Public Shared Function HasInternet As Boolean
Return Not (HttpGet("http://www.google.com/") = "Error")
End Function
Public Shared Function HttpGet(url As String) As String
Dim request As WebRequest = WebRequest.Create(url)
request.Method = "GET"
Try
Dim response As WebResponse = request.GetResponse()
Dim dataStream As Stream = response.GetResponseStream()
Dim reader As New StreamReader(dataStream)
Dim responseFromServer As String = reader.ReadToEnd()
reader.Close()
dataStream.Close()
response.Close()
Return responseFromServer
Catch ex As Exception
Return "Error"
End Try
End Function
And you can check the sql connection by using the following function:
Private Function IsDatabaseConnected() As Boolean
Try
Using sqlConn As New SqlConnection("YourConnectionString")
sqlConn.Open()
Return (sqlConn.State = ConnectionState.Open)
End Using
Catch e1 As SqlException
Return False
Catch e2 As Exception
Return False
End Try
End Function
I would simply use try..catch, so if you get exception, you can know, based on its id, why the code failed, and decide what to do next, and finally you can execute some more code regardless of data being retrieved or not
Private Sub GetData()
Try
'code to get the data from table
Catch ex As Exception
' Show the exception's message.
MessageBox.Show(ex.Message)
' Show the stack trace, which is a list of methods
' that are currently executing.
MessageBox.Show("Stack Trace: " & vbCrLf & ex.StackTrace)
Finally
' This line executes whether or not the exception occurs.
MessageBox.Show("in Finally block")
End Try
End Sub
Related
I'm using the following code to open a database connection. If the connection fails for any reason, I get the typical VB error message with all of the details. and my program stops. It does not give me my graceful message and ending.
My try/catch does not work regardless of the connection error (whether it is password related, network related, or sql server related).
I need my program to continue on even if I can't connect to the database.
Public Class SQL_Connection
Public conn As New SqlConnection
Public cmd As New SqlCommand
Public Sub New()
conn.ConnectionString = my_connection_string
Try
conn.Open()
Catch ex As Exception
MessageBox.Show("Unable to open database. " + ex.ToString)
End Try
cmd = conn.CreateCommand()
End If
End Sub
End Class
Have a look at this article.
If the program is not run in debug mode, the try catch would do it's thing right away with out stopping the execution.
Sometimes when my customers turn on or restart their computer, and open my vb.net application directly, the application opens before SQL Server has started completely.
This results in many unexpected behaviors. To avoid this situation, I need to start a splash screen and check the SQL Server state within it, and only when SQL Server state indicates that it is loaded completely, can I run the whole application.
The question is: how to check the SQL Server state, whether it is finished loading or not? The whole SQL Server, not the database.
You can instantiate a timer in your splash form that checks if it can log into the database every one second (or whatever interval you like). I'd invoke the splash form as modal so the calling app can't continue until the splash form has detected the connection and closed itself.
At the very least you need the server name to check the connection for. If it is using a named instance then the server name should also include the instance name in the format "myserver\myinstance".
I've encapsulated the connection checking logic in the 3 overloaded functions IsConnected. You can use these functions in your splash form to check connection from the timer tick. (Each depends on the next). You can use whichever function overload is suitable based on the input items you have available.
For the first overload, if the app is running under a Windows security context that can connect to the db server then you don't need to provide the username and password (pass as empty string), otherwise you need to provide those credentials needed to login to the db server. Or you can provide your own connection string or connection object for the other overloads.
(code within the splash form)...
Private Sub Timer1_Tick(sender As Object, e As System.EventArgs) Handles Timer1.Tick
If Me.IsConnected("(local)\SQL2008R2", "", "") Then Me.Close()
End Sub
Public Function IsConnected(ServerName As String, UserID As String, Password As String) As Boolean
Dim connStr As String = String.Format("Data Source={0}", ServerName)
If Not String.IsNullOrEmpty(UserID) Then
connStr &= String.Format(";User ID={0};Password={1}", UserID, Password)
Else
connStr &= ";Integrated Security=True"
End If
Return IsConnected(connStr)
End Function
Public Function IsConnected(Connection As String) As Boolean
Static conn As SqlConnection
If conn Is Nothing Then
conn = New SqlConnection(Connection)
conn.Open()
End If
Return IsConnected(conn)
End Function
Public Function IsConnected(ByRef Conn As SqlConnection) As Boolean
If Conn IsNot Nothing Then Return (Conn.State = ConnectionState.Open)
Return False
End Function
I'd invoke the splash form from the main app as a modal dialog, as such, so the app is blocked until the connection is detected.
(from the calling app form...)
frm_Splash.ShowDialog()
I made a windows service that listens to a port(using HttpListner) and accepts XML Repuest and once the request is valid it connects to a database (usually on the same pc) and construct the xml response and sends it back.
So far, Everything is great except when the service accepts two or more requests that require retrieving 100+ records, it crashes. First, I was using just one shared connection to the database, it does crashes, then I changed to multiple connections i.e. when you need something from the database create your connection.
I did some troubleshooting using eventlog to get the exceptions, here are some of the exception I got before crashing:
A transport-level error has occurred when receiving results from the server. (provider: Session Provider, error: 19 - Physical connection is not usable)
The ConnectionString property has not been initialized.
ExecuteReader requires an open and available Connection. The connection's current state is connecting.
ExecuteReader requires an open and available Connection. The connection's current state is open.
Invalid attempt to call Read when reader is closed.
Here is a sample of the code I am using:
Private Sub StartLisitng()
MyListener.Start()
Dim result As IAsyncResult
result = MyListener.BeginGetContext(New AsyncCallback(AddressOf ListnerCallback), MyListener)
End Sub
Private Sub ListnerCallback(ByVal result As IAsyncResult)
StartLisitng()
If result.IsCompleted Then
ctx = MyListener.EndGetContext(result)
Dim HandleRequestThread As New Thread(AddressOf New HandleRequest(ctx).RequestProcess)
HandleRequestThread.Start()
End If
End Sub
Public Function RemoteConnect(ByVal DNSBranch As String) As Boolean
Dim IsRemoteConnected As Boolean = False
RemoteConnString = "Data Source = " & DNSBranch & ";Initial Catalog=xxxxx;User ID=xxxxx;Password=xxxxx;Connect Timeout=5;MultipleActiveResultSets=True;"
RemoteConn = New SqlConnection(RemoteConnString)
Try
RemoteConn.Open()
Catch ex As Exception
IsRemoteConnected = False
End Try
If RemoteConn.State = 1 Then
IsRemoteConnected = True
Else
IsRemoteConnected = False
End If
Return IsRemoteConnected
End Function
Public Function RemoteExeComd(ByVal DNSBranch As String, ByVal query As String) As DataSet
Dim MyDataSet As New DataSet
RemoteConnect(DNSBranch)
Comd = New SqlCommand(query, RemoteConn)
Adapter = New SqlDataAdapter(Comd)
If query.StartsWith("Se") Or query.StartsWith("se") Or query.StartsWith("SE") Then
If RemoteConn.State = ConnectionState.Open Then
Try
Adapter.Fill(MyDataSet)
Catch ex As Exception
EventLog.WriteEntry("My Service", "Exception: " & ex.Message.ToString)
End Try
End If
Else
Try
Comd.ExecuteNonQuery()
Catch ex As Exception
EventLog.WriteEntry("My Service", "Exception: " & ex.Message.ToString)
End Try
End If
Comd.Dispose()
Adapter.Dispose()
Return MyDataSet
End Function
I do not have any problems with the listner or parsing the request, I know I have the problem on how i interact with the databse.
Any advice, Thanks for you time.
I have written a web application in which I have not allowed connection pooling for this application. I have written sample code as shown below which gets record from my table 20 times and fill in Data set I have close connection at every time.
But if I look in SQL Server Activity monitor it shows me one connection open in sleeping mode.
anyone tell me why this happens?
does this sleeping connection increase if users increase?
If SQL Server pools my connection then why its pooling if I have not allowed pooling for this application? How can I avoid this?
Code to fetch data
Try
Dim i As Integer
For i = 0 To 20
Dim _db As New commonlib.Common.DBManager(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString.ToString())
GridView1.DataSource = _db.ExecuteDataSet(CommandType.Text, "SELECT * FROM BT_AppSetting")
GridView1.DataBind()
Next
Catch ex As Exception
Response.Write(ex.Message.ToString())
ex = Nothing
End Try
DBManager constructor
'CONSTRUCTOR WHICH ACCEPTS THE CONNECTION STRING AS ARGUMENT
Public Sub New(ByVal psConnectionString As String)
'SET NOT ERROR
_bIsError = False
_sErrorMessage = Nothing
_cn = New SqlConnection
_sConnectionString = psConnectionString
_cn.ConnectionString = _sConnectionString
Try
_cn.Open()
Catch ex As Exception
_bIsError = True
_sErrorMessage = ex.ToString
ex = Nothing
End Try
End Sub
ExecuteDataSet Function body
Public Function ExecuteDataSet(ByVal CmdType As CommandType, ByVal CmdText As String, ByVal ParamArray Params As SqlParameter()) As DataSet
Try
Dim cmd As New SqlCommand
Dim da As New SqlDataAdapter(cmd)
Dim ds As New DataSet
PrepareCommand(cmd, CmdType, CmdText, Params)
da.Fill(ds)
cmd.Parameters.Clear()
If _cn.State = ConnectionState.Open Then
_cn.Close()
End If
Return ds
Catch ex As Exception
_sErrorMessage = ex.ToString
_bIsError = True
ex = Nothing
Return Nothing
End Try
Please help me.... Waiting for kind reply
1)I THINK sql server does not close the connection right away. That why you see it.
2) Since you are closing the connection you should see only one. Unless your users are running the code at the same time. e.g if it was in a web page and there are 2 users, you will/shoudl see 2 connections.
Also if dont close your connections (just to try) your number of connection will (should :) ) go up.
It is your .net application that pools the connection and not sql server.
My goal is to have this program send a logout command when the user is logging off or shutting down their pc.
The program is connected to a server application via a tcp socket using a Winsock object. Calling singleSock.SendData "quit" & vbCrLf is simply a way of logging out. I am going to start capturing data with Wireshark, but I'd like to know if I'm trying to do something fundamentally wrong.
Oddly enough, if I set Cancel to True, and allow a timer I have running to do the logout command, then call another unload, it works, however in testing this configuration (different code), this prevents the user from logging out the first time. They have to initiate a logout, it doesn't do anything, then they logout again and my program is gone at that point. Also oddly enough, in Vista the logout goes through after briefly displaying a screen saying my program was preventing the logout. Most of my deployment is on XP, which has the two logouts problem.
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
If UnloadMode = vbFormControlMenu Then
Me.WindowState = vbMinimized
Cancel = True
Else
If SHUTDOWN_FLAG = True Then
Cancel = False
Else
Cancel = True
SHUTDOWN_FLAG = True
End If
tmrSocket.Enabled = False
SHUTDOWN_FLAG = True
Sleep (1000)
singleSock.SendData "quit" & vbCrLf
Call pUnSubClass
'If singleSock.state <> sckConnected Then
' singleSock.Close
' tmrSocket.Enabled = False
' LogThis "tmrSocket turned off"
'End If
DoEvents
End If
End Sub
You're not waiting for the Winsock control to actually send the "quit" message. The SendData method is asynchronous: it can return before the data has actually been sent across the network. The data is buffered locally on your machine and sent at some later time by the network driver.
In your case, you are trying to send the "quit" message and then closing the socket almost immediately afterwards. Because SendData is asynchronous, the call might return before the "quit" message has actually been sent to the server, and therefore the code might close the socket before it has a chance to send the message.
It works when you cancel the unloading of the form first and let the timer send the "quit" message because you're giving the socket enough extra time to send the message to the server before the socket is closed. However, I wouldn't count on this always working; it's a coincidence that the extra steps gave the socket enough time to send the message, and it's not guaranteed to always work out that way.
You can fix the problem by waiting for the socket to raise a SendCompleted event after you send the "quit" message and before you close the socket. Below is a basic example. Note that the QueryUnload code is much simpler.
Private m_bSendCompleted As Boolean
Private m_bSocketError As Boolean
Private Sub singleSock_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
'Set error flag so we know if a SendData call failed because of an error'
'A more robust event handler could also store the error information so that'
'it can be properly logged elsewhere'
m_bSocketError = True
End Sub
Private Sub singleSock_SendCompleted()
'Set send completed flag so we know when all our data has been sent to the server'
m_bSendCompleted = True
End Sub
'Helper routine. Use this to send data to the server'
'when you need to make sure that the client sends all the data.'
'It will wait until all the data is sent, or until an error'
'occurs (timeout, connection reset, etc.).'
Private Sub SendMessageAndWait(ByVal sMessage As String)
m_bSendCompleted = False
singleSock.SendData sMessage
singleSock.SendData sMessage
Do Until m_bSendCompleted or m_bSocketError
DoEvents
Loop
If m_bSocketError Then
Err.Raise vbObjectError+1024,,"Socket error. Message may not have been sent."
End If
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
'This is (almost) all the code needed to properly send the quit message'
'and ensure that it is sent before the socket is closed. The only thing'
'missing is some error-handling (because SendMessageAndWait could raise an error).'
If UnloadMode = vbFormControlMenu Then
Me.WindowState = vbMinimized
Cancel = True
Else
SendMessageAndWait "quit" & vbCrLf
singleSock.Close
End If
End Sub
You can make the code cleaner by putting the logic to send a message and wait for it to be sent in a separate class. This keeps the private variables and the event handlers in one place, instead of having them litter your main code. It also makes it easier to re-use the code when you have multiple sockets. I called the class SynchronousMessageSender for lack of a better name. This example also has more complete error handling:
SynchronousMessageSender.cls
Private WithEvents m_Socket As Winsock
Private m_bAttached As Boolean
Private m_bSendCompleted As Boolean
Private m_bSocketError As Boolean
Private Type SocketError
Number As Integer
Description As String
Source As String
HelpFile As String
HelpContext As Long
End Type
Private m_LastSocketError As SocketError
'Call this method first to attach the SynchronousMessageSender to a socket'
Public Sub AttachSocket(ByVal socket As Winsock)
If m_bAttached Then
Err.Raise 5,,"A socket is already associated with this SynchronousMessageSender instance."
End If
If socket Is Nothing Then
Err.Raise 5,,"Argument error. 'socket' cannot be Nothing."
End If
Set m_Socket = socket
End Sub
Private Sub socket_SendCompleted()
m_bSendCompleted = True
End Sub
Private Sub socket_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
m_bSocketError = True
'Store error information for later use'
'Another option would be to create an Error event for this class'
'and re-raise it here.'
With m_lastSocketError
.Number = Number
.Description = Description
.Source = Source
.HelpFile = HelpFile
.HelpContext = HelpContext
End With
End Sub
'Sends the text in sMessage and does not return'
'until the data is sent or a socket error occurs.'
'If a socket error occurs, this routine will re-raise'
'the error back to the caller.'
Public Sub SendMessage(ByVal sMessage As String)
If Not m_bAttached Then
Err.Raise 5,,"No socket is associated with this SynchronousMessageSender. Call Attach method first."
End If
m_bSendCompleted = False
m_bSocketError = False
m_socket.SendData sMessage & vbCrLf
'Wait until the message is sent or an error occurs'
Do Until m_bSendCompleted Or m_bSocketError
DoEvents
Loop
If m_bSocketError Then
RaiseLastSocketError
End If
End Sub
Private Sub RaiseLastSocketError()
Err.Raise m_lastSocketError.Number, _
m_lastSocketError.Source, _
m_lastSocketError.Description, _
m_lastSocketError.HelpFile, _
m_lastSocketError.HelpContext
End Sub
Example Use
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Dim sender As New SynchronousMessageSender
'Ignore errors since the application is closing...'
On Error Resume Next
If UnloadMode = vbFormControlMenu Then
Me.WindowState = vbMinimized
Cancel = True
Else
Set sender = New SynchronousMessageSender
sender.AttachSocket singleSock
sender.SendMessage "quit"
singleSock.Close
End If
End Sub
By using a separate class, now all the necessary code can be placed in the Form_QueryUnload, which keeps things tidier.
Wouldn't is be easier to just go without the QUIT command. In your server code just assume that the closing of a socket does the same thing as receiving a quit.
I addition, one thing you want to watch out for is abrupt shut downs of the client software. For example, a machine that losses power or network connection or a machine that goes into sleep or hibernate mode.
In those cases you should be periodically checking the connection for all of the clients from the server and closing any connections that do not respond to some kind of ping command.