I have a one threaded application. Its supposed to connect to a local MSMQ queue, and once a message is received it should process it before continuing to listen for additional messages. The messages contain data that is supposed to be inserted into a database table. But before inserting the data, it does a query to see if the item already exists. However, I am thinking that by creating a handler for ReceiveCompleted, that if more than one messages is in the queue that multiple threads are being spawned off. Is that what will happen? If it is then its possible that duplicate data could be in both messages, and my sql query may not see any duplication because the 2nd thread is still working and has not yet inserted its data into the database table.
Dim objQueue As New MessageQueue(ConfigurationManager.AppSettings("myQueuePath"))
AddHandler objQueue.ReceiveCompleted, AddressOf QueueReceived
objQueue.BeginReceive()
Private Sub QueueReceived(source As Object, asyncResult As ReceiveCompletedEventArgs)
Dim mq = DirectCast(source, MessageQueue)
Dim objMessage As Message = Nothing
Try
mq.Formatter = New XmlMessageFormatter(New [String]() {"System.String,mscorlib"})
objMessage = mq.EndReceive(asyncResult.AsyncResult)
Dim strMessage As String = objMessage.Body.ToString()
'Call routine to read data, check for suplicates and then insert into database
ProcessBXRS(objMessage)
Catch ex As Exception
'Do some exception handling
End Try
'Listen for next message
mq.BeginReceive()
End Sub
I guess I have to call BeginReceive() again.
Related
I have a service that watches 2 email inboxes. One thread is created for each inbox. The new messages are read and marked as Read on startup, then the NewMail event handler handles all new mail after that.
We have been using EWS version 14. We had no issues retrieving emails.
After we moved the emails to Office 365, the problems started.
On startup, the retrieval and handling of existing new messages is still working fine.
After startup, when the NewMail event handler is triggered, the bind/load method times out, regardless of what we set the Timeout property to.
We tried to switch to the newest EWS version (15.0).
With the new version, the startup handling still works fine.
However, trying to bind one email in the NewMail event handler makes no error, but makes the inbox thread quit.
When there is a new email message in both inboxes, the entire service freezes on the Bind line (i let it sit for 40 minutes before having to kill the service).
We tried both EWS versions with the following, with no success:
The below code is used in the NewEmail event handler AND the startup processing of existing new messages. Why would the same code have issues in one place and not the other? How do i fix this?
I have also tried to use EmailMessage.Bind using the NotificationEventArgs object, but i have the same issues.
We tried a SyncLock to get around the lock up and/or timeout, but that did not help.
Thanks!
Private Sub HaveMail(ByVal sender As Object, ByVal e As Microsoft.Exchange.WebServices.Data.NotificationEventArgs)
Dim error_occured As Boolean = False
Try
Try
SyncLock lock
Logger.LogDebug("Just entered the Locked state of the HaveMail event")
Dim ir As FindItemsResults(Of Item) = service.FindItems(WellKnownFolderName.Inbox, New SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, False), New ItemView(20))
Do While ir.Items.Count > 0
For Each i As EmailMessage In ir
Try
Logger.LogDebug("About to load a newly received email message")
i.Load(PropertySet.FirstClassProperties)
Catch ex As Exception
Throw New Exception("Error while loading an email message: " & ex.Message)
End Try
Dim rm As New ReceivedMessage
rm.ReceivedDateTime = i.DateTimeReceived
rm.ToAddress = i.DisplayTo
rm.Subject = i.Subject
rm.Body = i.Body
rm.FromAddress = i.From.Address
Logger.LogDebug("Just loaded a newly received email message from " & rm.FromAddress)
Dim rme As New ReceivedMessageEvent
rme.msg = rm
RaiseEvent GotMail(Me, rme)
Logger.LogDebug("Just processed a newly received email message from " & rm.FromAddress)
i.IsRead = True
i.Update(ConflictResolutionMode.AlwaysOverwrite)
Next
ir = service.FindItems(WellKnownFolderName.Inbox, New SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, False), New ItemView(20))
Loop
End SyncLock
Generally speaking, it's not a good practice to do much of anything from within the actual event handler. So Update, FindItems, and Bind would all make a call back to EWS from within your handler, and that is not good. The ExchangeService object is also not thread safe. How did you get away with it before O365? I have no answer other than just lucky.
Thanks to an answer on my posting on MSN, I was able to fix the problem.
I needed to raise the DefaultConnectionLimit to 100. Apparently, it defaults to 2, which was not enough.
I have a named pipes server running on a workstation. When the server receives a message I am able to process it. The problem is several messages can be sent at the same time. The server processes the first message but the remaining messages are lost. Not sure how to listen for multiple messages. I cannot batch the messages into one message as I need to have the server respond to each and every message separately. Does anyone know how I can accomplish this. My server code is below which is running in a thread.
Dim Pipe As New Pipes.NamedPipeServerStream("bellhop", Pipes.PipeDirection.InOut, -1, Pipes.PipeTransmissionMode.Message, Pipes.PipeOptions.Asynchronous)
While BellhopExiting = False
Pipe.WaitForConnection()
Dim Reader As New StreamReader(Pipe)
Dim XML As String = Reader.ReadLine
If XML IsNot Nothing Then
Dim Writer As New StreamWriter(Pipe)
Writer.AutoFlush = True
Try
ParseXML(XML)
'Send a success acknowledgement back to the sender.
Writer.WriteLine("Message Delivered")
Catch ex As Exception
'Send a failed acknowledgement back to the sender.
Writer.WriteLine("Failed->Bellhop->WaitForConnection->Computer: " & ComputerName & " Error: " & ex.Message)
End Try
End If
Pipe.Disconnect()
End While
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.
I have a VB.net app with a DataGridView displaying a list of jobs, retrieved from a SQL query into a DataTable, then a DataView and finally a BindingSource for the DataGridView.DataSource. I have recently added SqlNotificationRequest functionality to the setup so user A is immediately updated when user B performs an action on a job in the list.
I used this MSDN article (http://msdn.microsoft.com/en-US/library/3ht3391b(v=vs.80).aspx) as the basis for my development and it works ok. The problem comes when the user wants to change the parameters of the SQL query which displays the jobs, for example the date displayed. Currently I am creating a new SqlCommand with new Notification but after the user has changed the date a few times (say 30), but no data changes, when the notification timeout occurs I receive the above error when the callback handler tried to EndExecuteReader. My callback handler is below:
Private Sub OnSalesReaderComplete(ByVal asynResult As IAsyncResult)
' You may not interact with the form and its contents
' from a different thread, and this callback procedure
' is all but guaranteed to be running from a different thread
' than the form. Therefore you cannot simply call code that
' updates the UI.
' Instead, you must call the procedure from the form's thread.
' This code will use recursion to switch from the thread pool
' to the UI thread.
If Me.InvokeRequired Then
myStatus.addHistory("OnSalesReaderComplete - Background", "Sub")
Dim switchThreads As New AsyncCallback(AddressOf Me.OnSalesReaderComplete)
Dim args() As Object = {asynResult}
Me.BeginInvoke(switchThreads, args)
Exit Sub
End If
' At this point, this code will run on the UI thread.
Try
myStatus.addHistory("OnSalesReaderComplete - UI", "Sub")
Dim sourceText, rSalesId As String
waitInProgressSales = False
Trace.WriteLine(String.Format("Sales:asynResult.IsCompleted1: {0}", asynResult.IsCompleted.ToString), "SqlNotificationRequest")
Trace.WriteLine(String.Format("Sales:asynResult.CompletedSynchronously: {0}", asynResult.CompletedSynchronously.ToString), "SqlNotificationRequest")
Dim reader As SqlDataReader = DirectCast(asynResult.AsyncState, SqlCommand).EndExecuteReader(asynResult)
Trace.WriteLine(String.Format("Sales:asynResult.IsCompleted2: {0}", asynResult.IsCompleted.ToString), "SqlNotificationRequest")
Do While reader.Read
' Empty queue of messages.
' Application logic could parse
' the queue data to determine why things.
'For i As Integer = 0 To reader.FieldCount - 1
' 'Debug.WriteLine(reader(i).ToString())
' Console.WriteLine(reader(i).ToString)
'Next
Dim bytesQN As SqlBytes = reader.GetSqlBytes(reader.GetOrdinal("message_body"))
Dim rdrXml As XmlReader = New XmlTextReader(bytesQN.Stream)
Do While rdrXml.Read
Select Case rdrXml.NodeType
Case XmlNodeType.Element
Select Case rdrXml.LocalName
Case "QueryNotification"
sourceText = rdrXml.GetAttribute("source")
Case "Message"
rSalesId = rdrXml.ReadElementContentAsString
End Select
End Select
Loop
Loop
reader.Close()
' The user can decide to request
' a new notification by
' checking the check box on the form.
' However, if the user has requested to
' exit, we need to do that instead.
If exitRequestedSales Then
'Me.Close()
commandSales.Notification = Nothing
Else
Select Case sourceText.ToLower
Case "data"
Trace.WriteLine(String.Format("SalesId: {0}, data notification", rSalesId), "SqlNotificationRequest")
Call GetSalesData(True, action.REATTACH)
Case "timeout"
'check timeout is for this user and relates to current wait thread
Select Case salesId = rSalesId
Case True
Trace.WriteLine(String.Format("SalesId: {0}, timeout - current", rSalesId), "SqlNotificationRequest")
Call GetSalesData(True, False)
Case False
Trace.WriteLine(String.Format("SalesId: {0}, timeout - old", rSalesId), "SqlNotificationRequest")
Me.ListenSales()
End Select
End Select
End If
Catch ex As Exception
Call errorHandling(ex, "OnSalesReaderComplete", "Sub")
End Try
End Sub
The problem seems to be where I am only refreshing the data and renewing the notification request (using GetSalesData) when either the notification is due to an update ("data") or the timeout is for the current request. On other notifications, the application calls Me.ListenSales which creates a SQL command "WAITFOR (RECEIVE * FROM [QueueMessage])" and starts the callback listener as per the MSDN article. If I remove the Me.ListenSales line, once a notification is received which is not due to data or the timeout of the current query, the application stops listening for notifications.
I have also posted the same question on MSDN forums (http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/0f7a636d-0c9b-4b39-b341-6becf13873dc) as I have tried other resolutions without success so require some advice on whether this is possible and if so how.
I'm not even sure I understand this situation enough to come up with a proper title. I come from a modest understanding of VB6 and having to climb a steep learning curve for VB 2010.
I am trying to create a multi-client server program that will communicate with my Enterprise iPhone app. I found a relatively simple example to build upon here: http://www.strokenine.com/blog/?p=218. I have been able to modify the code enough to make it work with my app, but with one glitch: I can't get access to the controls on the form to add items, even though the method is invoked within the form's class. (I tried this on the original code too, and it does the same thing. I don't know how the author managed to get it to work.)
Here's the code segment in question:
Public Class Server 'The form with the controls is on/in this class.
Dim clients As New Hashtable 'new database (hashtable) to hold the clients
Sub recieved(ByVal msg As String, ByVal client As ConnectedClient)
Dim message() As String = msg.Split("|") 'make an array with elements of the message recieved
Select Case message(0) 'process by the first element in the array
Case "CHAT" 'if it's CHAT
TextBox3.Text &= client.name & " says: " & " " & message(1) & vbNewLine 'add the message to the chatbox
sendallbutone(message(1), client.name) 'this will update all clients with the new message
' and it will not send the message to the client it recieved it from :)
Case "LOGIN" 'A client has connected
clients.Add(client, client.name) 'add the client to our database (a hashtable)
ListBox1.Items.Add(client.name) 'add the client to the listbox to display the new user
End Select
End Sub
Under Case "LOGIN" the code tries to add the login ID to the listbox. It throws an exception: "A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll" The listbox (all controls, for that matter) is in the same class, Server.vb and Server.vb [Design].
The data comes in from another class that is created whenever a client logs on, which raises the event that switches back to the Server class:
Public Class ConnectedClient
Public Event gotmessage(ByVal message As String, ByVal client As ConnectedClient) 'this is raised when we get a message from the client
Public Event disconnected(ByVal client As ConnectedClient) 'this is raised when we get the client disconnects
Sub read(ByVal ar As IAsyncResult) 'this will process all messages being recieved
Try
Dim sr As New StreamReader(cli.GetStream) 'initialize a new streamreader which will read from the client's stream
Dim msg As String = sr.ReadLine() 'create a new variable which will be used to hold the message being read
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been recieved. Me is passed as an argument which represents
' the current client which it has recieved the message from to perform any client specific
' tasks if needed
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'continue reading from the stream
Catch ex As Exception
Try 'if an error occurs in the reading purpose, we will try to read again to see if we still can read
Dim sr As New StreamReader(cli.GetStream) 'initialize a new streamreader which will read from the client's stream
Dim msg As String = sr.ReadLine() 'create a new variable which will be used to hold the message being read
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been recieved. Me is passed as an argument which represents
' the current client which it has recieved the message from to perform any client specific
' tasks if needed
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'continue reading from the stream
Catch ' IF WE STILL CANNOT READ
RaiseEvent disconnected(Me) 'WE CAN ASSUME THE CLIENT HAS DISCONNECTED
End Try
End Try
End Sub
I hope I am making sense with all this. It all seems to bounce back and forth, it seems so convoluted.
I've tried using Me.listbox1 and Server.listbox1 and several other similar structures, but to no avail.
I'm reading a lot about Invoke and Delegates, but would that be necessary if the method and the control are in the same class? Or do I have a fundamental misperception of what a class is?
Many thanks for any help I can get.
Private Delegate Sub UpdateListDelegate(byval itemName as string)
Private Sub UpdateList(byval itemName as string)
If Me.InvokeRequired Then
Me.Invoke(New UpdateListDelegate(AddressOf UpdateList), itemName)
Else
' UpdateList
' add list add code
ListBox1.Items.Add(itemName)
End If
End Sub
Add above, then replace:
ListBox1.Items.Add(client.name)
to
UpdateList(client.name)
Does it work? check the syntax, may have typo as I type it.