Dynamically creating multiple background workers and passing them arguments - vb.net

I've written an app that basically does constant pings to a list of hosts and logs the results.
I have a function...
Public Function doping(ByRef host As String)
Dim Result As Net.NetworkInformation.PingReply
Dim SendPing As New Net.NetworkInformation.Ping
Dim ResponseTime As Long
Dim timestamp As String = System.DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss")
Try
Result = SendPing.Send(host, 300)
ResponseTime = Result.RoundtripTime
If Result.Status = Net.NetworkInformation.IPStatus.Success Then
DynaLogging(timestamp & " - Reply from " & host & ": bytes=32 time=" & ResponseTime.ToString & " TTL=??", host & ".log")
TextBox2.Text = timestamp & " - Reply from " & host & " : time =" & ResponseTime.ToString & br & TextBox2.Text
Else
DynaLogging(timestamp & " - No reply received from " & host, host & ".log")
TextBox2.Text = timestamp & " - No reply received from " & host & br & TextBox2.Text
End If
Catch ex As Exception
End Try
End Function
And I've got a timer, which currently fires off the following in a background worker...
On Error Resume Next
For Each hostyhost As String In ListBox1.Items
doping(hostyhost)
Next
This works a treat until one of the hosts in the list is not responding, then the backgroundworker waits because it can only process one ping at a time and so if one host is delayed, the remaining hosts have to wait before they are checked and the whole process slows down.
I could do with somehow dynamically creating multiple background workers at runtime but I do not know how to create a background worker dynamically which can be passed an argument.
I looked at this post about creating bgw's at runtime, but have no idea how to deploy this for what I need.
Can anyone point me in the right direction?

Why not a Parallel ForEach?
Dim Items As List(Of String) = New List(Of String)
For Each item As String In ListBox1.Items
Items.Add(item.ToString())
Next
Parallel.ForEach(Items, Sub(hostyhost)
doping(hostyhost)
End Sub)
It's included in the .NET Framework 4.0 under the System.Threading namespace and will take care of almost everything, without writing a million lines of code.

Related

stop windows service on an event

I need to stop the service on an event .where i am sending file through ftp and ftp response is generating in text file.
So i am checking the response in text file ,if failoure message is there then i need to stop the service.But because this one is not an exception so i am not able to call OnStart method where i can stop the service.
How to stop the service in class?
Dim text As String = "Error: Could not open connection"
Dim lines() As String = Filter(System.IO.File.ReadAllLines(SFtpLogFullPath), text)
If UBound(lines) = -1 Then
'MsgBox("not found")
Else
'MsgBox("found")
Dim UpdFailFTPStatus As New AseCommand("update tb_kamp_filesprocess set FileFTPStatus = '" & "" & "' where FILENAME = '" & fileName & "' ", _SQLConnection)
recordsAffected = UpdFailFTPStatus.ExecuteNonQuery()
ExecuteSP("ml_test_kamp")
writelog("Error occured during SFTP ")
'Need to stop the service here
Exit Sub
End If

Writing To Text File, File In Use By Another Process, Multithreaded Application .NET

Afternoon,
I have a program whereby I really need to be keeping a log of some kind to ascertain what the program is doing. Essentially the software monitors for a window on the desktop to live pause a call recording on our Call Recorder Server.
Lets on argument say a Call Recording itself was pulled up by a monitoring agent and they state that a certain sensitive part of the conversation has been recorded when really it should have been silenced, if they were to say the agent hadn't done their job and clicked the pause recording button OR the onfocus action hadn't occurred I would have a situation whereby I would need to prove what the software was doing at the same.
I decided that I would write the actions of the software to a .txt file stored in the users app data.
This works for the most part, however every now and then even though the .txt is never accessed by any other program I get 'This file is in use by another process'.
This application is multithreaded and does make very frequent calls to write to the log, I am using the below code:
Private Sub WriteToLog(ByVal strSubTitle As String, ByVal strLogInfo As String)
Try
If My.Computer.FileSystem.FileExists(strLogFilePath) = True Then
'Delete yesterdays log file
Dim strFileDate As Date = File.GetCreationTime(strLogFilePath)
strFileDate = FormatDateTime(strFileDate, DateFormat.ShortDate)
'If strFileDate < Date.Today Then
' My.Computer.FileSystem.DeleteFile(strLogFilePath)
'End If
Using outFile As IO.StreamWriter = My.Computer.FileSystem.OpenTextFileWriter(strLogFilePath, True)
outFile.WriteLine("" & Date.Today & "," & Date.Now.ToLongTimeString & ", " & strUsername & ", " & strSubTitle & ", " & Replace(strLogInfo, ",", "|") & "")
outFile.Close()
End Using
''CSV File
'outFile.WriteLine("" & Date.Today & "," & Date.Now.ToLongTimeString & ", " & strUsername & ", " & strSubTitle & ", " & Replace(strLogInfo, ",", "|") & "")
'outFile.Close()
Else
Using outFile As IO.StreamWriter = My.Computer.FileSystem.OpenTextFileWriter(strLogFilePath, False)
outFile.WriteLine("" & Date.Today & "," & Date.Now.ToLongTimeString & ", " & strUsername & ", " & strSubTitle & ", " & Replace(strLogInfo, ",", "|") & "")
outFile.Close()
End Using
'CSV File
'outFile.WriteLine("Date, Time, Username, Sub(Process), Information")
'outFile.WriteLine("" & Date.Today & "," & Date.Now.ToLongTimeString & ", " & strUsername & ", " & strSubTitle & ", " & Replace(strLogInfo, ",", "|") & "")
'outFile.Close()
End If
Catch ex As Exception
CreateErrorFile(ex.Message, ex.StackTrace, "Log Write Failure!")
End Try
End Sub
Is there any advice/pointers someone could state as to why this would be saying another process is using the file.
I'm guessing the situation would occur when two separate threads try to do the 'WriteToLog' Sub while one or the other is writing to the file.
Am I on the right tracks? If so how could I rectify this?
Cheers,
James
You will either want to make it so that only one thread has the ability to write to the log file by using the Invoke method from the secondary thread(s) to call the write functionality on the main thread, or you can use one of .NET's various synchronization mechanisms.
Here is a simple example of the first approach:
Private Sub BackgroundMethod()
'do stuff
Me.Invoke(New Action(Of String)(AddressOf WriteToLog), "write a line blah blah")
'do more stuff
End Sub
Private Sub WriteToLog(valueToWrite As String)
System.IO.File.AppendAllLines(MyLogFilePath, {valueToWrite})
End Sub
Here's an example using a SyncLock block:
Private lock As New Object()
Private Sub BackgroundMethod()
'do stuff
WriteToLog("write a line blah blah")
'do more stuff
End Sub
Private Sub WriteToLog(valueToWrite As String)
SyncLock (lock)
System.IO.File.AppendAllLines(MyLogFilePath, {valueToWrite})
End SyncLock
End Sub
MSDN has good information on synchronization mechanisms: http://msdn.microsoft.com/en-us/library/ms228964%28v=vs.110%29.aspx
I would use a global Queue where new entries get added to and if the log writer is not busy then start it to write down all available lines.
sth like:
Private LogList As New Queue(Of String)
Private WriterBusy As Boolean = False
Private Sub WriteToLog(ByVal strSubTitle As String, ByVal strLogInfo As String)
LogList.Enqueue("" & Date.Today & "," & Date.Now.ToLongTimeString & ", " & strUsername & ", " & strSubTitle & ", " & Replace(strLogInfo, ",", "|") & "")
If WriterBusy = True Then Exit Sub
WriterBusy = True
Try
If My.Computer.FileSystem.FileExists(strLogFilePath) = True Then
...
Using outFile As IO.StreamWriter = My.Computer.FileSystem.OpenTextFileWriter(strLogFilePath, True)
While LogList.Count > 0
outFile.WriteLine(LogList.Dequeue)
End While
outFile.Close()
End Using
...
End Try
WriterBusy = False
End Sub

Response.Write in a Shared function

Is it possible to open a new window from a shared function? There is a compile time error on the line that starts: Response.Write:
<System.Web.Services.WebMethod()> _
Public Shared Function UpdateTimeBasedDisposal(ByVal usn As String, ByVal strCon As String, ByVal decision As String, ByVal review As String) As String
Dim boolDecision As Boolean = CType(decision, Boolean)
Dim objNominal As New clsPrimaryNominal(strCon)
Dim strUpdateTimeBasedDisposal As String = ""
Dim objReview As New clsReviews(ConfigurationManager.ConnectionStrings("GeniedbConnection").ConnectionString), tyReview As New typeReview, intTotal As Integer, intDisposalTotal As Integer, intType As Integer
If boolDecision Then
If objNominal.MakeTimeBased(CInt(usn)) < 1 Then
strUpdateTimeBasedDisposal = "THERE WAS A PROBLEM MAKING THE NOMINAL RECORD FOR " & usn & " TIME BASED DISPOSAL." & vbCrLf
Else
strUpdateTimeBasedDisposal = "The Primary Nominal was successfully put into time based disposal"
End If
Else
If objNominal.MakeNotTimeBased(CInt(usn)) < 1 Then
strUpdateTimeBasedDisposal = "THERE WAS A PROBLEM MAKING THE NOMINAL RECORD FOR " & usn & " NOT TIME BASED DISPOSAL." & vbCrLf
Else
strUpdateTimeBasedDisposal = "The Primary Nominal was successfully taken out of time based disposal"
' next thing to do is create all the disposal records
'CreateDisposals()
intType = objReview.ReviewType(CLng(review), intTotal, intDisposalTotal)
Response.Write("<script>window.open('frmNRAC.aspx?USN=" & CStr(Session("PNUSN")) & "&Review=" & CStr(Session("Review")) & "&Total=" & intTotal & "&Disposals=" & intDisposalTotal & "','_blank')</script>")
End If
End If
Return strUpdateTimeBasedDisposal
End Function
This is server-side code. Server-side code can never directly open a new window. All it can do is create an http response that causes some javascript to open a new window. WebMethods also can't call the javascript on their own directly. You need code at the call site for the webmethod to invoke your javascript based on the result of the method.
Additionally: beware Shared methods in ASP.Net in the first place. They share data at the application domain level, and in ASP.Net, all the users of your site are in the same application domain.

List that this enumerator is bound to has been modified

I have this bit of code here, and at the next statement it's giving me an error saying:
List that this enumerator is bound to has been modified. An enumerator can only be used if the list does not change.
I really don't know how to further explain this issue, but if you need me to I can try.
For Each itemChecked In storedAuthorsListbox.CheckedItems
Dim selectedAuthor As String = storedAuthorsListbox.SelectedItem.ToString()
Dim authorFile As String = "Authors\" & itemChecked.ToString()
Dim document As XmlReader = New XmlTextReader(authorFile)
metaInfo &= "[Author]" & vbNewLine
While (document.Read())
Dim type = document.NodeType
If (type = XmlNodeType.Element) Then
If (document.Name = "Name") Then
metaInfo &= "Name=" & document.ReadInnerXml.ToString() & vbNewLine
ElseIf (document.Name = "Website") Then
metaInfo &= "Website=" & document.ReadInnerXml.ToString() & vbNewLine
ElseIf (document.Name = "Notes") Then
metaInfo &= "Notes=" & document.ReadInnerXml.ToString() & vbNewLine
End If
End If
End While
document.Close()
Next
Some code somewhere is changing storedAuthorsListbox while you are iterating it. That code is not visible in the snippet. Do make sure that the posted code is not running in a worker thread, that is not legal. It certainly quacks like the kind of code you'd run in a worker.
The generic solution is to make a copy of the items and work from that copy instead of the control:
Dim copy = storedAuthorsListBox.SelectedItems.OfType(Of String)().ToList()
For Each itemchecked In copy
'' etc..
Next
If this runs in a worker thread then pass the copy to the worker.

Is it safe to call SmtpClient.Dispose() in .NET?

I have a scenario where I need to send 100 emails in one shot (using a loop), but also I am not allowed to send 1 email per SMTP session.
Right now all 100 emails are sharing same SMTP session.
I was thinking that calling SmtpClient.Dispose() will take care of what I need. Please correct me if I am wrong.
So, basically 3 questions:
Will SmtpClient.Dispose() take care of what I need?
If Yes, is it safe to Dispose() SmtpClient without affecting other services on the
server?
If No, What would be the right approach to achieve what I
want?
Sample Code:
Private Shared Sub SendMail(ByVal MailServer As SmtpClient, ByVal body As String, ByVal Subject As String, ByVal FromEmail As String, _
ByVal ToEmailList As String, Optional ByVal AttFile As Attachment = Nothing)
Dim message As New MailMessage
Try
message.From = New MailAddress(FromEmail)
message.Subject = Subject
message.IsBodyHtml = False
message.Body = body
message.Priority = MailPriority.High
If Not AttFile Is Nothing Then
message.Attachments.Add(AttFile)
Else
message.Attachments.Add(AttFile)
End If
MailServer.Send(message)
Catch ex As Exception
Throw New ApplicationException("SERVICE1.SendMail ERROR -- Error sending email [ERROR]:[" & ex.Message.ToString & "] " & vbCrLf & "To:" & ToEmailList & vbCrLf & "From:" & FromEmail & vbCrLf & "Subject: " & Subject & vbCrLf & "Body: " & body)
End Try
message.Dispose()
End Sub
And this is how the method is being executed:
For Each Item In ItemListCollection
m_MailServer = New SmtpClient(MailServerName)
MailServer.Credentials = New System.Net.NetworkCredential(MailServerUserName, MailServerPassword)
SendMail(WeeklyMailServer, msgBody, msgSubject, MsgFromEmail, "xyz#abc.com", rptAttachment)
Next
You could wrap it in a using statement and ensure that it is disposed when execution leaves the block. And you can call Send multiple times in a loop using the same SmtpClient.
Using client = New SmtpClient()
For i As Integer = 0 To 99
Dim message = New MailMessage()
'initialization of whatever is needed
' message creation
client.Send(message)
Next
End Using
Inside execution loop, you can enclose the code in a Using block. This will use a separate smtpclient for each email and will dispose / close it properly.
For Each Item In ItemListCollection
using m_MailServer as New SmtpClient(MailServerName)
MailServer.Credentials = New System.Net.NetworkCredential(MailServerUserName, MailServerPassword)
SendMail(WeeklyMailServer, msgBody, msgSubject, MsgFromEmail, "xyz#abc.com", rptAttachment)
end using
Next