473,732 Members | 2,205 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

How to have multiple worker threads submit to one final processing queue? - HELP

Hello,

I have a multithreaded windows NT service application (vb.net 2003) that I
am working on (my first one), which reads a message queue and creates
multiple threads to perform the processing for long running reports. When
the processing is complete it uses crystal reports to load a template file,
populate it, and then export it to a PDF.

It works fine so far....

Now, since few reports are run - but multiple could be submitted at the same
time, I would like to keep the longer processing multithreaded (i.e.
function ReloadReportDat a() in the processing module below), but then single
thread the crystal report creation/pdf export and e-mailing of the PDF, so
that additional crystal report licenses will not be required (these are very
quick once the processing has been completed). Can someone help me figure
out the best way to do this? From what I can gather in reading various
posts I believe that I would create a QUEUE (note, I don't think is the same
thing as a message queue) and then have a separate thread that is just
pulling messages off of this, and then processing. Once the processing is
done, check for another entry in the QUEUE... Is this correct? But I
haven't seen any good examples of how to do that, and how to wait for the
message.

Below you will find my current source code.

I wouldn't mind additional comments on the techniques that I finally chose
for the threading. Is this all ok? Are there better ways to do this?

Thanks in advance for any assistance!

Jim

=============== =============== =============== =============== =============== =
=============== =============
the following is in the start up of the windows service
=============== =============== =============== =============== =============== =
=============== =============
Private myThreadPool As ThreadPool()
Private oThread(1) As Thread

Protected Overrides Sub OnStart(ByVal args() As String)
' Write a message to the log
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ", "Serv
ice started at : " & FormatDateTime( Now(), DateFormat.Long Time),
Diagnostics.Eve ntLogEntryType. Information, 1)

Dim i As Integer 'Thread count
Dim objMQListen As MQListen

' Declare a worker thread
Dim objThreadStart As ThreadStart

'declare the Class that will run our threads
objMQListen = New MQListen

' Create a ThreadStart object, passing the address of
objMQListener.L isten
' then set the reference and start the main MQListener thread
objThreadStart = New ThreadStart(Add ressOf objMQListen.Lis ten)
oThread(0) = New Thread(objThrea dStart)
oThread(0).Star t()
End Sub

=============== =============== =============== =============== =============== =
=============== =============
the following is the Message Queue Listener Class
=============== =============== =============== =============== =============== =
=============== =============

Imports System.Messagin g
Imports System.Threadin g

Public Class MQListen
Private configurationAp pSettings As _
System.Configur ation.AppSettin gsReader = New _
System.Configur ation.AppSettin gsReader

'constructor accepts the necessary queue information
Sub MQListen(ByVal MachineName As String, ByVal QueueName As String)
End Sub

'One and only method that each thread uses to
Sub Listen()
Dim oThread As Thread
Dim objThreadStart As ThreadStart

'Create a MessageQueue object
Dim objMQ As System.Messagin g.MessageQueue
Try
objMQ = New
System.Messagin g.MessageQueue( CType(configura tionAppSettings .GetValue("Sell a
rs.MessageQueue ", GetType(System. String)), String))
Catch
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error connecting to MessageQueue: " & Err.Description ,
Diagnostics.Eve ntLogEntryType. Error)
Debug.WriteLine (Err.Descriptio n)
End Try
Dim myMessageBody As New MQPassedData
Dim TargetTypes(0) As System.Type
TargetTypes(0) = myMessageBody.G etType
objMQ.Formatter = New XmlMessageForma tter(TargetType s)
myMessageBody = Nothing

'Create a Message object
Dim objMsg As Message

Try
'repeat until Interrupt received
While True
Try
'sleep in order to catch the interrupt if it has been
thrown
'Interrupt will only be processed by a thread that is in
a
'wait, sleep or join state
Thread.CurrentT hread.Sleep(100 )

'Set the Message object equal to the result from the
receive function
'there are 2 implementations of Receive. The one I use
requires a
'TimeSpan object which specifies the timeout period.
There is also an
'implementation of Receive which requires nothing and
will wait indefinitely
'for a message to arrive on a queue
'Timespan(?, hours, minutes, seconds)
Dim newMessageBody As New MQPassedData
objMsg = objMQ.Receive(N ew TimeSpan(0, 0, 0, 1))
Try
newMessageBody = objMsg.Body
Catch emsg As Exception

System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ", "Msg received
error: " & emsg.Message, Diagnostics.Eve ntLogEntryType. Information)
' Create a ThreadStart object, passing the address of objMQListener.L isten
End Try

' Set the passed data in, and place it in a new
ThreadPool element
' The treadpool takes care of managing all the thread
issues in a very
' simple way.
Dim processingutili ties As New SDRAProcessing
Dim passData As New MQPassedData
passData = newMessageBody
ThreadPool.Queu eUserWorkItem(N ew WaitCallback(Ad dressOf
processingutili ties.ProcessMes sage), passData)

' Free up memory held during processing
newMessageBody = Nothing
Catch e As ThreadInterrupt edException
'catch the ThreadInterrupt from the main thread and exit
' Console.WriteLi ne("Exiting Thread")
Exit While
Catch excp As Exception
'Catch any exceptions thrown in receive
'MsgBox("No message received in 10 seconds")
'Console.WriteL ine(excp.Messag e)
End Try

End While

Catch e As ThreadInterrupt edException
'catch the ThreadInterrupt from the main thread and exit
'Console.WriteL ine("Exiting Thread")

End Try

'exit thread

End Sub

End Class

=============== =============== =============== =============== =============== =
=============== =============
the following is my main processing class
=============== =============== =============== =============== =============== =
=============== =============

Imports System.Configur ation
Imports System.Data
Imports System.IO
Imports System.Messagin g
Imports System.Threadin g
Imports System.Web.Mail
Imports CrystalDecision s.CrystalReport s.Engine
Imports CrystalDecision s.Shared

' This class handles the processing for each Sales Date Range Analysis
request
' that is received from the queue
Public Class SDRAProcessing
Private configurationAp pSettings As _
System.Configur ation.AppSettin gsReader = New _
System.Configur ation.AppSettin gsReader

' Declare local variables to store login information for the SQL Server
' this information is read in from the configuration file which resides
in
' the same directory as the service's executable module.
Private mvarDatabaseNam e As String
Private mvarServerName As String
Private mvaruserName As String
Private mvarPassword As String

' Local variables to store various parameters read in from the
configuration file
' this information is read in from the configuration file which resides
in
' the same directory as the service's executable module.
Private mvarReport As String
Private mvarCrystalName As String
Private mvarTempFileDir As String
Private mvarMailTo As String
Private mvarMailFrom As String
Private mvarMailServer As String
Private mvarWebSite As String
Private mvarStyleSheet As String
Private mvarPDFViewLoca tion As String

' Instantiate an object containing the data passed from the web page via
the message queue
Public passData As New MQPassedData

' Local ENUMERATIONS for the EVENT ID used when writing to the Windows
Event Log
Private Enum SDRAEvent As Integer
ServiceStart = 1
ServiceStop = 2
ProcessStart = 3
ProcessStop = 4
ReloadData = 100
DeleteData = 101
ReadConfig = 200
OpenConnection = 201
CloseConnection = 202
CrystalFile = 300
CrystalLoad = 301
CrystalExport = 302
MailParamters = 400
SendMail = 401
End Enum

' This routine is ONLY called when a valid sales date range analysis
request has
' been received. Then
' 1) The requested data is loaded into a temporary database (via the
' ReloadReportDat a routine) off of which we can perform various
reporting tasks
' 2) A PDF file containing the report is produced using interaction
with Crystal Reports.
' 3) The PDF is e-mail to the user that submitted the report
request.
'
Public Sub ProcessMessage( ByVal passedinData As Object)

' Reference the state object passed in via the ThreadPool call to
the procedure.
' this contains the data as it was passed from the web page via the
MSMQ
passData = passedinData

' Write an event log message to show that we have received a valid
report request
Dim StartTime As Date = Now()
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Processing Started at : " & FormatDateTime( StartTime, DateFormat.Long Time)
& " on request submitted by " & passData.UserNa me & " for sales analysis
from " & Format(passData .StartDate, "MM/dd/yyyy") & " thru " &
Format(passData .EndDate, "MM/dd/yyyy") & ".",
Diagnostics.Eve ntLogEntryType. Information, SDRAEvent.Proce ssStart)

' Get all the configuration data items and set them to local
variables.
' If there is an error, then write an event log record, and exit the
subroutine.
Try
Report = CType(configura tionAppSettings .GetValue("SDRA .Report",
GetType(System. String)), String)
ServerName =
CType(configura tionAppSettings .GetValue("Data base.Server",
GetType(System. String)), String)
DatabaseName =
CType(configura tionAppSettings .GetValue("Data base.Database",
GetType(System. String)), String)
UserName =
CType(configura tionAppSettings .GetValue("Data base.UserName",
GetType(System. String)), String)
Password =
CType(configura tionAppSettings .GetValue("Data base.Password",
GetType(System. String)), String)
CrystalName =
CType(configura tionAppSettings .GetValue("Repo rt.Location",
GetType(System. String)), String) & Report & ".rpt"
TempFileDir =
CType(configura tionAppSettings .GetValue("Sell ars.TempFileDir ectory",
GetType(System. String)), String)
MailFrom = CType(configura tionAppSettings .GetValue("EMai l.From",
GetType(System. String)), String)
WebSite =
CType(configura tionAppSettings .GetValue("Sell ars.WebSite",
GetType(System. String)), String)
StyleSheet =
CType(configura tionAppSettings .GetValue("Sell ars.StyleSheet" ,
GetType(System. String)), String)
PDFViewLocation =
CType(configura tionAppSettings .GetValue("PDFV iewReport.Locat ion",
GetType(System. String)), String)
MailServer =
CType(configura tionAppSettings .GetValue("Emai l.SMTPServer",
GetType(System. String)), String)
Catch ex As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error reading configuration app settings: " & ex.Message,
Diagnostics.Eve ntLogEntryType. Error, SDRAEvent.ReadC onfig)
Exit Sub
End Try

' Call a routine to extract all the requred data from the Invoice
Master, Invoice Detail
' place it in the CustomerDateRan geMargins table, and perform all
necessary calculations
' for the report.
ReloadReportDat a()

' Populate the pre-defined Crystal Report, and export it to a PDF
stored with a unique
' file name.
CreatePDF()

' Capture the time when the report creation processing completed
Dim EndTime As Date = Now

' Mail the crystal reports PDF to the user
EMailReport(Sta rtTime, EndTime)

' Delete the temporary database tables that were used to hold the
data
DeleteReportDat a()

' Delete the PDF File that was created to keep the system clean
If File.Exists(PDF FileName()) Then
File.Delete(PDF FileName())
End If

' Write an event log message signifying that the valid message was
completely processed
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Processing completed at : " & FormatDateTime( EndTime, DateFormat.Long Time)
& " on request submitted by " & passData.UserNa me & " for sales analysis
from " & Format(passData .StartDate, "MM/dd/yyyy") & " thru " &
Format(passData .EndDate, "MM/dd/yyyy") & ".",
Diagnostics.Eve ntLogEntryType. Information)
End Sub
' This routine loads in a pre-defined Crystal Report .rpt file that has
been set up.
' After loading the report with the correct data chosen by the user, a
PDF is created
' from the populated report and saved to disk.
Private Function CreatePDF() As Boolean
'Initialize the return value to true
Dim retvalue As Boolean = True

' Declare necessary local variables to open a Crystal Report
' and access the report parameters.
Dim crReportDocumen t As New ReportDocument
Dim crDatabase As Database
Dim crTables As Tables
Dim crTable As Table
Dim crTableLogOnInf o As TableLogOnInfo
Dim crConnectionInf o As ConnectionInfo

Dim crParameterFiel dDefinitions As ParameterFieldD efinitions
Dim crParameterValu es1 As ParameterValues
Dim crParameterDisc reteValue1 As ParameterDiscre teValue
Dim crParameterValu es2 As ParameterValues
Dim crParameterDisc reteValue2 As ParameterDiscre teValue
Dim crParameterValu es3 As ParameterValues
Dim crParameterDisc reteValue3 As ParameterDiscre teValue
Dim crParameterValu es4 As ParameterValues
Dim crParameterDisc reteValue4 As ParameterDiscre teValue

' Create an instance of the strongly-typed report object and load
the
' correct .rpt file
Dim strReport As String
strReport = CrystalName
Try
crReportDocumen t.Load(strRepor t)
Catch e As Exception
retvalue = False
' Write an event log message
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error loading .rpt template: " & e.Message,
Diagnostics.Eve ntLogEntryType. Error, SDRAEvent.Cryst alLoad)
End Try

' Create a new instance of the connectioninfo object and
' set its properties to reference the database listed in the
configuration settings.
crConnectionInf o = New ConnectionInfo
With crConnectionInf o
.ServerName = ServerName
.DatabaseName = DatabaseName
.UserID = UserName
.Password = Password
End With

'Get the tables collection from the report object
crDatabase = crReportDocumen t.Database
crTables = crDatabase.Tabl es

'Apply the logon information to each table in the collection
For Each crTable In crTables
crTableLogOnInf o = crTable.LogOnIn fo
crTableLogOnInf o.ConnectionInf o = crConnectionInf o
crTable.ApplyLo gOnInfo(crTable LogOnInfo)
Next

' Set the Start Date parameter value
crParameterDisc reteValue1 = New ParameterDiscre teValue
crParameterValu es1 = New ParameterValues
crParameterDisc reteValue1.Valu e = passData.StartD ate
crParameterValu es1.Add(crParam eterDiscreteVal ue1)

crReportDocumen t.DataDefinitio n.ParameterFiel ds("StartDate") .ApplyCurrentVa l
ues(crParameter Values1)

' Set the End Date parameter value
crParameterDisc reteValue2 = New ParameterDiscre teValue
crParameterValu es2 = New ParameterValues
crParameterDisc reteValue2.Valu e = passData.EndDat e
crParameterValu es2.Add(crParam eterDiscreteVal ue2)

crReportDocumen t.DataDefinitio n.ParameterFiel ds("EndDate").A pplyCurrentValu e
s(crParameterVa lues2)

' Set the Request Date parameter value
crParameterDisc reteValue3 = New ParameterDiscre teValue
crParameterValu es3 = New ParameterValues
crParameterDisc reteValue3.Valu e = passData.Report Date
crParameterValu es3.Add(crParam eterDiscreteVal ue3)

crReportDocumen t.DataDefinitio n.ParameterFiel ds("RequestDate ").ApplyCurrent V
alues(crParamet erValues3)

' Set the UserID parameter value
crParameterDisc reteValue4 = New ParameterDiscre teValue
crParameterValu es4 = New ParameterValues
crParameterDisc reteValue4.Valu e = passData.UserID
crParameterValu es4.Add(crParam eterDiscreteVal ue4)

crReportDocumen t.DataDefinitio n.ParameterFiel ds("UserID").Ap plyCurrentValue s
(crParameterVal ues4)

' Define and set the options necessary to save the pdf file to a
disk location
Dim crDiskFileDesti nationOptions As New DiskFileDestina tionOptions
crDiskFileDesti nationOptions.D iskFileName = PDFFileName()
Dim crExportOption As ExportOptions = crReportDocumen t.ExportOptions
With crExportOption
.DestinationOpt ions = crDiskFileDesti nationOptions
.ExportDestinat ionType = ExportDestinati onType.DiskFile
.ExportFormatTy pe = ExportFormatTyp e.PortableDocFo rmat
End With

' Export the refreshed report using the appropriate selection
criteria
' If there is an error with this process, write an appropriate
Windows Event
' Log record.
Try
crReportDocumen t.Export()
Catch e As Exception
retvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error exporting report: " & e.Message, Diagnostics.Eve ntLogEntryType. Error,
SDRAEvent.Cryst alExport)
End Try
End Function

' This function returns the physical direct file path and name of the
temporary file
' top be created and sent via e-mail
Public Function PDFFileName() As String
Return TempFileDir + PDFViewName()
End Function

' This is a unique name for a file so multiple users can access this
routine without any issues.
' A file name will be comprised of three parts:
' 1) The UserID used when the individual logged into the system.
' 2) The time that the request was submitted at the web page making
the request
' (this is necessary so the user can run multiple reports without
any problems)
' 3) The Name defined fo the report which is read in from the
configuration file.
' (this will be the same name as the crystal report .rpt file
except we use a PDF extention)
Public Function PDFViewName() As String
Return passData.UserID + Format(passData .ReportDate, "MMddyyhhmm ss")
+ "_" & Report & ".pdf"
End Function

' This routine is used to run a stored procedure against the
CustomerDateRan geMargins file
' and delete all records that match the UserID and Request Date. This
is typically run
' after all processing has been completed and the e-mail sent as part of
the clean up process.
Private Function DeleteReportDat a() As Boolean
Dim m_objConn As New System.Data.Sql Client.SqlConne ction

'try to open the connection
If Not OpenConnection( m_objConn) Then
Exit Function
End If

Dim returnvalue As Boolean = True
Dim myCommand As New
SqlClient.SqlCo mmand("DeleteCu stomerDateRange Margins", m_objConn)

' Mark the Command as a SPROC
' The timeout value of zero lets all transactions run without timing
out.
myCommand.Comma ndType = CommandType.Sto redProcedure
myCommand.Comma ndTimeout = 0

' Add Parameters to SPROC
Dim parameterReques tDate As New
SqlClient.SqlPa rameter("@Reque stDate", SqlDbType.DateT ime)
parameterReques tDate.Value = passData.Report Date
myCommand.Param eters.Add(param eterRequestDate )

Dim parameterUserID As New SqlClient.SqlPa rameter("@UserI D",
SqlDbType.NVarC har, 15)
parameterUserID .Value = passData.UserID
myCommand.Param eters.Add(param eterUserID)

' Execute the command to perform the query request on the server
' if there is a problem, then write an appropriate Windows Event Log
record.
Try
myCommand.Execu teNonQuery()
Catch e As Exception
returnvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error deleting CustomerDateRan geMargins: " & e.Message,
Diagnostics.Eve ntLogEntryType. Error, SDRAEvent.Delet eData)
End Try

' Free up memory
myCommand = Nothing

' close the database connection and free up memory
CloseConnection (m_objConn)
m_objConn = Nothing

' return a flag indicating if any errors occures while this was
running
Return returnvalue
End Function

' This function calls an SQL Stored procedure. This procedure:
' 1) First deletes any old records that may match the username abd
request date
' 2) Gets all the appropriate records from the Invoice Master,
Invoice Detail and
' Customer master files.
' 3) Applies additional processing to ensure all the necessary
calculations are correct.
Private Function ReloadReportDat a() As Boolean
Dim m_objConn As New System.Data.Sql Client.SqlConne ction

'try to open the connection
If Not OpenConnection( m_objConn) Then
Exit Function
End If

Dim returnvalue As Boolean = True
Dim myCommand As New
SqlClient.SqlCo mmand("ReloadCu stomerDateRange Margins", m_objConn)

' Mark the Command as a SPROC
myCommand.Comma ndType = CommandType.Sto redProcedure
myCommand.Comma ndTimeout = 0

' Add Parameters to SPROC
Dim parameterReques tDate As New
SqlClient.SqlPa rameter("@Reque stDate", SqlDbType.DateT ime)
parameterReques tDate.Value = passData.Report Date
myCommand.Param eters.Add(param eterRequestDate )

Dim parameterUserID As New SqlClient.SqlPa rameter("@UserI D",
SqlDbType.NVarC har, 15)
parameterUserID .Value = passData.UserID
myCommand.Param eters.Add(param eterUserID)

Dim parameterStartD ate As New SqlClient.SqlPa rameter("@Start Date",
SqlDbType.DateT ime)
parameterStartD ate.Value = passData.StartD ate
myCommand.Param eters.Add(param eterStartDate)

Dim parameterEndDat e As New SqlClient.SqlPa rameter("@EndDa te",
SqlDbType.DateT ime)
parameterEndDat e.Value = passData.EndDat e
myCommand.Param eters.Add(param eterEndDate)

' Execute the stored procedure, and if there is an error, write an
appropriate Event Log record.
Try
myCommand.Execu teNonQuery()
Catch e As Exception
returnvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error running ReloadCustomerD ateRangeMargins : " & e.Message,
Diagnostics.Eve ntLogEntryType. Error, SDRAEvent.Reloa dData)
End Try

' Free up memory
myCommand = Nothing

' close the database connection and free up memory
CloseConnection (m_objConn)
m_objConn = Nothing

' return a flag showing whether the report data was retrieved,
loaded and calculated appropriately.
Return returnvalue
End Function

' This routine e-mails the PDF file created above to the user that
submitted the request.
Private Function EMailReport(ByV al StartTime As Date, ByVal EndTime As
Date) As Integer
' Set all the necessary message routing and descriptive information.
Dim myMessage As New System.Web.Mail .MailMessage
Dim strMessage As String
Try
myMessage.To = passData.EMailA ddress
myMessage.From = MailFrom
myMessage.Subje ct = "Sales Analysis from " &
Format(passData .StartDate, "MM/dd/yyyy") & " thru " &
Format(passData .EndDate, "MM/dd/yyyy")
myMessage.BodyF ormat = MailFormat.Html
myMessage.Prior ity = MailPriority.Hi gh
Catch e As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error assigning email data: " & e.Message,
Diagnostics.Eve ntLogEntryType. Error, SDRAEvent.MailP aramters)
Exit Function
End Try

' Set up the message body text.
strMessage = "<html><head><l ink href='" + WebSite + StyleSheet + "'
type='text/css' rel='stylesheet '></head><body>"
strMessage = strMessage + "<Table cellspacing=0 cellpadding=0
style='border-collapse: collapse' bordercolor='#1 11111' width='100%'>"

' Insert a blank line
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display a header line
strMessage = strMessage + "<TR class='Text'><T D>Sales Analysis
processing was performed for data from " & Format(passData .StartDate,
"MM/dd/yyyy") & " thru " & Format(passData .EndDate, "MM/dd/yyyy") & "
</TD></TR>"

' Insert two blank lines
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display the start and end times for the processing
strMessage = strMessage + "<TR class='Text'><T D>Processing was
started at: " + FormatDateTime( StartTime, DateFormat.Long Time) +
"</TD></TR>"
strMessage = strMessage + "<TR class='Text'><T D>Processing was
completed at: " + FormatDateTime( EndTime, DateFormat.Long Time) +
"</TD></TR>"

' Insert two blank lines
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display a header line
strMessage = strMessage + "<TR class='Text'><T D>The completed report
is attached to this e-mail in a PDF format .</TD></TR>"

' End the table
strMessage = strMessage + "</table></body></html>"

' Set the body of the message to the text
myMessage.Body = strMessage

' Add the PDF File as an attachment
Dim objAttach As New MailAttachment( PDFFileName)

' try adding the attachment, and sending the message
Try
myMessage.Attac hments.Add(objA ttach)
SmtpMail.SmtpSe rver = MailServer
SmtpMail.Send(m yMessage)
Catch ex As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error sending email: " & ex.Message, Diagnostics.Eve ntLogEntryType. Error,
SDRAEvent.SendM ail)
Exit Function
End Try

End Function

' Routine that closes the SQL connection object used to access the SQL
server.
Public Sub CloseConnection (ByVal objConnection As
System.Data.Sql Client.SqlConne ction)
Try
objConnection.C lose()
Catch e As Exception
' Write an event log message
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error closing connection: " & e.Message,
Diagnostics.Eve ntLogEntryType. Error, SDRAEvent.Close Connection)
End Try
End Sub

' Routine that opens the SQL connection object used to access the SQL
server.
Public Function OpenConnection( ByVal objConnection As
System.Data.Sql Client.SqlConne ction) As Boolean
Dim retvalue As Boolean = True

Try
objConnection.C onnectionString = "Server=" & ServerName &
";User=" & UserName & ";Password= " & Password & "; " _
& "Database=" & DatabaseName
objConnection.O pen()
Catch e As Exception
retvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error opening connection: " & e.Message,
Diagnostics.Eve ntLogEntryType. Error, SDRAEvent.OpenC onnection)
End Try

Return retvalue
End Function

' Declare properties for all configuration data file items.
Private Property DatabaseName() As String
Get
DatabaseName = mvarDatabaseNam e
End Get
Set(ByVal Value As String)
mvarDatabaseNam e = Value
End Set
End Property

Private Property Password() As String
Get
Password = mvarPassword
End Get
Set(ByVal Value As String)
mvarPassword = Value
End Set
End Property

Private Property ServerName() As String
Get
ServerName = mvarServerName
End Get
Set(ByVal Value As String)
mvarServerName = Value
End Set
End Property

Private Property UserName() As String
Get
UserName = mvaruserName
End Get
Set(ByVal Value As String)
mvaruserName = Value
End Set
End Property

Private Property MailTo() As String
Get
MailTo = mvarMailTo
End Get
Set(ByVal Value As String)
mvarMailTo = Value
End Set
End Property

Private Property MailFrom() As String
Get
MailFrom = mvarMailFrom
End Get
Set(ByVal Value As String)
mvarMailFrom = Value
End Set
End Property

Private Property MailServer() As String
Get
MailServer = mvarMailServer
End Get
Set(ByVal Value As String)
mvarMailServer = Value
End Set
End Property

Private Property PDFViewLocation () As String
Get
PDFViewLocation = mvarPDFViewLoca tion
End Get
Set(ByVal Value As String)
mvarPDFViewLoca tion = Value
End Set
End Property

Private Property Report() As String
Get
Report = mvarReport
End Get
Set(ByVal Value As String)
mvarReport = Value
End Set
End Property

Private Property CrystalName() As String
Get
CrystalName = mvarCrystalName
End Get
Set(ByVal Value As String)
mvarCrystalName = Value
End Set
End Property

Private Property StyleSheet() As String
Get
StyleSheet = mvarStyleSheet
End Get
Set(ByVal Value As String)
mvarStyleSheet = Value
End Set
End Property

Private Property TempFileDir() As String
Get
TempFileDir = mvarTempFileDir
End Get
Set(ByVal Value As String)
mvarTempFileDir = Value
End Set
End Property

Private Property WebSite() As String
Get
WebSite = mvarWebSite
End Get
Set(ByVal Value As String)
mvarWebSite = Value
End Set
End Property

End Class
Nov 20 '05 #1
6 4995
Hi James,

|| Below you will find my current source code.

All of it. Reams of it. Enough to frighten everyone away!!

It's a shame James, but very general questions like "what do you think?"
that arrive with masses of code are usually quietly left for someone else to
answer - except that "someone else" is doing the same!!
Some ideas :-
Resubmit your query with questions that are more specific.

Cut down the code drastically to the minimum required to understand
the issue.

Do a search not just for queue but pipeline, circular buffer,
consumer/producer.

Read up on Monitors and Threads (yes, I know you have, read it again
and go deeper :-)).
The answer to your question: "QUEUE ... Is this correct?" is Yes. But I
can't get you any further than that I'm afraid. :-(

The languages.cshar p newsgroup contains a lot of people who devour such
things as threading. You might like to post your query there as well - if you
can specify your query without reference to code, or if you are comfortable
translating snippets to C#. Or you can do it anyway, with your VB code (not
too much), but give them a big apology along with it.

Best of luck,
Fergus
Nov 20 '05 #2
Cor
Hi Fergus,
Nice mail, I was thinking the same when reading the post from James except
the part of C#.
MultiThreading was some weeks ago a very hot item in this newsgroup with big
discussions.
I think that are waves like it is now in my opinion inherriting and so.
What do you think is the part that cannot be done with VB.net?
Cor
Nov 20 '05 #3
Hi James,

You may take a look at the link below.
http://msdn.microsoft.com/library/de...us/csref/html/
vcwlkthreadingt utorial.asp

Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
--------------------
Reply-To: "James Radke" <jr*****@wi.rr. com>
From: "James Radke" <jr*****@wi.rr. com>
Subject: How to have multiple worker threads submit to one final processing queue? - HELPDate: Wed, 3 Sep 2003 14:04:42 -0500
Lines: 872
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2800.1158
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165
Message-ID: <OR************ **@TK2MSFTNGP10 .phx.gbl>
Newsgroups: microsoft.publi c.dotnet.langua ges.vb
NNTP-Posting-Host: cpe-24-167-241-101.wi.rr.com 24.167.241.101
Path: cpmsftngxa06.ph x.gbl!TK2MSFTNG P08.phx.gbl!TK2 MSFTNGP10.phx.g bl
Xref: cpmsftngxa06.ph x.gbl microsoft.publi c.dotnet.langua ges.vb:133967
X-Tomcat-NG: microsoft.publi c.dotnet.langua ges.vb

Hello,

I have a multithreaded windows NT service application (vb.net 2003) that I
am working on (my first one), which reads a message queue and creates
multiple threads to perform the processing for long running reports. When
the processing is complete it uses crystal reports to load a template file,
populate it, and then export it to a PDF.

It works fine so far....

Now, since few reports are run - but multiple could be submitted at the sametime, I would like to keep the longer processing multithreaded (i.e.
function ReloadReportDat a() in the processing module below), but then singlethread the crystal report creation/pdf export and e-mailing of the PDF, so
that additional crystal report licenses will not be required (these are veryquick once the processing has been completed). Can someone help me figure
out the best way to do this? From what I can gather in reading various
posts I believe that I would create a QUEUE (note, I don't think is the samething as a message queue) and then have a separate thread that is just
pulling messages off of this, and then processing. Once the processing is
done, check for another entry in the QUEUE... Is this correct? But I
haven't seen any good examples of how to do that, and how to wait for the
message.

Below you will find my current source code.

I wouldn't mind additional comments on the techniques that I finally chose
for the threading. Is this all ok? Are there better ways to do this?

Thanks in advance for any assistance!

Jim

============== =============== =============== =============== =============== = =============== ==============
the following is in the start up of the windows service
============== =============== =============== =============== =============== = =============== ==============
Private myThreadPool As ThreadPool()
Private oThread(1) As Thread

Protected Overrides Sub OnStart(ByVal args() As String)
' Write a message to the log
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ", "Service started at : " & FormatDateTime( Now(), DateFormat.Long Time),
Diagnostics.Ev entLogEntryType .Information, 1)

Dim i As Integer 'Thread count
Dim objMQListen As MQListen

' Declare a worker thread
Dim objThreadStart As ThreadStart

'declare the Class that will run our threads
objMQListen = New MQListen

' Create a ThreadStart object, passing the address of
objMQListener. Listen
' then set the reference and start the main MQListener thread
objThreadStart = New ThreadStart(Add ressOf objMQListen.Lis ten)
oThread(0) = New Thread(objThrea dStart)
oThread(0).Star t()
End Sub

============== =============== =============== =============== =============== = =============== ==============
the following is the Message Queue Listener Class
============== =============== =============== =============== =============== = =============== ==============

Imports System.Messagin g
Imports System.Threadin g

Public Class MQListen
Private configurationAp pSettings As _
System.Configur ation.AppSettin gsReader = New _
System.Configur ation.AppSettin gsReader

'constructor accepts the necessary queue information
Sub MQListen(ByVal MachineName As String, ByVal QueueName As String)
End Sub

'One and only method that each thread uses to
Sub Listen()
Dim oThread As Thread
Dim objThreadStart As ThreadStart

'Create a MessageQueue object
Dim objMQ As System.Messagin g.MessageQueue
Try
objMQ = New
System.Messagi ng.MessageQueue (CType(configur ationAppSetting s.GetValue("Sel l ars.MessageQueu e", GetType(System. String)), String))
Catch
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error connecting to MessageQueue: " & Err.Description ,
Diagnostics.Ev entLogEntryType .Error)
Debug.WriteLine (Err.Descriptio n)
End Try
Dim myMessageBody As New MQPassedData
Dim TargetTypes(0) As System.Type
TargetTypes(0) = myMessageBody.G etType
objMQ.Formatter = New XmlMessageForma tter(TargetType s)
myMessageBody = Nothing

'Create a Message object
Dim objMsg As Message

Try
'repeat until Interrupt received
While True
Try
'sleep in order to catch the interrupt if it has been
thrown
'Interrupt will only be processed by a thread that is ina
'wait, sleep or join state
Thread.CurrentT hread.Sleep(100 )

'Set the Message object equal to the result from the
receive function
'there are 2 implementations of Receive. The one I use
requires a
'TimeSpan object which specifies the timeout period.
There is also an
'implementation of Receive which requires nothing and
will wait indefinitely
'for a message to arrive on a queue
'Timespan(?, hours, minutes, seconds)
Dim newMessageBody As New MQPassedData
objMsg = objMQ.Receive(N ew TimeSpan(0, 0, 0, 1))
Try
newMessageBody = objMsg.Body
Catch emsg As Exception

System.Diagnos tics.EventLog.W riteEntry("Sell arsReportServic e", "Msg receivederror: " & emsg.Message, Diagnostics.Eve ntLogEntryType. Information)
' Create a ThreadStart object, passing the address of objMQListener.L isten
End Try

' Set the passed data in, and place it in a new
ThreadPool element
' The treadpool takes care of managing all the thread
issues in a very
' simple way.
Dim processingutili ties As New SDRAProcessing
Dim passData As New MQPassedData
passData = newMessageBody
ThreadPool.Queu eUserWorkItem(N ew WaitCallback(Ad dressOf
processingutil ities.ProcessMe ssage), passData)

' Free up memory held during processing
newMessageBody = Nothing
Catch e As ThreadInterrupt edException
'catch the ThreadInterrupt from the main thread and exit ' Console.WriteLi ne("Exiting Thread")
Exit While
Catch excp As Exception
'Catch any exceptions thrown in receive
'MsgBox("No message received in 10 seconds")
'Console.WriteL ine(excp.Messag e)
End Try

End While

Catch e As ThreadInterrupt edException
'catch the ThreadInterrupt from the main thread and exit
'Console.WriteL ine("Exiting Thread")

End Try

'exit thread

End Sub

End Class

============== =============== =============== =============== =============== = =============== ==============
the following is my main processing class
============== =============== =============== =============== =============== = =============== ==============

Imports System.Configur ation
Imports System.Data
Imports System.IO
Imports System.Messagin g
Imports System.Threadin g
Imports System.Web.Mail
Imports CrystalDecision s.CrystalReport s.Engine
Imports CrystalDecision s.Shared

' This class handles the processing for each Sales Date Range Analysis
request
' that is received from the queue
Public Class SDRAProcessing
Private configurationAp pSettings As _
System.Configur ation.AppSettin gsReader = New _
System.Configur ation.AppSettin gsReader

' Declare local variables to store login information for the SQL Server
' this information is read in from the configuration file which resides
in
' the same directory as the service's executable module.
Private mvarDatabaseNam e As String
Private mvarServerName As String
Private mvaruserName As String
Private mvarPassword As String

' Local variables to store various parameters read in from the
configuratio n file
' this information is read in from the configuration file which resides
in
' the same directory as the service's executable module.
Private mvarReport As String
Private mvarCrystalName As String
Private mvarTempFileDir As String
Private mvarMailTo As String
Private mvarMailFrom As String
Private mvarMailServer As String
Private mvarWebSite As String
Private mvarStyleSheet As String
Private mvarPDFViewLoca tion As String

' Instantiate an object containing the data passed from the web page viathe message queue
Public passData As New MQPassedData

' Local ENUMERATIONS for the EVENT ID used when writing to the Windows
Event Log
Private Enum SDRAEvent As Integer
ServiceStart = 1
ServiceStop = 2
ProcessStart = 3
ProcessStop = 4
ReloadData = 100
DeleteData = 101
ReadConfig = 200
OpenConnection = 201
CloseConnection = 202
CrystalFile = 300
CrystalLoad = 301
CrystalExport = 302
MailParamters = 400
SendMail = 401
End Enum

' This routine is ONLY called when a valid sales date range analysis
request has
' been received. Then
' 1) The requested data is loaded into a temporary database (via the ' ReloadReportDat a routine) off of which we can perform various
reporting tasks
' 2) A PDF file containing the report is produced using interaction
with Crystal Reports.
' 3) The PDF is e-mail to the user that submitted the report
request.
'
Public Sub ProcessMessage( ByVal passedinData As Object)

' Reference the state object passed in via the ThreadPool call to
the procedure.
' this contains the data as it was passed from the web page via the
MSMQ
passData = passedinData

' Write an event log message to show that we have received a valid
report request
Dim StartTime As Date = Now()
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Processing Started at : " & FormatDateTime( StartTime, DateFormat.Long Time)
& " on request submitted by " & passData.UserNa me & " for sales analysis
from " & Format(passData .StartDate, "MM/dd/yyyy") & " thru " &
Format(passDat a.EndDate, "MM/dd/yyyy") & ".",
Diagnostics.Ev entLogEntryType .Information, SDRAEvent.Proce ssStart)

' Get all the configuration data items and set them to local
variables.
' If there is an error, then write an event log record, and exit thesubroutine.
Try
Report = CType(configura tionAppSettings .GetValue("SDRA .Report",
GetType(System .String)), String)
ServerName =
CType(configur ationAppSetting s.GetValue("Dat abase.Server",
GetType(System .String)), String)
DatabaseName =
CType(configur ationAppSetting s.GetValue("Dat abase.Database" ,
GetType(System .String)), String)
UserName =
CType(configur ationAppSetting s.GetValue("Dat abase.UserName" ,
GetType(System .String)), String)
Password =
CType(configur ationAppSetting s.GetValue("Dat abase.Password" ,
GetType(System .String)), String)
CrystalName =
CType(configur ationAppSetting s.GetValue("Rep ort.Location",
GetType(System .String)), String) & Report & ".rpt"
TempFileDir =
CType(configur ationAppSetting s.GetValue("Sel lars.TempFileDi rectory",
GetType(System .String)), String)
MailFrom = CType(configura tionAppSettings .GetValue("EMai l.From",GetType(System .String)), String)
WebSite =
CType(configur ationAppSetting s.GetValue("Sel lars.WebSite",
GetType(System .String)), String)
StyleSheet =
CType(configur ationAppSetting s.GetValue("Sel lars.StyleSheet ",
GetType(System .String)), String)
PDFViewLocation =
CType(configur ationAppSetting s.GetValue("PDF ViewReport.Loca tion",
GetType(System .String)), String)
MailServer =
CType(configur ationAppSetting s.GetValue("Ema il.SMTPServer",
GetType(System .String)), String)
Catch ex As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error reading configuration app settings: " & ex.Message,
Diagnostics.Ev entLogEntryType .Error, SDRAEvent.ReadC onfig)
Exit Sub
End Try

' Call a routine to extract all the requred data from the Invoice
Master, Invoice Detail
' place it in the CustomerDateRan geMargins table, and perform all
necessary calculations
' for the report.
ReloadReportDat a()

' Populate the pre-defined Crystal Report, and export it to a PDF
stored with a unique
' file name.
CreatePDF()

' Capture the time when the report creation processing completed
Dim EndTime As Date = Now

' Mail the crystal reports PDF to the user
EMailReport(Sta rtTime, EndTime)

' Delete the temporary database tables that were used to hold the
data
DeleteReportDat a()

' Delete the PDF File that was created to keep the system clean
If File.Exists(PDF FileName()) Then
File.Delete(PDF FileName())
End If

' Write an event log message signifying that the valid message was
completely processed
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Processing completed at : " & FormatDateTime( EndTime, DateFormat.Long Time)
& " on request submitted by " & passData.UserNa me & " for sales analysis
from " & Format(passData .StartDate, "MM/dd/yyyy") & " thru " &
Format(passDat a.EndDate, "MM/dd/yyyy") & ".",
Diagnostics.Ev entLogEntryType .Information)
End Sub
' This routine loads in a pre-defined Crystal Report .rpt file that has
been set up.
' After loading the report with the correct data chosen by the user, a
PDF is created
' from the populated report and saved to disk.
Private Function CreatePDF() As Boolean
'Initialize the return value to true
Dim retvalue As Boolean = True

' Declare necessary local variables to open a Crystal Report
' and access the report parameters.
Dim crReportDocumen t As New ReportDocument
Dim crDatabase As Database
Dim crTables As Tables
Dim crTable As Table
Dim crTableLogOnInf o As TableLogOnInfo
Dim crConnectionInf o As ConnectionInfo

Dim crParameterFiel dDefinitions As ParameterFieldD efinitions
Dim crParameterValu es1 As ParameterValues
Dim crParameterDisc reteValue1 As ParameterDiscre teValue
Dim crParameterValu es2 As ParameterValues
Dim crParameterDisc reteValue2 As ParameterDiscre teValue
Dim crParameterValu es3 As ParameterValues
Dim crParameterDisc reteValue3 As ParameterDiscre teValue
Dim crParameterValu es4 As ParameterValues
Dim crParameterDisc reteValue4 As ParameterDiscre teValue

' Create an instance of the strongly-typed report object and load
the
' correct .rpt file
Dim strReport As String
strReport = CrystalName
Try
crReportDocumen t.Load(strRepor t)
Catch e As Exception
retvalue = False
' Write an event log message
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error loading .rpt template: " & e.Message,
Diagnostics.Ev entLogEntryType .Error, SDRAEvent.Cryst alLoad)
End Try

' Create a new instance of the connectioninfo object and
' set its properties to reference the database listed in the
configuratio n settings.
crConnectionInf o = New ConnectionInfo
With crConnectionInf o
.ServerName = ServerName
.DatabaseName = DatabaseName
.UserID = UserName
.Password = Password
End With

'Get the tables collection from the report object
crDatabase = crReportDocumen t.Database
crTables = crDatabase.Tabl es

'Apply the logon information to each table in the collection
For Each crTable In crTables
crTableLogOnInf o = crTable.LogOnIn fo
crTableLogOnInf o.ConnectionInf o = crConnectionInf o
crTable.ApplyLo gOnInfo(crTable LogOnInfo)
Next

' Set the Start Date parameter value
crParameterDisc reteValue1 = New ParameterDiscre teValue
crParameterValu es1 = New ParameterValues
crParameterDisc reteValue1.Valu e = passData.StartD ate
crParameterValu es1.Add(crParam eterDiscreteVal ue1)

crReportDocume nt.DataDefiniti on.ParameterFie lds("StartDate" ).ApplyCurrentV a lues(crParamete rValues1)

' Set the End Date parameter value
crParameterDisc reteValue2 = New ParameterDiscre teValue
crParameterValu es2 = New ParameterValues
crParameterDisc reteValue2.Valu e = passData.EndDat e
crParameterValu es2.Add(crParam eterDiscreteVal ue2)

crReportDocume nt.DataDefiniti on.ParameterFie lds("EndDate"). ApplyCurrentVal u es(crParameterV alues2)

' Set the Request Date parameter value
crParameterDisc reteValue3 = New ParameterDiscre teValue
crParameterValu es3 = New ParameterValues
crParameterDisc reteValue3.Valu e = passData.Report Date
crParameterValu es3.Add(crParam eterDiscreteVal ue3)

crReportDocume nt.DataDefiniti on.ParameterFie lds("RequestDat e").ApplyCurren t Values(crParame terValues3)

' Set the UserID parameter value
crParameterDisc reteValue4 = New ParameterDiscre teValue
crParameterValu es4 = New ParameterValues
crParameterDisc reteValue4.Valu e = passData.UserID
crParameterValu es4.Add(crParam eterDiscreteVal ue4)

crReportDocume nt.DataDefiniti on.ParameterFie lds("UserID").A pplyCurrentValu e s(crParameterVa lues4)

' Define and set the options necessary to save the pdf file to a
disk location
Dim crDiskFileDesti nationOptions As New DiskFileDestina tionOptions
crDiskFileDesti nationOptions.D iskFileName = PDFFileName()
Dim crExportOption As ExportOptions = crReportDocumen t.ExportOptions With crExportOption
.DestinationOpt ions = crDiskFileDesti nationOptions
.ExportDestinat ionType = ExportDestinati onType.DiskFile
.ExportFormatTy pe = ExportFormatTyp e.PortableDocFo rmat
End With

' Export the refreshed report using the appropriate selection
criteria
' If there is an error with this process, write an appropriate
Windows Event
' Log record.
Try
crReportDocumen t.Export()
Catch e As Exception
retvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error exporting report: " & e.Message, Diagnostics.Eve ntLogEntryType. Error,SDRAEvent.Crys talExport)
End Try
End Function

' This function returns the physical direct file path and name of the
temporary file
' top be created and sent via e-mail
Public Function PDFFileName() As String
Return TempFileDir + PDFViewName()
End Function

' This is a unique name for a file so multiple users can access this
routine without any issues.
' A file name will be comprised of three parts:
' 1) The UserID used when the individual logged into the system.
' 2) The time that the request was submitted at the web page making
the request
' (this is necessary so the user can run multiple reports without
any problems)
' 3) The Name defined fo the report which is read in from the
configuratio n file.
' (this will be the same name as the crystal report .rpt file
except we use a PDF extention)
Public Function PDFViewName() As String
Return passData.UserID + Format(passData .ReportDate, "MMddyyhhmm ss")+ "_" & Report & ".pdf"
End Function

' This routine is used to run a stored procedure against the
CustomerDateRa ngeMargins file
' and delete all records that match the UserID and Request Date. This
is typically run
' after all processing has been completed and the e-mail sent as part ofthe clean up process.
Private Function DeleteReportDat a() As Boolean
Dim m_objConn As New System.Data.Sql Client.SqlConne ction

'try to open the connection
If Not OpenConnection( m_objConn) Then
Exit Function
End If

Dim returnvalue As Boolean = True
Dim myCommand As New
SqlClient.SqlC ommand("DeleteC ustomerDateRang eMargins", m_objConn)

' Mark the Command as a SPROC
' The timeout value of zero lets all transactions run without timingout.
myCommand.Comma ndType = CommandType.Sto redProcedure
myCommand.Comma ndTimeout = 0

' Add Parameters to SPROC
Dim parameterReques tDate As New
SqlClient.SqlP arameter("@Requ estDate", SqlDbType.DateT ime)
parameterReques tDate.Value = passData.Report Date
myCommand.Param eters.Add(param eterRequestDate )

Dim parameterUserID As New SqlClient.SqlPa rameter("@UserI D",
SqlDbType.NVar Char, 15)
parameterUserID .Value = passData.UserID
myCommand.Param eters.Add(param eterUserID)

' Execute the command to perform the query request on the server
' if there is a problem, then write an appropriate Windows Event Logrecord.
Try
myCommand.Execu teNonQuery()
Catch e As Exception
returnvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error deleting CustomerDateRan geMargins: " & e.Message,
Diagnostics.Ev entLogEntryType .Error, SDRAEvent.Delet eData)
End Try

' Free up memory
myCommand = Nothing

' close the database connection and free up memory
CloseConnection (m_objConn)
m_objConn = Nothing

' return a flag indicating if any errors occures while this was
running
Return returnvalue
End Function

' This function calls an SQL Stored procedure. This procedure:
' 1) First deletes any old records that may match the username abd
request date
' 2) Gets all the appropriate records from the Invoice Master,
Invoice Detail and
' Customer master files.
' 3) Applies additional processing to ensure all the necessary
calculations are correct.
Private Function ReloadReportDat a() As Boolean
Dim m_objConn As New System.Data.Sql Client.SqlConne ction

'try to open the connection
If Not OpenConnection( m_objConn) Then
Exit Function
End If

Dim returnvalue As Boolean = True
Dim myCommand As New
SqlClient.SqlC ommand("ReloadC ustomerDateRang eMargins", m_objConn)

' Mark the Command as a SPROC
myCommand.Comma ndType = CommandType.Sto redProcedure
myCommand.Comma ndTimeout = 0

' Add Parameters to SPROC
Dim parameterReques tDate As New
SqlClient.SqlP arameter("@Requ estDate", SqlDbType.DateT ime)
parameterReques tDate.Value = passData.Report Date
myCommand.Param eters.Add(param eterRequestDate )

Dim parameterUserID As New SqlClient.SqlPa rameter("@UserI D",
SqlDbType.NVar Char, 15)
parameterUserID .Value = passData.UserID
myCommand.Param eters.Add(param eterUserID)

Dim parameterStartD ate As New SqlClient.SqlPa rameter("@Start Date",
SqlDbType.Date Time)
parameterStartD ate.Value = passData.StartD ate
myCommand.Param eters.Add(param eterStartDate)

Dim parameterEndDat e As New SqlClient.SqlPa rameter("@EndDa te",
SqlDbType.Date Time)
parameterEndDat e.Value = passData.EndDat e
myCommand.Param eters.Add(param eterEndDate)

' Execute the stored procedure, and if there is an error, write an
appropriate Event Log record.
Try
myCommand.Execu teNonQuery()
Catch e As Exception
returnvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error running ReloadCustomerD ateRangeMargins : " & e.Message,
Diagnostics.Ev entLogEntryType .Error, SDRAEvent.Reloa dData)
End Try

' Free up memory
myCommand = Nothing

' close the database connection and free up memory
CloseConnection (m_objConn)
m_objConn = Nothing

' return a flag showing whether the report data was retrieved,
loaded and calculated appropriately.
Return returnvalue
End Function

' This routine e-mails the PDF file created above to the user that
submitted the request.
Private Function EMailReport(ByV al StartTime As Date, ByVal EndTime As
Date) As Integer
' Set all the necessary message routing and descriptive information. Dim myMessage As New System.Web.Mail .MailMessage
Dim strMessage As String
Try
myMessage.To = passData.EMailA ddress
myMessage.From = MailFrom
myMessage.Subje ct = "Sales Analysis from " &
Format(passDat a.StartDate, "MM/dd/yyyy") & " thru " &
Format(passDat a.EndDate, "MM/dd/yyyy")
myMessage.BodyF ormat = MailFormat.Html
myMessage.Prior ity = MailPriority.Hi gh
Catch e As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error assigning email data: " & e.Message,
Diagnostics.Ev entLogEntryType .Error, SDRAEvent.MailP aramters)
Exit Function
End Try

' Set up the message body text.
strMessage = "<html><head><l ink href='" + WebSite + StyleSheet + "'
type='text/css' rel='stylesheet '></head><body>"
strMessage = strMessage + "<Table cellspacing=0 cellpadding=0
style='borde r-collapse: collapse' bordercolor='#1 11111' width='100%'>"

' Insert a blank line
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display a header line
strMessage = strMessage + "<TR class='Text'><T D>Sales Analysis
processing was performed for data from " & Format(passData .StartDate,
"MM/dd/yyyy") & " thru " & Format(passData .EndDate, "MM/dd/yyyy") & "
</TD></TR>"

' Insert two blank lines
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display the start and end times for the processing
strMessage = strMessage + "<TR class='Text'><T D>Processing was
started at: " + FormatDateTime( StartTime, DateFormat.Long Time) +
"</TD></TR>"
strMessage = strMessage + "<TR class='Text'><T D>Processing was
completed at: " + FormatDateTime( EndTime, DateFormat.Long Time) +
"</TD></TR>"

' Insert two blank lines
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display a header line
strMessage = strMessage + "<TR class='Text'><T D>The completed reportis attached to this e-mail in a PDF format .</TD></TR>"

' End the table
strMessage = strMessage + "</table></body></html>"

' Set the body of the message to the text
myMessage.Body = strMessage

' Add the PDF File as an attachment
Dim objAttach As New MailAttachment( PDFFileName)

' try adding the attachment, and sending the message
Try
myMessage.Attac hments.Add(objA ttach)
SmtpMail.SmtpSe rver = MailServer
SmtpMail.Send(m yMessage)
Catch ex As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error sending email: " & ex.Message, Diagnostics.Eve ntLogEntryType. Error,
SDRAEvent.Send Mail)
Exit Function
End Try

End Function

' Routine that closes the SQL connection object used to access the SQL
server.
Public Sub CloseConnection (ByVal objConnection As
System.Data.Sq lClient.SqlConn ection)
Try
objConnection.C lose()
Catch e As Exception
' Write an event log message
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error closing connection: " & e.Message,
Diagnostics.Ev entLogEntryType .Error, SDRAEvent.Close Connection)
End Try
End Sub

' Routine that opens the SQL connection object used to access the SQL
server.
Public Function OpenConnection( ByVal objConnection As
System.Data.Sq lClient.SqlConn ection) As Boolean
Dim retvalue As Boolean = True

Try
objConnection.C onnectionString = "Server=" & ServerName &
";User=" & UserName & ";Password= " & Password & "; " _
& "Database=" & DatabaseName
objConnection.O pen()
Catch e As Exception
retvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error opening connection: " & e.Message,
Diagnostics.Ev entLogEntryType .Error, SDRAEvent.OpenC onnection)
End Try

Return retvalue
End Function

' Declare properties for all configuration data file items.
Private Property DatabaseName() As String
Get
DatabaseName = mvarDatabaseNam e
End Get
Set(ByVal Value As String)
mvarDatabaseNam e = Value
End Set
End Property

Private Property Password() As String
Get
Password = mvarPassword
End Get
Set(ByVal Value As String)
mvarPassword = Value
End Set
End Property

Private Property ServerName() As String
Get
ServerName = mvarServerName
End Get
Set(ByVal Value As String)
mvarServerName = Value
End Set
End Property

Private Property UserName() As String
Get
UserName = mvaruserName
End Get
Set(ByVal Value As String)
mvaruserName = Value
End Set
End Property

Private Property MailTo() As String
Get
MailTo = mvarMailTo
End Get
Set(ByVal Value As String)
mvarMailTo = Value
End Set
End Property

Private Property MailFrom() As String
Get
MailFrom = mvarMailFrom
End Get
Set(ByVal Value As String)
mvarMailFrom = Value
End Set
End Property

Private Property MailServer() As String
Get
MailServer = mvarMailServer
End Get
Set(ByVal Value As String)
mvarMailServer = Value
End Set
End Property

Private Property PDFViewLocation () As String
Get
PDFViewLocation = mvarPDFViewLoca tion
End Get
Set(ByVal Value As String)
mvarPDFViewLoca tion = Value
End Set
End Property

Private Property Report() As String
Get
Report = mvarReport
End Get
Set(ByVal Value As String)
mvarReport = Value
End Set
End Property

Private Property CrystalName() As String
Get
CrystalName = mvarCrystalName
End Get
Set(ByVal Value As String)
mvarCrystalName = Value
End Set
End Property

Private Property StyleSheet() As String
Get
StyleSheet = mvarStyleSheet
End Get
Set(ByVal Value As String)
mvarStyleSheet = Value
End Set
End Property

Private Property TempFileDir() As String
Get
TempFileDir = mvarTempFileDir
End Get
Set(ByVal Value As String)
mvarTempFileDir = Value
End Set
End Property

Private Property WebSite() As String
Get
WebSite = mvarWebSite
End Get
Set(ByVal Value As String)
mvarWebSite = Value
End Set
End Property

End Class


Nov 20 '05 #4
Hi James,

In addition, you may take a quick look at the link below.
http://www.codeproject.com/useritems/threadingvbnet.asp

Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
--------------------
Newsgroups: microsoft.publi c.dotnet.langua ges.vb
From: v-******@online.m icrosoft.com (Peter Huang [MSFT])
Organization : Microsoft
Date: Thu, 04 Sep 2003 08:57:07 GMT
Subject: RE: How to have multiple worker threads submit to one final processing queue? - HELPX-Tomcat-NG: microsoft.publi c.dotnet.langua ges.vb
MIME-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Hi James,

You may take a look at the link below.
http://msdn.microsoft.com/library/de...-us/csref/html /vcwlkthreading tutorial.asp

Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
--------------------
Reply-To: "James Radke" <jr*****@wi.rr. com>
From: "James Radke" <jr*****@wi.rr. com>
Subject: How to have multiple worker threads submit to one finalprocessing queue? - HELP
Date: Wed, 3 Sep 2003 14:04:42 -0500
Lines: 872
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2800.1158
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165
Message-ID: <OR************ **@TK2MSFTNGP10 .phx.gbl>
Newsgroups: microsoft.publi c.dotnet.langua ges.vb
NNTP-Posting-Host: cpe-24-167-241-101.wi.rr.com 24.167.241.101
Path: cpmsftngxa06.ph x.gbl!TK2MSFTNG P08.phx.gbl!TK2 MSFTNGP10.phx.g bl
Xref: cpmsftngxa06.ph x.gbl microsoft.publi c.dotnet.langua ges.vb:133967
X-Tomcat-NG: microsoft.publi c.dotnet.langua ges.vb

Hello,

I have a multithreaded windows NT service application (vb.net 2003) that I
am working on (my first one), which reads a message queue and creates
multiple threads to perform the processing for long running reports. When
the processing is complete it uses crystal reports to load a template file,populate it, and then export it to a PDF.

It works fine so far....

Now, since few reports are run - but multiple could be submitted at the

same
time, I would like to keep the longer processing multithreaded (i.e.
function ReloadReportDat a() in the processing module below), but then

single
thread the crystal report creation/pdf export and e-mailing of the PDF, so
that additional crystal report licenses will not be required (these are

very
quick once the processing has been completed). Can someone help me figure
out the best way to do this? From what I can gather in reading various
posts I believe that I would create a QUEUE (note, I don't think is the

same
thing as a message queue) and then have a separate thread that is just
pulling messages off of this, and then processing. Once the processing is
done, check for another entry in the QUEUE... Is this correct? But I
haven't seen any good examples of how to do that, and how to wait for the
message.

Below you will find my current source code.

I wouldn't mind additional comments on the techniques that I finally chose
for the threading. Is this all ok? Are there better ways to do this?

Thanks in advance for any assistance!

Jim

============= =============== =============== =============== =============== = ==
============= ===============
the following is in the start up of the windows service
============= =============== =============== =============== =============== =
==
============= ===============
Private myThreadPool As ThreadPool()
Private oThread(1) As Thread

Protected Overrides Sub OnStart(ByVal args() As String)
' Write a message to the log
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ","Serv
ice started at : " & FormatDateTime( Now(), DateFormat.Long Time),
Diagnostics.E ventLogEntryTyp e.Information, 1)

Dim i As Integer 'Thread count
Dim objMQListen As MQListen

' Declare a worker thread
Dim objThreadStart As ThreadStart

'declare the Class that will run our threads
objMQListen = New MQListen

' Create a ThreadStart object, passing the address of
objMQListener .Listen
' then set the reference and start the main MQListener thread
objThreadStart = New ThreadStart(Add ressOf objMQListen.Lis ten)
oThread(0) = New Thread(objThrea dStart)
oThread(0).Star t()
End Sub

============= =============== =============== =============== =============== =

==
============= ===============
the following is the Message Queue Listener Class
============= =============== =============== =============== =============== =
==
============= ===============

Imports System.Messagin g
Imports System.Threadin g

Public Class MQListen
Private configurationAp pSettings As _
System.Configur ation.AppSettin gsReader = New _
System.Configur ation.AppSettin gsReader

'constructor accepts the necessary queue information
Sub MQListen(ByVal MachineName As String, ByVal QueueName As String)
End Sub

'One and only method that each thread uses to
Sub Listen()
Dim oThread As Thread
Dim objThreadStart As ThreadStart

'Create a MessageQueue object
Dim objMQ As System.Messagin g.MessageQueue
Try
objMQ = New
System.Messag ing.MessageQueu e(CType(configu rationAppSettin gs.GetValue("Se l
la
rs.MessageQue ue", GetType(System. String)), String))
Catch
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error connecting to MessageQueue: " & Err.Description ,
Diagnostics.E ventLogEntryTyp e.Error)
Debug.WriteLine (Err.Descriptio n)
End Try
Dim myMessageBody As New MQPassedData
Dim TargetTypes(0) As System.Type
TargetTypes(0) = myMessageBody.G etType
objMQ.Formatter = New XmlMessageForma tter(TargetType s)
myMessageBody = Nothing

'Create a Message object
Dim objMsg As Message

Try
'repeat until Interrupt received
While True
Try
'sleep in order to catch the interrupt if it has been
thrown
'Interrupt will only be processed by a thread that isin
a
'wait, sleep or join state
Thread.CurrentT hread.Sleep(100 )

'Set the Message object equal to the result from the
receive function
'there are 2 implementations of Receive. The one I

userequires a
'TimeSpan object which specifies the timeout period.
There is also an
'implementation of Receive which requires nothing and
will wait indefinitely
'for a message to arrive on a queue
'Timespan(?, hours, minutes, seconds)
Dim newMessageBody As New MQPassedData
objMsg = objMQ.Receive(N ew TimeSpan(0, 0, 0, 1))
Try
newMessageBody = objMsg.Body
Catch emsg As Exception

System.Diagno stics.EventLog. WriteEntry("Sel larsReportServi ce", "Msg

received
error: " & emsg.Message, Diagnostics.Eve ntLogEntryType. Information)
' Create a ThreadStart object, passing the address of objMQListener.L isten
End Try

' Set the passed data in, and place it in a new
ThreadPool element
' The treadpool takes care of managing all the thread
issues in a very
' simple way.
Dim processingutili ties As New SDRAProcessing
Dim passData As New MQPassedData
passData = newMessageBody
ThreadPool.Queu eUserWorkItem(N ew WaitCallback(Ad dressOfprocessinguti lities.ProcessM essage), passData)

' Free up memory held during processing
newMessageBody = Nothing
Catch e As ThreadInterrupt edException
'catch the ThreadInterrupt from the main thread and

exit
' Console.WriteLi ne("Exiting Thread")
Exit While
Catch excp As Exception
'Catch any exceptions thrown in receive
'MsgBox("No message received in 10 seconds")
'Console.WriteL ine(excp.Messag e)
End Try

End While

Catch e As ThreadInterrupt edException
'catch the ThreadInterrupt from the main thread and exit
'Console.WriteL ine("Exiting Thread")

End Try

'exit thread

End Sub

End Class

============= =============== =============== =============== =============== = ==
============= ===============
the following is my main processing class
============= =============== =============== =============== =============== =
==
============= ===============

Imports System.Configur ation
Imports System.Data
Imports System.IO
Imports System.Messagin g
Imports System.Threadin g
Imports System.Web.Mail
Imports CrystalDecision s.CrystalReport s.Engine
Imports CrystalDecision s.Shared

' This class handles the processing for each Sales Date Range Analysis
request
' that is received from the queue
Public Class SDRAProcessing
Private configurationAp pSettings As _
System.Configur ation.AppSettin gsReader = New _
System.Configur ation.AppSettin gsReader

' Declare local variables to store login information for the SQL
Server ' this information is read in from the configuration file which residesin
' the same directory as the service's executable module.
Private mvarDatabaseNam e As String
Private mvarServerName As String
Private mvaruserName As String
Private mvarPassword As String

' Local variables to store various parameters read in from the
configurati on file
' this information is read in from the configuration file which residesin
' the same directory as the service's executable module.
Private mvarReport As String
Private mvarCrystalName As String
Private mvarTempFileDir As String
Private mvarMailTo As String
Private mvarMailFrom As String
Private mvarMailServer As String
Private mvarWebSite As String
Private mvarStyleSheet As String
Private mvarPDFViewLoca tion As String

' Instantiate an object containing the data passed from the web page

via
the message queue
Public passData As New MQPassedData

' Local ENUMERATIONS for the EVENT ID used when writing to the Windows
Event Log
Private Enum SDRAEvent As Integer
ServiceStart = 1
ServiceStop = 2
ProcessStart = 3
ProcessStop = 4
ReloadData = 100
DeleteData = 101
ReadConfig = 200
OpenConnection = 201
CloseConnection = 202
CrystalFile = 300
CrystalLoad = 301
CrystalExport = 302
MailParamters = 400
SendMail = 401
End Enum

' This routine is ONLY called when a valid sales date range analysis
request has
' been received. Then
' 1) The requested data is loaded into a temporary database (via

the
' ReloadReportDat a routine) off of which we can perform various
reporting tasks
' 2) A PDF file containing the report is produced using interactionwith Crystal Reports.
' 3) The PDF is e-mail to the user that submitted the report
request.
'
Public Sub ProcessMessage( ByVal passedinData As Object)

' Reference the state object passed in via the ThreadPool call to
the procedure.
' this contains the data as it was passed from the web page via theMSMQ
passData = passedinData

' Write an event log message to show that we have received a valid
report request
Dim StartTime As Date = Now()
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Processing Started at : " & FormatDateTime( StartTime, DateFormat.Long Time)& " on request submitted by " & passData.UserNa me & " for sales analysis
from " & Format(passData .StartDate, "MM/dd/yyyy") & " thru " &
Format(passDa ta.EndDate, "MM/dd/yyyy") & ".",
Diagnostics.E ventLogEntryTyp e.Information, SDRAEvent.Proce ssStart)

' Get all the configuration data items and set them to local
variables.
' If there is an error, then write an event log record, and exit

the
subroutine.
Try
Report = CType(configura tionAppSettings .GetValue("SDRA .Report",GetType(Syste m.String)), String)
ServerName =
CType(configu rationAppSettin gs.GetValue("Da tabase.Server",
GetType(Syste m.String)), String)
DatabaseName =
CType(configu rationAppSettin gs.GetValue("Da tabase.Database ",
GetType(Syste m.String)), String)
UserName =
CType(configu rationAppSettin gs.GetValue("Da tabase.UserName ",
GetType(Syste m.String)), String)
Password =
CType(configu rationAppSettin gs.GetValue("Da tabase.Password ",
GetType(Syste m.String)), String)
CrystalName =
CType(configu rationAppSettin gs.GetValue("Re port.Location",
GetType(Syste m.String)), String) & Report & ".rpt"
TempFileDir =
CType(configu rationAppSettin gs.GetValue("Se llars.TempFileD irectory",
GetType(Syste m.String)), String)
MailFrom =

CType(configur ationAppSetting s.GetValue("EMa il.From",
GetType(Syste m.String)), String)
WebSite =
CType(configu rationAppSettin gs.GetValue("Se llars.WebSite",
GetType(Syste m.String)), String)
StyleSheet =
CType(configu rationAppSettin gs.GetValue("Se llars.StyleShee t",
GetType(Syste m.String)), String)
PDFViewLocation =
CType(configu rationAppSettin gs.GetValue("PD FViewReport.Loc ation",
GetType(Syste m.String)), String)
MailServer =
CType(configu rationAppSettin gs.GetValue("Em ail.SMTPServer" ,
GetType(Syste m.String)), String)
Catch ex As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error reading configuration app settings: " & ex.Message,
Diagnostics.E ventLogEntryTyp e.Error, SDRAEvent.ReadC onfig)
Exit Sub
End Try

' Call a routine to extract all the requred data from the Invoice
Master, Invoice Detail
' place it in the CustomerDateRan geMargins table, and perform all
necessary calculations
' for the report.
ReloadReportDat a()

' Populate the pre-defined Crystal Report, and export it to a PDF
stored with a unique
' file name.
CreatePDF()

' Capture the time when the report creation processing completed
Dim EndTime As Date = Now

' Mail the crystal reports PDF to the user
EMailReport(Sta rtTime, EndTime)

' Delete the temporary database tables that were used to hold the
data
DeleteReportDat a()

' Delete the PDF File that was created to keep the system clean
If File.Exists(PDF FileName()) Then
File.Delete(PDF FileName())
End If

' Write an event log message signifying that the valid message was
completely processed
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Processing completed at : " & FormatDateTime( EndTime, DateFormat.Long Time)& " on request submitted by " & passData.UserNa me & " for sales analysis
from " & Format(passData .StartDate, "MM/dd/yyyy") & " thru " &
Format(passDa ta.EndDate, "MM/dd/yyyy") & ".",
Diagnostics.E ventLogEntryTyp e.Information)
End Sub
' This routine loads in a pre-defined Crystal Report .rpt file that hasbeen set up.
' After loading the report with the correct data chosen by the user, a
PDF is created
' from the populated report and saved to disk.
Private Function CreatePDF() As Boolean
'Initialize the return value to true
Dim retvalue As Boolean = True

' Declare necessary local variables to open a Crystal Report
' and access the report parameters.
Dim crReportDocumen t As New ReportDocument
Dim crDatabase As Database
Dim crTables As Tables
Dim crTable As Table
Dim crTableLogOnInf o As TableLogOnInfo
Dim crConnectionInf o As ConnectionInfo

Dim crParameterFiel dDefinitions As ParameterFieldD efinitions
Dim crParameterValu es1 As ParameterValues
Dim crParameterDisc reteValue1 As ParameterDiscre teValue
Dim crParameterValu es2 As ParameterValues
Dim crParameterDisc reteValue2 As ParameterDiscre teValue
Dim crParameterValu es3 As ParameterValues
Dim crParameterDisc reteValue3 As ParameterDiscre teValue
Dim crParameterValu es4 As ParameterValues
Dim crParameterDisc reteValue4 As ParameterDiscre teValue

' Create an instance of the strongly-typed report object and load
the
' correct .rpt file
Dim strReport As String
strReport = CrystalName
Try
crReportDocumen t.Load(strRepor t)
Catch e As Exception
retvalue = False
' Write an event log message
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error loading .rpt template: " & e.Message,
Diagnostics.E ventLogEntryTyp e.Error, SDRAEvent.Cryst alLoad)
End Try

' Create a new instance of the connectioninfo object and
' set its properties to reference the database listed in the
configurati on settings.
crConnectionInf o = New ConnectionInfo
With crConnectionInf o
.ServerName = ServerName
.DatabaseName = DatabaseName
.UserID = UserName
.Password = Password
End With

'Get the tables collection from the report object
crDatabase = crReportDocumen t.Database
crTables = crDatabase.Tabl es

'Apply the logon information to each table in the collection
For Each crTable In crTables
crTableLogOnInf o = crTable.LogOnIn fo
crTableLogOnInf o.ConnectionInf o = crConnectionInf o
crTable.ApplyLo gOnInfo(crTable LogOnInfo)
Next

' Set the Start Date parameter value
crParameterDisc reteValue1 = New ParameterDiscre teValue
crParameterValu es1 = New ParameterValues
crParameterDisc reteValue1.Valu e = passData.StartD ate
crParameterValu es1.Add(crParam eterDiscreteVal ue1)

crReportDocum ent.DataDefinit ion.ParameterFi elds("StartDate ").ApplyCurrent V al
ues(crParamet erValues1)

' Set the End Date parameter value
crParameterDisc reteValue2 = New ParameterDiscre teValue
crParameterValu es2 = New ParameterValues
crParameterDisc reteValue2.Valu e = passData.EndDat e
crParameterValu es2.Add(crParam eterDiscreteVal ue2)

crReportDocum ent.DataDefinit ion.ParameterFi elds("EndDate") .ApplyCurrentVa l
ue
s(crParameter Values2)

' Set the Request Date parameter value
crParameterDisc reteValue3 = New ParameterDiscre teValue
crParameterValu es3 = New ParameterValues
crParameterDisc reteValue3.Valu e = passData.Report Date
crParameterValu es3.Add(crParam eterDiscreteVal ue3)

crReportDocum ent.DataDefinit ion.ParameterFi elds("RequestDa te").ApplyCurre n
tV
alues(crParam eterValues3)

' Set the UserID parameter value
crParameterDisc reteValue4 = New ParameterDiscre teValue
crParameterValu es4 = New ParameterValues
crParameterDisc reteValue4.Valu e = passData.UserID
crParameterValu es4.Add(crParam eterDiscreteVal ue4)

crReportDocum ent.DataDefinit ion.ParameterFi elds("UserID"). ApplyCurrentVal u
es
(crParameterV alues4)

' Define and set the options necessary to save the pdf file to a
disk location
Dim crDiskFileDesti nationOptions As New DiskFileDestina tionOptions
crDiskFileDesti nationOptions.D iskFileName = PDFFileName()
Dim crExportOption As ExportOptions =

crReportDocume nt.ExportOption s
With crExportOption
.DestinationOpt ions = crDiskFileDesti nationOptions
.ExportDestinat ionType = ExportDestinati onType.DiskFile
.ExportFormatTy pe = ExportFormatTyp e.PortableDocFo rmat
End With

' Export the refreshed report using the appropriate selection
criteria
' If there is an error with this process, write an appropriate
Windows Event
' Log record.
Try
crReportDocumen t.Export()
Catch e As Exception
retvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error exporting report: " & e.Message,

Diagnostics.Ev entLogEntryType .Error,
SDRAEvent.Cry stalExport)
End Try
End Function

' This function returns the physical direct file path and name of the
temporary file
' top be created and sent via e-mail
Public Function PDFFileName() As String
Return TempFileDir + PDFViewName()
End Function

' This is a unique name for a file so multiple users can access this
routine without any issues.
' A file name will be comprised of three parts:
' 1) The UserID used when the individual logged into the system.
' 2) The time that the request was submitted at the web page making
the request
' (this is necessary so the user can run multiple reports without
any problems)
' 3) The Name defined fo the report which is read in from the
configurati on file.
' (this will be the same name as the crystal report .rpt file
except we use a PDF extention)
Public Function PDFViewName() As String
Return passData.UserID + Format(passData .ReportDate,

"MMddyyhhmmss" )
+ "_" & Report & ".pdf"
End Function

' This routine is used to run a stored procedure against the
CustomerDateR angeMargins file
' and delete all records that match the UserID and Request Date. This
is typically run
' after all processing has been completed and the e-mail sent as part

of
the clean up process.
Private Function DeleteReportDat a() As Boolean
Dim m_objConn As New System.Data.Sql Client.SqlConne ction

'try to open the connection
If Not OpenConnection( m_objConn) Then
Exit Function
End If

Dim returnvalue As Boolean = True
Dim myCommand As New
SqlClient.Sql Command("Delete CustomerDateRan geMargins", m_objConn)

' Mark the Command as a SPROC
' The timeout value of zero lets all transactions run without

timing
out.
myCommand.Comma ndType = CommandType.Sto redProcedure
myCommand.Comma ndTimeout = 0

' Add Parameters to SPROC
Dim parameterReques tDate As New
SqlClient.Sql Parameter("@Req uestDate", SqlDbType.DateT ime)
parameterReques tDate.Value = passData.Report Date
myCommand.Param eters.Add(param eterRequestDate )

Dim parameterUserID As New SqlClient.SqlPa rameter("@UserI D",
SqlDbType.NVa rChar, 15)
parameterUserID .Value = passData.UserID
myCommand.Param eters.Add(param eterUserID)

' Execute the command to perform the query request on the server
' if there is a problem, then write an appropriate Windows Event

Log
record.
Try
myCommand.Execu teNonQuery()
Catch e As Exception
returnvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error deleting CustomerDateRan geMargins: " & e.Message,
Diagnostics.E ventLogEntryTyp e.Error, SDRAEvent.Delet eData)
End Try

' Free up memory
myCommand = Nothing

' close the database connection and free up memory
CloseConnection (m_objConn)
m_objConn = Nothing

' return a flag indicating if any errors occures while this was
running
Return returnvalue
End Function

' This function calls an SQL Stored procedure. This procedure:
' 1) First deletes any old records that may match the username abd
request date
' 2) Gets all the appropriate records from the Invoice Master,
Invoice Detail and
' Customer master files.
' 3) Applies additional processing to ensure all the necessary
calculation s are correct.
Private Function ReloadReportDat a() As Boolean
Dim m_objConn As New System.Data.Sql Client.SqlConne ction

'try to open the connection
If Not OpenConnection( m_objConn) Then
Exit Function
End If

Dim returnvalue As Boolean = True
Dim myCommand As New
SqlClient.Sql Command("Reload CustomerDateRan geMargins", m_objConn)

' Mark the Command as a SPROC
myCommand.Comma ndType = CommandType.Sto redProcedure
myCommand.Comma ndTimeout = 0

' Add Parameters to SPROC
Dim parameterReques tDate As New
SqlClient.Sql Parameter("@Req uestDate", SqlDbType.DateT ime)
parameterReques tDate.Value = passData.Report Date
myCommand.Param eters.Add(param eterRequestDate )

Dim parameterUserID As New SqlClient.SqlPa rameter("@UserI D",
SqlDbType.NVa rChar, 15)
parameterUserID .Value = passData.UserID
myCommand.Param eters.Add(param eterUserID)

Dim parameterStartD ate As New SqlClient.SqlPa rameter("@Start Date",
SqlDbType.Dat eTime)
parameterStartD ate.Value = passData.StartD ate
myCommand.Param eters.Add(param eterStartDate)

Dim parameterEndDat e As New SqlClient.SqlPa rameter("@EndDa te",
SqlDbType.Dat eTime)
parameterEndDat e.Value = passData.EndDat e
myCommand.Param eters.Add(param eterEndDate)

' Execute the stored procedure, and if there is an error, write an
appropriate Event Log record.
Try
myCommand.Execu teNonQuery()
Catch e As Exception
returnvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error running ReloadCustomerD ateRangeMargins : " & e.Message,
Diagnostics.E ventLogEntryTyp e.Error, SDRAEvent.Reloa dData)
End Try

' Free up memory
myCommand = Nothing

' close the database connection and free up memory
CloseConnection (m_objConn)
m_objConn = Nothing

' return a flag showing whether the report data was retrieved,
loaded and calculated appropriately.
Return returnvalue
End Function

' This routine e-mails the PDF file created above to the user that
submitted the request.
Private Function EMailReport(ByV al StartTime As Date, ByVal EndTime As
Date) As Integer
' Set all the necessary message routing and descriptive

information.
Dim myMessage As New System.Web.Mail .MailMessage
Dim strMessage As String
Try
myMessage.To = passData.EMailA ddress
myMessage.From = MailFrom
myMessage.Subje ct = "Sales Analysis from " &
Format(passDa ta.StartDate, "MM/dd/yyyy") & " thru " &
Format(passDa ta.EndDate, "MM/dd/yyyy")
myMessage.BodyF ormat = MailFormat.Html
myMessage.Prior ity = MailPriority.Hi gh
Catch e As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error assigning email data: " & e.Message,
Diagnostics.E ventLogEntryTyp e.Error, SDRAEvent.MailP aramters)
Exit Function
End Try

' Set up the message body text.
strMessage = "<html><head><l ink href='" + WebSite + StyleSheet +

"'type='text/css' rel='stylesheet '></head><body>"
strMessage = strMessage + "<Table cellspacing=0 cellpadding=0
style='bord er-collapse: collapse' bordercolor='#1 11111' width='100%'>"

' Insert a blank line
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display a header line
strMessage = strMessage + "<TR class='Text'><T D>Sales Analysis
processing was performed for data from " & Format(passData .StartDate,
"MM/dd/yyyy") & " thru " & Format(passData .EndDate, "MM/dd/yyyy") & "
</TD></TR>"

' Insert two blank lines
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display the start and end times for the processing
strMessage = strMessage + "<TR class='Text'><T D>Processing was
started at: " + FormatDateTime( StartTime, DateFormat.Long Time) +
"</TD></TR>"
strMessage = strMessage + "<TR class='Text'><T D>Processing was
completed at: " + FormatDateTime( EndTime, DateFormat.Long Time) +
"</TD></TR>"

' Insert two blank lines
strMessage = strMessage + "<TR class='Text'><T D>&nbsp;</TD></TR>"

' Display a header line
strMessage = strMessage + "<TR class='Text'><T D>The completed

report
is attached to this e-mail in a PDF format .</TD></TR>"

' End the table
strMessage = strMessage + "</table></body></html>"

' Set the body of the message to the text
myMessage.Body = strMessage

' Add the PDF File as an attachment
Dim objAttach As New MailAttachment( PDFFileName)

' try adding the attachment, and sending the message
Try
myMessage.Attac hments.Add(objA ttach)
SmtpMail.SmtpSe rver = MailServer
SmtpMail.Send(m yMessage)
Catch ex As Exception
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error sending email: " & ex.Message, Diagnostics.Eve ntLogEntryType. Error,
SDRAEvent.Sen dMail)
Exit Function
End Try

End Function

' Routine that closes the SQL connection object used to access the SQL
server.
Public Sub CloseConnection (ByVal objConnection As
System.Data.S qlClient.SqlCon nection)
Try
objConnection.C lose()
Catch e As Exception
' Write an event log message
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error closing connection: " & e.Message,
Diagnostics.E ventLogEntryTyp e.Error, SDRAEvent.Close Connection)
End Try
End Sub

' Routine that opens the SQL connection object used to access the SQL
server.
Public Function OpenConnection( ByVal objConnection As
System.Data.S qlClient.SqlCon nection) As Boolean
Dim retvalue As Boolean = True

Try
objConnection.C onnectionString = "Server=" & ServerName &
";User=" & UserName & ";Password= " & Password & "; " _
& "Database=" & DatabaseName
objConnection.O pen()
Catch e As Exception
retvalue = False
System.Diagnost ics.EventLog.Wr iteEntry("Sella rsReportService ",
"Error opening connection: " & e.Message,
Diagnostics.E ventLogEntryTyp e.Error, SDRAEvent.OpenC onnection)
End Try

Return retvalue
End Function

' Declare properties for all configuration data file items.
Private Property DatabaseName() As String
Get
DatabaseName = mvarDatabaseNam e
End Get
Set(ByVal Value As String)
mvarDatabaseNam e = Value
End Set
End Property

Private Property Password() As String
Get
Password = mvarPassword
End Get
Set(ByVal Value As String)
mvarPassword = Value
End Set
End Property

Private Property ServerName() As String
Get
ServerName = mvarServerName
End Get
Set(ByVal Value As String)
mvarServerName = Value
End Set
End Property

Private Property UserName() As String
Get
UserName = mvaruserName
End Get
Set(ByVal Value As String)
mvaruserName = Value
End Set
End Property

Private Property MailTo() As String
Get
MailTo = mvarMailTo
End Get
Set(ByVal Value As String)
mvarMailTo = Value
End Set
End Property

Private Property MailFrom() As String
Get
MailFrom = mvarMailFrom
End Get
Set(ByVal Value As String)
mvarMailFrom = Value
End Set
End Property

Private Property MailServer() As String
Get
MailServer = mvarMailServer
End Get
Set(ByVal Value As String)
mvarMailServer = Value
End Set
End Property

Private Property PDFViewLocation () As String
Get
PDFViewLocation = mvarPDFViewLoca tion
End Get
Set(ByVal Value As String)
mvarPDFViewLoca tion = Value
End Set
End Property

Private Property Report() As String
Get
Report = mvarReport
End Get
Set(ByVal Value As String)
mvarReport = Value
End Set
End Property

Private Property CrystalName() As String
Get
CrystalName = mvarCrystalName
End Get
Set(ByVal Value As String)
mvarCrystalName = Value
End Set
End Property

Private Property StyleSheet() As String
Get
StyleSheet = mvarStyleSheet
End Get
Set(ByVal Value As String)
mvarStyleSheet = Value
End Set
End Property

Private Property TempFileDir() As String
Get
TempFileDir = mvarTempFileDir
End Get
Set(ByVal Value As String)
mvarTempFileDir = Value
End Set
End Property

Private Property WebSite() As String
Get
WebSite = mvarWebSite
End Get
Set(ByVal Value As String)
mvarWebSite = Value
End Set
End Property

End Class


Nov 20 '05 #5
Howdy Cor,

I think the only part that can't be done in VB is getting someone in this
newsgroup to give a detailed response to the query as it currently stands! :-)
The C# lot seem more into heavy debating.

Regards,
Fergus
Nov 20 '05 #6
Hi Cor,

|| But by the way, I did not tell you there is a long
|| thread about multithreading in this newsgroup.

ROFL.

Thanks, I must have missed that thread somehow. :-))

Regards,
Fergus
Nov 20 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

23
2491
by: Antoon Pardon | last post by:
I have had a look at the signal module and the example and came to the conclusion that the example wont work if you try to do this in a thread. So is there a chance similar code will work in a thread? -- Antoon Pardon
12
2162
by: Joey Powell | last post by:
Re: Original post = Windows forms - how do I get them to render/update properly? from August 22. Okay I am making some progress with being able to use delegates to run my shelled processes on worker threads. Yes I have gotten it to work, kind-of - that is I have gotten the shelled processes off of the UI thread (I think?). But the UI still is not updating properly! Still I have white boxes for forms, label text that does not update, and...
1
3274
by: Mark Hoffman | last post by:
All, From what I've read, the CLR gives each App Domain a thread pool of 25 threads, and once this pool is exhausted then any new threads created with BeginInvoke will block until the pool frees up another thread. Am I right on that? I did a little test where I went into a loop and attempted to spawn 50 new worker threads with a call to BeginInvoke that used an asynchronous callback. I expected it to launch 24 threads, then block for...
3
506
by: Jacob | last post by:
I'm working on a class that needs to be called from a windows form, do it's work, and then, show progress back to the main form. I'm well aware that worker threads need to call Invoke for updates to the main thread to be threadsafe. I want to make this worker class I'm writing a self contained assembly so that other's can drop it into their projects. My question is: How can I NOT force those implementing my class to have to call...
9
23082
by: Abhishek Srivastava | last post by:
Hello All, In IIS 6.0 We have a concept of worker processes and application pools. As I understand it, we can have multiple worker process per appliction pool. Each worker process is dedicated to a pool. If I assign only one application to a applicaton pool and have multiple worker processes assigned to that pool. Will my application be processed by many worker processes?
0
8774
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9307
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9235
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8186
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6735
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4550
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3261
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2721
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2180
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.