Timeouts and Freezing in EWS with Office 365 - vb.net

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.

Related

MSMQ FIFO/Synchronous Processing

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.

"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.

How do I solve 'System.OutOfMemoryException'

I have a Windows Service application. It is a very busy application. It is supposed to run continuously looking for things to do. After it runs for a while I get
Exception of type 'System.OutOfMemoryException' was thrown.
It can happen at different times but usually a this paragraph:
Private Shared Function GetUnprocessedQueue() As Boolean
Try
Dim l_svcOOA As New svcITGOOA.IsvcITGOOAClient(OOAProcessing.cGlobals.EndPoint_ITGOOA)
Dim l_iFilter As New svcITGOOA.clsFilter
With l_svcOOA
With l_iFilter
.FilingType = OOAProcessing.cGlobals.FilingType
End With
m_ReturnClass = .itgWcfOOA(1, cGlobals.DatabaseIndicator, svcITGOOA.eOOAAction.GetUnprocessedQueue, l_iFilter, 71)
Return CompletedGetUnprocessedQueue(m_ReturnClass)
End With
Catch ex As Exception
ExceptionHandling(ex, "GetUnprocessedQueue " & m_Application)
Return False
End Try
End Function
This is using a wcf service to read a queue. It reads the queue every two minutes to see if new records have been added to it.
Please help me solve this. I don’t know where to start.
The OutOfMemoryException exception occurs when the GC has completed a cycle of collection but the memory is not available even after that. I couldn't make out what the above code snippet does, but I think using Weak References for objects could be useful.
I had a timer that was generated within the same paragraph that I was setting
For example
m_svcTimer = New Timers.Timer With {.Interval = m_Interval, .Enabled = True}
AddHandler m_svcTimer.Elapsed, AddressOf StartTheQueueIfTime
m_svcTimer.Enabled = True
m_svcTimer.Start()
was within the paragraph StartTheQueueIfTime. I thought this would be a way to change the time interval. Instead it kept creating new events. Finally too many caused my crash.
Bob

vb.net: listbox.items.add() throws exception in same class

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.