1. Implementing the Worker Class
Before continuing, we need to make adjustments external to this class.
Adding a FileWorker Collection
We need to add a collection to the service that can hold the number of worker class instances we plan to create. As shown in Listing 1,
we will create five worker threads. This number is simply for example
purposes and could easily change on a dynamic basis, which I will
demonstrate shortly.
Listing 1. Declaration for the worker collection in the Tutorials service class.
Private m_WorkerThreads As New Collection
|
Adding New File Type and Input Locations
With
this implementation, we need to be able to supply five specific file
locations or a combination of file locations and file types. These
should be implemented as resource strings For a total of five input
locations, I have to add four more. Table 1 lists the locations.
Table 1. New File Type Location
Name | Value |
---|
IncomingPath2 | C:\temp\incoming2 |
IncomingPath3 | c:\temp\incoming3 |
IncomingPath4 | c:\temp\incoming4 |
IncomingPath5 | c:\temp\incoming5 |
For
the service to work properly, I need to add five unique file types. In
this implementation we want to create the additional four folders
listed previously. You can create them anywhere you wish, but make sure
that the service resources are updated to reflect their location.
2. Creating the FileWorkerOptions Class
Each instance of the FileWorker class needs to know three things:
The file input location
The file output location
The file type to process
Therefore we will add another class called FileWorkerOptions. Instead of creating another class file, we simply add the code shown in Listing 2 to the FileWorker class .vb file.
Listing 2. Adding a new property class to FileWorker.vb.
Public Class FileWorkerOptions Private m_Output As String Private m_Input As String Private m_FileType As String Public Property Output() As String Get Return m_Output End Get Set(ByVal value As String) m_Output = value End Set End Property Public Property Input() As String Get Return m_Input End Get Set(ByVal value As String) m_Input = value End Set End Property Public Property FileType() As String Get Return m_FileType End Get Set(ByVal value As String) m_FileType = value End Set End Property End Class
|
As shown in Listing 3, we now create an instance of FileWorkerOptions in the FileWorker class.
Listing 3. Create an instance of FileWorkerOptions.
Private m_FileWorkerOptions As New FileWorkerOptions
|
Updating the FileWorker Constructor
We
need to modify the constructor to reflect the required parameters that
need to be passed into the class instance when it is created. Because
these are required parameters, we must remove the parameterless
constructor. First, as shown in Listing 4, we need to pass in a reference of the ThreadActionState from the Tutorials service class as well as the FileWorkerOptions settings for each specific FileWorker class instance.
Listing 4. Update the FileWorker constructor.
Public Sub New(ByRef threadaction As ThreadActionState, ByVal _ fileworkeroptions As FileWorkerOptions) m_ThreadAction = threadaction m_FileWorkerOptions.Input = fileworkeroptions.Input m_FileWorkerOptions.Output = fileworkeroptions.Output m_FileWorkerOptions.FileType = fileworkeroptions.FileType End Sub
|
We use a reference to ThreadActionState because it is a shared instance from the Tutorials service class. When the values of the ThreadActionState are updated, we want them reflected in each FileWorker class instance so that the threads will properly react to state changes.
Because each FileWorker has its own options, we need to have these options passed into the FileWorker
class, then stored locally. We may want to expose these properties so
that we can update them on the fly. For example, pause the service,
update the options, and then continue.
Updating Our <FileWorker.ThreadFunc>
To reflect the changes to our processing based on a per FileWorker instance we have to update the <ThreadFunc> method to allow for the options we are passing into the class instance.
Listing 5. Updated FileWorker thread function.
For Each TextFile As String In My.Computer.FileSystem.GetFiles( _ m_FileWorkerOptions.Input, _ FileIO.SearchOption.SearchTopLevelOnly, _ m_FileWorkerOptions.FileType) If m_ThreadAction.Pause Or m_ThreadAction.StopThread Then Exit For End If Try Dim FileOutput As String = My.Resources.OutgoingPath + "\" + _ My.Computer.FileSystem.GetName(TextFile) My.Computer.FileSystem.MoveFile(TextFile, FileOutput) WriteLogEvent(My.Resources.ThreadMessage + TextFile, THREAD_INFO, _ EventLogEntryType.Information, My.Resources.Source) Catch ex As Exception WriteLogEvent(My.Resources.ThreadErrorMessage + Now.ToString, THREAD_ERROR, _ EventLogEntryType.Error, My.Resources.Source) End Try Next
|
Notice
that now we are using the passed-in options for Output, FileType, and
Input locations. This allows each instance of the class to monitor
different locations and different file types. In this example we are
using five different locations, one file type, and one file output
path. We could easily use one location, five file types, and five
output paths.
Before we continue to update
the code we need to create the five file type entries in our resource
file to reflect those we will monitor in our incoming paths. I have
created the following entries listed in Table 2 in my Tutorials Resource file.
Table 2. New File Type Resource Entries
Name | Value |
---|
FileType1 | *.txt |
FileType2 | *.bat |
FileType3 | *.dat |
FileType4 | *.inf |
FileType5 | *.ico |