So I reversed the syntax of this send sms code from c# to vb net so I can reuse it.
The code works sometimes, but for some reason it would often give me the "response received is incomplete" exception.
I was thinking perhaps my code is processing commands faster than my GSM device, could handle, so I tried increasing the timeout response for the serial port, still ends up with this exception.
What do you think is the problem and what would you recommend I do to solve it?
Public Class SmsHelper
Public receiveNow As AutoResetEvent
#Region "Open and Close Ports"
'Open Port
Public Function OpenPort(portName As String, baudRate As Integer, dataBits As Integer, readTimeout As Integer, writeTimeout As Integer) As SerialPort
receiveNow = New AutoResetEvent(False)
Dim port As New SerialPort()
Try
port.PortName = portName
'COM1
port.BaudRate = baudRate
'9600
port.DataBits = dataBits
'8
port.StopBits = StopBits.One
'1
port.Parity = Parity.None
'None
port.ReadTimeout = readTimeout
'300
port.WriteTimeout = writeTimeout
'300
port.Encoding = Encoding.GetEncoding("iso-8859-1")
port.NewLine = vbCrLf
AddHandler port.DataReceived, AddressOf port_DataReceived
port.Open()
port.DtrEnable = True
port.RtsEnable = True
Catch ex As Exception
Throw ex
End Try
Return port
End Function
' Send AT Command
Public Function SendATCommand(port As SerialPort, command As String, responseTimeout As Integer, errorMessage As String) As String
Try
port.DiscardOutBuffer()
port.DiscardInBuffer()
receiveNow.Reset()
port.Write(command & Convert.ToString(vbCrLf))
Dim input As String = ReadResponse(port, responseTimeout)
Console.WriteLine("Received data is " & input)
If (input.Length = 0) OrElse ((Not input.EndsWith(vbCr & vbLf & "> ")) AndAlso (Not input.EndsWith(vbCr & vbLf & "OK" & vbCr & vbLf))) Then
Throw New ApplicationException("No success message was received.")
End If
Return input
Catch ex As Exception
Throw ex
Finally
End Try
End Function
'Receive data from port
Public Sub port_DataReceived(sender As Object, e As SerialDataReceivedEventArgs)
Try
If e.EventType = SerialData.Chars Then
receiveNow.[Set]()
End If
Catch ex As Exception
Throw ex
End Try
End Sub
Public Function ReadResponse(port As SerialPort, timeout As Integer) As String
Dim serialPortData As String = ""
Try
Do
If receiveNow.WaitOne(timeout, False) Then
Dim data As String = port.ReadLine()
serialPortData += data
Else
'Console.WriteLine("SerialPortData data is " & serialPortData)
If serialPortData.Length > 0 Then
Console.WriteLine("SerialPortData is " & serialPortData.ToString)
Throw New ApplicationException("Response received is incomplete.")
Else
Throw New ApplicationException("No data received from phone.")
End If
End If
Loop While Not serialPortData.EndsWith(vbCr & vbLf & "OK" & vbCr & vbLf) AndAlso Not serialPortData.EndsWith(vbCr & vbLf & "> ") AndAlso Not serialPortData.EndsWith(vbCr & vbLf & "ERROR" & vbCr & vbLf)
Catch ex As Exception
Throw ex
End Try
Return serialPortData
End Function
Shared readNow As New AutoResetEvent(False)
Public Function SendMessage(port As SerialPort, phoneNo As String, message As String) As Boolean
Dim isSend As Boolean = False
Try
Dim recievedData As String = SendATCommand(port, "AT", 3000, "No phone connected")
Dim command As String = "AT+CMGF=1" + Char.ConvertFromUtf32(13)
recievedData = SendATCommand(port, command, 3000, "Failed to set message format.")
' AT Command Syntax - http://www.smssolutions.net/tutorials/gsm/sendsmsat/
command = (Convert.ToString("AT+CMGS=""") & phoneNo) + """" + Char.ConvertFromUtf32(13)
recievedData = SendATCommand(port, command, 3000, "Failed to accept phoneNo")
'wait(2)
command = message & Char.ConvertFromUtf32(26)
recievedData = SendATCommand(port, command, 3000, "Failed to send message")
Console.WriteLine("Received data is " & recievedData)
If recievedData.EndsWith(vbCr & vbLf & "OK" & vbCr & vbLf) Then
isSend = True
ElseIf recievedData.Contains("ERROR") Then
isSend = False
End If
Return isSend
Catch ex As Exception
Throw ex
End Try
End Function
Private Shared Sub DataReceived(sender As Object, e As SerialDataReceivedEventArgs)
Try
If e.EventType = SerialData.Chars Then
readNow.[Set]()
End If
Catch ex As Exception
Throw ex
End Try
End Sub
#End Region
End Class
Related
Ive written a service application that listens to a port for any communication that may come through, our lab will run a certain test which will send serial data down every couple hours or so. the service is runs picks up the data fine for a few hours and then mysteriously stops. the system eventlog says the service terminated unexpectedly. and in the application event log it has a more descriptive .NET error,
Application: BondTestService.exe Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.ObjectDisposedException at
System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean
ByRef) at
System.StubHelpers.StubHelpers.SafeHandleAddRef(System.Runtime.InteropServices.SafeHandle,
Boolean ByRef) at
Microsoft.Win32.UnsafeNativeMethods.GetOverlappedResult(Microsoft.Win32.SafeHandles.SafeFileHandle,
System.Threading.NativeOverlapped*, Int32 ByRef, Boolean) at
System.IO.Ports.SerialStream+EventLoopRunner.WaitForCommEvent() at
System.Threading.ThreadHelper.ThreadStart_Context(System.Object) at
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext,
System.Threading.ContextCallback, System.Object, Boolean) at
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
System.Threading.ContextCallback, System.Object, Boolean) at
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
System.Threading.ContextCallback, System.Object) at
System.Threading.ThreadHelper.ThreadStart()
i was reading how services behave and how serial ports behave, so correct me if im wrong if the there is a 2 hour gap or so inbetween tests, the service will assume that its not running and stop itself?
I also read after reading the buffer from the serial port i append to a string builder object like below and do what i need to the string, then what happens to the serial port does it just stay open waiting for next value or do i have to close it and reopen it in order to refresh it?
Not sure how to handle this as it needs to be open waiting for the lab tester to send his data at any given time.
Imports System
Imports System.Data.SqlClient
Imports System.IO.Ports
Imports System.Net.Mime
Imports Microsoft.Win32
Imports System.IO
Imports System.Text.RegularExpressions
Imports BondTestService.PI
Imports PCA.Core.Configuration
Public Class Bond
Dim WithEvents serialPort As New IO.Ports.SerialPort
Public Delegate Sub myDelegate()
Public RawString As New System.Text.StringBuilder
Public value As String
Public BondTest As Integer = 10
#Region "Commport Traffic and Configuration Validations"
Public Sub StartListening()
If serialPort.IsOpen Then
serialPort.Close()
ErrorLog2(Now.ToString & "Port Closed because StartListening method started over")
End If
Try
With serialPort
.PortName = Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("commport")
.BaudRate = CInt(Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("baudrate"))
If Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("parity") = 0 Then
.Parity = Parity.None
End If
If Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("stopbits") = 1 Then
.StopBits = StopBits.One
End If
.DataBits = CInt(Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("bytesize"))
.Handshake = Handshake.None
If Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("RtsControl") = 1 Then
.RtsEnable = True
Else
.RtsEnable = False
End If
End With
serialPort.Open()
'debug
'ErrorLog2("Listening to COM 19, SerialPort has been Opened")
Catch ex As Exception
ErrorLog2(Now.ToString & ex.tostring)
End Try
End Sub
Public Function Filelocator() As String
' Dim filePath As String = IO.Path.Combine(Application.StartupPath, "bondtest.bat")
Dim filePath As String = IO.Path.Combine("C:\Program Files (x86)\PIPC\Interfaces\Lab", "BondTest.bat")
'Dim reader As New System.IO.StreamReader(filePath)
Dim LineNumber = 4
Using file As New StreamReader(filePath)
' Skip all preceding lines: '
For i As Integer = 1 To LineNumber - 1
If file.ReadLine() Is Nothing Then
ErrorLog2("LineNumber")
End If
Next
' Attempt to read the line you're interested in: '
Dim line As String = file.ReadLine()
If line Is Nothing Then
ErrorLog2("LineNumber")
End If
Return line
End Using
End Function
Private Sub serialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
Try
If GetBondInterfaceStatus = 1 Then
UPdateVariable()
Else
exit Sub
End If
Catch ex As Exception
Errorlog2(Ex.Tostring)
End Try
End Sub
#End Region
#Region "String Handling"
Public Sub UPdateVariable()
With RawString
.Append(serialPort.ReadLine())
End With
try
ErrorLog2(now.ToString & RawString.ToString)
InsertTestDataDEBUG(GetRecordID, BondTest, BondTestType.ToUpper.ToString, GetBondPosition(), StringParser(RawString.ToString()), RawString.tostring)
InsertTestData(GetRecordID, BondTest, BondTestType.ToUpper.ToString, GetBondPosition(), StringParser(RawString.ToString()))
RawString.Clear()
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
End Sub
Public Function StringParser(RawString As String)As Double ()
Dim Moisture = RawString
Dim pattern As String = "[0-9],"
Dim regex As New Regex(pattern)
Dim Counter As Integer = 0
Dim dblValues(1) As Double
Dim values As String() = Moisture.Split(New Char() {" "c})
for i = 0 to values.Count - 1
if regex.IsMatch(values(i)) Then
dblValues(Counter) = CDbl(values(i).Substring(0,1))
Counter = Counter + 1
Elseif values(i) = "" Then
continue for
else
if Double.TryParse(values(i), dblValues(Counter)) Then
Counter = Counter + 1
End If
End If
Next
Return dblValues
End Function
#End Region
#Region "SQL Statements"
Private Sub InsertTestData(RecordID As Integer, BondTest As Integer, TestType As String, TestPos As Integer, dataArray() As Double)
Dim InsertQuery As String = ""
Dim conn As New BondSQLConnection("PaperTests")
' Dim TestPos = StartingTestPos + (CInt(dataArray(0)) - 1)
conn("#RecordID") = RecordID
conn("#Test") = BondTest
conn("#TestType") = TestType
conn("#TestPos") = TestPos
conn("#TestData") = dataArray(1)
conn("#TestDateTime") = now.tostring
InsertQuery = "INSERT INTO PaperTests.dbo.PaperTestValues(ReelRecordID, Test, TestLocation, TestPosition, TestValue, TestTimeStamp) VALUES (#RecordID, #Test, #TestType, #TestPos, #TestData, #TestDateTime)"
Try
conn.ExecuteNonQuery(InsertQuery)
IncrementTestPosition
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
End Sub
Private Sub InsertTestDataDEBUG(RecordID As Integer, BondTest As Integer, TestType As String, TestPos As Integer, dataArray() As Double, rawString As String)
Dim InsertQuery As String = ""
Dim conn As New BondSQLConnection("PaperTests")
conn("#RecordID") = RecordID
conn("#Test") = BondTest
conn("#TestType") = TestType
conn("#TestPos") = TestPos
conn("#TestData") = dataArray(1)
conn("#RawString") = rawString
conn("#TestDateTime") = now.tostring
InsertQuery = "INSERT INTO PaperTests.dbo.InterfaceTesting(ReelRecordID, Test, TestLocation, TestPosition, TestValue, TestTimeStamp, RawValue) VALUES (#RecordID, #Test, #TestType, #TestPos, #TestData, #TestDateTime, #RawString)"
Try
conn.ExecuteNonQuery(InsertQuery)
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
End Sub
Private Sub IncrementTestPosition()
Dim tempPosition As Integer = GetBondPosition()
Dim FrontOriginalMax = 5
Dim CenterOriginalMax = 15
Dim BackOriginalMax = 25
Dim FrontRetestOrWinderMax = 10
Dim CenterRetestOrWinderMax = 20
Dim BackRetestOrWinderMax = 30
If tempPosition = FrontOriginalMax Then
tempPosition = 11
else if tempPosition = CenterOriginalMax Then
tempPosition = 21
else if tempPosition = BackOriginalMax Then
tempPosition = 1
Else If tempPosition = FrontRetestOrWinderMax then
tempPosition = 1
Else If tempPosition = CenterRetestOrWinderMax then
tempPosition = 1
Else If tempPosition = BackRetestOrWinderMax then
tempPosition = 1
else
tempPosition = tempPosition + 1
End If
SetBondPosition(tempPosition.tostring)
End Sub
#End Region
#Region "Get PiValues"
Private Function GetRecordID() As Int64
Dim RecordID As Int32 = 0
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
RecordID = piserver.GetCurrentValue("PAPERLAB:PaperLabReelSelected")
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return RecordID
End Function
Private Function GetBondPosition() As Int64
Dim BondPos As Int32 = 0
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
BondPos = CInt(piserver.GetCurrentValue("PAPERLAB:SBOND.POS"))
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return BondPos
End Function
Private Sub SetBondPosition(pos As String)
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
piserver.WriteValue("PAPERLAB:SBOND.POS", pos)
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
End Sub
Private Function BondTestType() As String
Dim TestType As String = ""
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
TestType = piserver.GetCurrentValue("M1:BOND.TYPE")
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return TestType
End Function
Private Function BondReelLoc() As String
Dim ReelLoc As String = ""
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
ReelLoc = piserver.GetCurrentValue("M1:BOND.ReelLoc")
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return ReelLoc
End Function
Private Function GetBondInterfaceStatus() As Integer
Dim Status As Integer = 0
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
Status = CInt(piserver.GetCurrentValue("PAPERLAB:BOND_INTERFACE.S"))
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return Status
End Function
#End Region
#Region "Debug"
Private Sub ErrorLog(RecordID As Int32, BondTest As Integer, ReelLoc As String, TestType As String, StartingTestPos As Integer, dataArray() As Double)
Dim SavePath As String = "C:\Program Files (x86)\PIPC\Interfaces\Lab"
Dim NameOfFile As String = "BondTest Debug File"
Dim TestPos = StartingTestPos + (CInt(dataArray(0)) - 1)
If System.IO.File.Exists(SavePath & "\" & NameOfFile & ".txt") Then
Using sw As StreamWriter = New StreamWriter(SavePath & "\" & NameOfFile & ".txt", True)
' For i = 0 To dataArray.Count -1
sw.WriteLine(" ")
sw.WriteLine(RecordID & " " & BondTest & " " & ReelLoc & " " & TestType & " " & TestPos & " " & dataArray(1).ToString)
' TestPos = TestPos + 1
' Next
End Using
else
File.Create(SavePath & "\" & NameOfFile & ".txt").Dispose()
Using sw As StreamWriter = File.CreateText(SavePath & "\" & NameOfFile & ".txt")
'For i = 0 To dataArray.Count -1
sw.WriteLine(" ")
sw.WriteLine(RecordID & " " & BondTest & " " & ReelLoc & " " & TestType & " " & TestPos & " " & dataArray(1).ToString)
' TestPos = TestPos + 1
'Next
End Using
End If
End Sub
Private Sub ErrorLog2(dataArray as string)
Dim SavePath As String = "C:\Program Files (x86)\PIPC\Interfaces\Lab"
Dim NameOfFile As String = "BondTest Debug File"
' Dim TestPos = StartingTestPos
If System.IO.File.Exists(SavePath & "\" & NameOfFile & ".txt") Then
Using sw As StreamWriter = New StreamWriter(SavePath & "\" & NameOfFile & ".txt", True)
sw.WriteLine(" ")
sw.WriteLine(dataArray)
End Using
else
File.Create(SavePath & "\" & NameOfFile & ".txt").Dispose()
Using sw As StreamWriter = File.CreateText(SavePath & "\" & NameOfFile & ".txt")
sw.WriteLine(" ")
sw.WriteLine(dataArray)
End Using
End If
End Sub
#End Region
This is a screenshot of the errors:
Thanks in advance
Normally, after opening the serial port in .NET it stays opened for arbitrary time. I've written several .NET applications were serial ports are used for months or years without app or computer restart and they work well.
According to the exception info you posted it looks like that serial port has been disposed. There are several possible reasons.
Using bad driver or HW, that disconnects your serial port. I've been using many USB-to-RS232 converters and some of them had bad drivers so sometimes ports were randomly disconnected and ObjectDisposedException was thrown. In earlier Windows editions (XP) the OS even 'blue-screened'. Here is more info about such situation where ObjectDisposedException is thrown.
This is a known problem with SerialPort. Device removal causes an uncatchable exception in a background thread it uses (WaitForCommEvent). The only solutions are to not use SerialPort or create a .config file that puts unhandled exception trapping mode back to .NET 1.1 behavior.
The USB cable of your RS232 converter is manually disconnected. If you do this, most drivers normally disconnect all handles to your serial port and .NET throws ObjectDisposedException.
Also check your power management settings on your USB port if USB-to-RS232 converter is used. Try to uncheck this option on USB device to which converter is connected.
SW bug in your code.
It's always advisable (especially if converter used) to try more types of converters just to be sure there is no problem in HW device/driver.
Update: So as Timmy was saying the connection was getting disposed by garbage collection. so i declared the object as a shared variable in the class
Shared Dim WithEvents serialPort as IO.Ports.SerialPort
and in the OnStart method i initiated it as a new Serial port and rocked on. has not throw any errors since garbage collection wont disposed of it. Hope this helps somebody having a similar issue.
I have an issue with reading the results of a serialport communication.
If have multiple functions, which are executing different commands on my device and also receiving and process the sent results on slightly different ways.
If i call the functions all at once, its not working 100% reliable. If i call only one of these functions, all of them working perfectly. Im assuming, thinks going a little to fast for the slow serialPort communication, so some functions dont get propper results when calling all "at once"
Code which calls 3 functions (Error on different Positions: "Index out of (array) range" or "CRC incorrect")
Private Sub btn_initialize_Click(sender As Object, e As EventArgs) Handles btn_initialize.Click
Dim actual_mw As Double
Dim attenuated As Integer
'open (virtual)COMport
If rfid.init_serialport(cb_com.SelectedItem.ToString) = True Then
flp_data.Visible = True
lbl_snr_data.Text = rfid.get_serial_number()
lbl_type_data.Text = rfid.get_reader_type
Dim collection As MatchCollection = Regex.Matches(rfid.get_attennuation, "\d+")
attenuated = collection(1).Value
If attenuated = 0 Then
lbl_leistung_data.Text = "100mW / 100mW"
Else
actual_mw = 100 - (10 ^ (attenuated / 10))
lbl_leistung_data.Text = Math.Round(actual_mw, 2) & "mW / 100mW"
End If
Else
MsgBox("Error! COM-Schnittstelle konnte nicht initialisiert werden!", MsgBoxStyle.Critical, "Error")
End If
End Sub
Intialize and Dispose SerialPort
Public Class RFE
Private RF_CHECKSUM As Byte
Private device_output() As Byte
Private data() As Byte
Private device_input() As Byte
Private sp As SerialPort
Public Function init_serialport(portName As String) As Boolean
Try
sp = New SerialPort
sp.PortName = portName
sp.BaudRate = 9600
sp.Parity = Parity.None
sp.DataBits = 8
sp.StopBits = StopBits.One
sp.Handshake = Handshake.None
sp.ReadTimeout = 500
sp.WriteTimeout = 500
sp.Open()
If sp.IsOpen Then
Return True
Else
Return False
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Function
Public Function disp_serialport()
Try
sp.Dispose()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Function
Functions
Public Function get_serial_number() As String
Try
Dim serial_number As String
ReDim data(8)
data(0) = RF_START_BYTE0
data(1) = RF_START_BYTE1
data(2) = RF_START_BYTE2
data(3) = RF_COMMAND_START_BYTE
data(4) = RF_READER_COMMON
data(5) = RF_GET_SERIAL_NUMBER
data(6) = RF_LENGTH_START_BYTE
data(7) = &H0
data(8) = RF_CHECKSUM_START_BYTE
RF_CHECKSUM = Hex(calc_xor(data, 1))
device_input = data
Array.Resize(device_input, data.Length + 1)
device_input(9) = "&H" & RF_CHECKSUM
sp.Write(device_input, 0, device_input.Length)
ReDim device_output(sp.BytesToRead)
sp.Read(device_output, 0, device_output.Length - 1)
If calc_xor(device_output, 3) <> device_output(14) Then
MsgBox("CRC incorrect!", MsgBoxStyle.Critical, "Error")
Form1.Close()
End If
serial_number = Hex(device_output(9)).PadLeft(2, "0") & "-" & Hex(device_output(10)).PadLeft(2, "0") & "-" & Hex(device_output(11)).PadLeft(2, "0") & "-" _
& Hex(device_output(12)).PadLeft(2, "0")
device_output = Nothing
data = Nothing
RF_CHECKSUM = Nothing
sp.DiscardInBuffer()
sp.DiscardOutBuffer()
Return serial_number
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Function
The other functions are structure-vise the same, only the sent bytes and the processing of the result is slightly different.
As I said, im assueming the problem is the transaction of the signals (possibly in both directions) so the SerialPort and/or Device cant handle things fast enough.
What do I have to do so that the communication runs reliably/sequentially?
Maybe DataReceivedHandler could fix the Problem? But for every function I call, the processing of the result is different, how do I implement this in the DataReceivedHandler then (if the Handler could fix the Problem)?
Thank you all!
I have not managed to find a conclusive answer for this on here or in MSDN. When using the following code, if I try to dispose the message after sending the asynch mail then I get a System.ObjectDisposedException: Cannot access a disposed object. This is when the microsoft example suggests disposing.
I can't dispose the message in the callback because it is out of scope. I have tried using a module level Mail message but get the same results. If I don't dispose the message everything works fine but this is not good practice. Please advice the best place to dispose the mail message.
Public Sub SendEmailWithReport(ByVal v_objEmailAddress As System.Collections.Generic.List(Of String), ByVal v_strSubject As String,
ByVal v_strBody As String, ByVal v_strFileName As String, ByVal v_intContentID As Integer,
ByVal v_strType As String) Implements IMessagingPlatform.SendEmailWithReport
Dim objMessage As New MailMessage
Dim objAttachment As New Attachment(v_strFileName, MediaTypeNames.Application.Pdf)
Try
'configure e-mail addresses and add attachment
With objMessage
For Each strAddress As String In v_objEmailAddress
.To.Add(strAddress)
Next
.Attachments.Add(objAttachment)
End With
SetUpAsynchEmail(objMessage, v_strSubject, v_strBody, v_strFileName, v_intContentID, v_strType)
Catch ex As Exception
Trace.WriteLine(DateTime.Now().ToString("dd/MM/yyyy HH:mm:ss.fff") & " : Failed to setup e-mail with report: " & ex.Message.ToString, "ERR")
Finally
'objMessage.Dispose() *disposing here gives System.ObjectDisposedException: Cannot access a disposed object.**
'objAttachment.Dispose()
End Try
End Sub
Private Sub SetUpAsynchEmail(ByVal v_objMessage As MailMessage, ByVal v_strSubject As String, ByVal v_strBody As String,
ByVal v_strFileName As String, ByVal v_intContentID As Integer, ByVal v_strType As String)
Dim intID As Integer
Try
Dim basicAuthenticationInfo As New System.Net.NetworkCredential(mstrUserName, mstrPassword)
Dim objClient As New SmtpClient()
'configure mail message
With v_objMessage
.IsBodyHtml = True
.Subject = v_strSubject
.Body = v_strBody
If mstrFromEmailName <> "" Then
.From = New MailAddress(mstrFromEmailAddress, mstrFromEmailName)
Else
.From = New MailAddress(mstrFromEmailAddress)
End If
End With
'configure mail client
With objClient
.Host = mstrSMTPHost
.UseDefaultCredentials = False
.Credentials = basicAuthenticationInfo
.EnableSsl = True
.Port = mintSMTPPort
End With
' Set the method that is called back when the send operation ends.
AddHandler objClient.SendCompleted, AddressOf SendCompletedCallback
'Generate a unique message number
intID = mobjContainer.AddUnsentMail(v_intContentID, v_strType, v_strFileName)
If intID > -1 Then
objClient.SendAsync(v_objMessage, intID)
End If
'v_objMessage.Dispose() **disposing here gives System.ObjectDisposedException: Cannot access a disposed object.
Catch ex As Exception
Trace.WriteLine(DateTime.Now().ToString("dd/MM/yyyy HH:mm:ss.fff") & " : Failed to setup e-mail: " & ex.Message.ToString, "ERR")
Finally
End Try
End Sub
Private Sub SendCompletedCallback(ByVal v_objSender As SmtpClient, ByVal e As AsyncCompletedEventArgs)
' Get the unique identifier for this asynchronous operation.
Dim strMessageID As String = CStr(e.UserState)
Try
If e.Cancelled Then
Trace.WriteLine(DateTime.Now().ToString("dd/MM/yyyy HH:mm:ss.fff") & " : E-mail cancelled for message with ID " &
strMessageID, "ERR")
End If
If e.Error IsNot Nothing Then
Trace.WriteLine(DateTime.Now().ToString("dd/MM/yyyy HH:mm:ss.fff") & " : Failed to send e-mail with ID " &
strMessageID & ", " & e.Error.ToString(), "ERR")
'E-mail error - update table
mobjContainer.UpdateUnsentMail(CInt(strMessageID))
Else
'E-mail success - delete record from table
mobjContainer.DeleteUnsentMailItem(CInt(strMessageID))
Trace.WriteLineIf(mobjLogTrace.LogEvents = True And mobjLogTrace.LogDetail >= 4, DateTime.Now().ToString("dd/MM/yyyy HH:mm:ss.fff") &
" : E-mail with ID " & strMessageID & " successfully sent", "EVT")
End If
Catch objException As Exception
Trace.WriteLine(DateTime.Now().ToString("dd/MM/yyyy HH:mm:ss.fff") & " : Failed to send e-mail with ID " &
strMessageID & ", " & objException.ToString(), "ERR")
Finally
v_objSender.Dispose()
End Try
End Sub
If you created a class to hold both intID and your v_objMessage and passed this as the second parameter in your objClient.SendAsync() call you would have access to both the ID and the message in the SendCompletedCallback() sub. You could then call .Dispose on the message in your Finally block.
I have a BackGroundWorker with a For Each loop that is inside of a Try Catch and I need to detect the error and continue the For Each loop whit the next item.
Actually I have a list of data to send to a server trough UDP and wait for an ACK, but if the server didn't answer in 5 seconds the timeout error is cachet and the whole process is aborted.
I need to do something like this
Dim MyData_Array As String()
For Each MyData As String In MyData_Array
MyData_Actual = MyData
' Translate the passed message into ASCII and store it as a Byte array.
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(MyData)
Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)
If data.Length = 67 Then
XMyData += 1
Dim Tx As New UdpClient()
Tx.Connect(Host, Port)
Tx.Client.SendTimeout = 5000
Tx.Client.ReceiveTimeout = 5000
Tx.Send(data, data.Length)
data = Tx.Receive(RemoteIpEndPoint)
Tx.Close()
Else
MyData_ErrorList += MyData & vbCrLf
End If
'Report progress
Porcentaje = (XMyData * 100) / MyData_Array.Count
BackgroundWorker1.ReportProgress(Porcentaje, "Sending MyData " & XMyData.ToString & " de " & MyData_Array.Count.ToString & " : " & MyData)
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
Exit For
End If
Next
End If
Catch ex As TimeoutException
MyData_ErrorList += MyData_Actual & vbCrLf
'**********************************************************
'Here need to delay 100mS and get back to the For Each to process the next item
'**********************************************************
Catch ex As Exception
MyData_List = ex.Message & vbCrLf & "StackTrace: " & ex.StackTrace & vbCrLf & MyData_List
End Try
Put the Try/Catch inside the for loop.
Dim MyData_Array As String()
For Each MyData As String In MyData_Array
Try
MyData_Actual = MyData
' Translate the passed message into ASCII and store it as a Byte array.
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(MyData)
Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)
If data.Length = 67 Then
XMyData += 1
Dim Tx As New UdpClient()
Tx.Connect(Host, Port)
Tx.Client.SendTimeout = 5000
Tx.Client.ReceiveTimeout = 5000
Tx.Send(data, data.Length)
data = Tx.Receive(RemoteIpEndPoint)
Tx.Close()
Else
MyData_ErrorList += MyData & vbCrLf
End If
'Report progress
Porcentaje = (XMyData * 100) / MyData_Array.Count
BackgroundWorker1.ReportProgress(Porcentaje, "Sending MyData " & XMyData.ToString & " de " & MyData_Array.Count.ToString & " : " & MyData)
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
Exit For
End If
Catch ex As TimeoutException
MyData_ErrorList += MyData_Actual & vbCrLf
Catch ex As Exception
MyData_List = ex.Message & vbCrLf & "StackTrace: " & ex.StackTrace & vbCrLf & MyData_List
'If you want to exit the For loop on generic exceptions, uncomment the following line
'Exit For
End Try
Next
You might consider putting the try catch inside the for loop, if the iterative collection is not modified somehow by the error. Then handle the exception and continue the for loop.
How you have your loop and try/catch setup now will cause the entire loop to be broken out of on the timeout exception since the try/catch is placed outside the loop.
The your code would look more like this:
For Each MyData As String In MyData_Array
Try
'Perform code for each loop iteration
Catch ex As TimeoutException
'Handle Exception Here
End Try
Next
I took this code from a website since VS 2010 doesn't support the timeout for the TCP connections:
Private Function ConnectWithTimeout() As Boolean
Dim ar As IAsyncResult = TCPClient.BeginConnect(IPAddress, TCPPort, Nothing, Nothing)
Dim wh As System.Threading.WaitHandle = ar.AsyncWaitHandle
Try
If Not ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2), False) Then
TCPClient.Close()
TCPClient = New System.Net.Sockets.TcpClient
Throw New TimeoutException()
End If
Catch ex As Exception
ThrowError("Timeout on connecting to " & IPAddress & " at port " & TCPPort & ".")
Return False
Finally
wh.Close()
End Try
Return True
End Function
And it works fine, but everytime, it gives me this on the debug output:
"A first chance exception of type 'System.TimeoutException' occurred in"
Even if I'm catching all the exceptions. Is there a way to get rid of this exception message as it is handled?
I've tried this:
Dim connectDone As New System.Threading.AutoResetEvent(False)
TCPClient.BeginConnect(IPAddress, TCPPort, New AsyncCallback(Sub(ar As IAsyncResult)
TCPClient.EndConnect(ar)
connectDone.Set()
End Sub), TCPClient)
'client.BeginConnect("127.0.0.1", 80, new AsyncCallback(delegate( IAsyncResult ar ) { client.EndConnect( ar ); connectDone.Set(); }), client);
If Not connectDone.WaitOne(2000) Then
Debug.WriteLine("TIMEOUT")
Return False
End If
Return True
But it gives me InvalidOperationException on the beginconnect line:
BeginConnect cannot be called while another asynchronous operation is in progress on the same Socket.
Private Function ConnectWithTimeout() As Boolean
Dim ar As IAsyncResult
Dim wh As System.Threading.WaitHandle
Try
ar = TCPClient.BeginConnect(IPAddress, TCPPort, Nothing, Nothing)
wh = ar.AsyncWaitHandle
Cath ex as Exception
'Code to catch exception
End Try
Try
If Not ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2), False) Then
TCPClient.Close()
TCPClient = New System.Net.Sockets.TcpClient
Throw New TimeoutException()
End If
Catch ex As Exception
ThrowError("Timeout on connecting to " & IPAddress & " at port " & TCPPort & ".")
Return False
Finally
wh.Close()
End Try
Return True
End Function