In VB6, writing a service was usually done by the C++ gurus. Also, watching directories for file creation, movement, etc., was not easy, to say the least. Under .NET, it's a breeze!
At the company, where I work, we have thousands of files offloaded and uploaded to our FTP Server. Our SQLServer database keeps a record of work processed through our company and file movement is a major tracking component. Therefore, we must see that we record the creation of every file, of certain types. We cannot afford to miss one!. This means that we have to come as close to 100% up-time for the FileWatcher application as possible.
When we first implemented the FileWatcher, as a stand-alone program, running on a client machine, we were periodically experiencing failures due to lost connections to the server, etc. Finally, it occured to us to put a Windows Service Application on the FTP server so that as long as the server is up, the FileWatcher is running. In addition, we kept the Service as "thin" as possible, simply creating a log file of created files. We placed the database update in another program, running on a client machine, so that the Service does not have to access any thing that is not on the host server.
In this article, I will show you how to create a Windows Service application, using the FileWatcher component. Just follow these simple steps.
1. Create a new VB.NET project, of type Windows Service. You will find this project type in the Template window for Visual Basic Projects.
2. Select a name and location for your new project. I called mine "FileWatcherService."
3. When the project opens, it will have a designer, but it will not have a form. You can use this designer surface to drop any components that you need, just as if it were a form designer.
4. Open the ToolBox and click on the Components tab. There you will see, among other components, the FileSystemWatcher. Double-click the FileSystemWatcher and it will be placed on your service designer.
5. In the property window of the service designer, set the Name to fwService, to set the name of the class. Next, set the ServiceName properties to fwService, which names the service itself. You can use different names, but I made them the same. Next, set the CanStop property to True, and the CanPauseAndContinue property to True. These property settings allow the service to be paused and stopped. Finally, set the AutoLog property to True. This will cause the service to write log entries in the Application event log when it starts and stops correctly, as well as insert entries when commands do not work.
Figure 1 is the abridged listing of the code generated by the designer. I have removed the full code for brevity's sake. The code automatically generated by the designer does include two events that are called when the service starts and stops. These two events are of interest to us because that is where we will start and stop the FileSystemWatcher component. I have added two private, declaration level variables to denote the path for the FileWatcher to watch and the path and file to which the log of created files will be written.
To start the FileSystemWatcher, I need set some properties for it. I do this in the OnStart event of the service. First, I set the path that is to be watched. Since I have set the whole D: Drive, I will be notified whenever a file is created on the drive, regardless of the type of file. Again, in the service, I am keeping it as thin and free of business logic as possible. The reason for this is that all I want this service to do is to record the creation of files on the server. Business logic regarding file types that are of interest will change periodically, and I do not want to have to take the service down for debugging new changes, etc. I need the service to be up 100% if possible. In another artice, I will describe the recovery process if the service/server fails. Next, I set the IncludeSubdirectories property to true so that the whole drive is watched. Next, I set the Filter property to watch all file types. Finally, I set the EnableRaisingEvents to True, which starts the FileSystemWatcher.
In the OnStop event, I simply turn off the FileSystemWatcher. The OnPause and OnContinue events mirror the OnStop and OnStart events.
Figure 1 - fwService Class.
| Public Class fwService Inherits System.ServiceProcess.ServiceBase ' Component Desiner Generate code omitted. ' Path for the file wathcer to watch. The D: drive is the FTP server drive Private Path As String = "D:\" ' Path for the FileWatcher log of created files to be written Private TxtFilePath As String = "D:\FileWatcherFiles\FileWatcher.Txt" Protected Overrides Sub OnStart(ByVal args() As String) ' Add code here to start your service. This method should set things ' in motion so your service can do its work. Try Me.FileSystemWatcher1.Path = Path Me.FileSystemWatcher1.IncludeSubdirectories = True Me.FileSystemWatcher1.Filter = "*.*" Me.FileSystemWatcher1.EnableRaisingEvents = True Catch ex As System.Exception StructuredErrorHandler(ex) End Try End Sub Protected Overrides Sub OnStop() ' Add code here to perform any tear-down necessary to stop your service. ' start receiving file created events Try Me.FileSystemWatcher1.EnableRaisingEvents = False Catch ex As System.Exception StructuredErrorHandler(ex) End Try End Sub Protected Overrides Sub OnPause() Try Me.FileSystemWatcher1.EnableRaisingEvents = False Catch ex As System.Exception StructuredErrorHandler(ex) End Try End Sub Protected Overrides Sub OnContinue() Try Me.FileSystemWatcher1.Path = Path Me.FileSystemWatcher1.IncludeSubdirectories = True Me.FileSystemWatcher1.Filter = "*.*" Me.FileSystemWatcher1.EnableRaisingEvents = True Catch ex As System.Exception StructuredErrorHandler(ex) End Try End Sub |
| Private Sub FileSystemWatcher1_Created(ByVal sender As Object, _ ByVal e As System.IO.FileSystemEventArgs) _ Handles FileSystemWatcher1.Created ' record the receipt of the file ' unless it is a temporary file created by Microsoft Word ' also ignore the creation of the file in which I am writing the ' log of files Dim FileTime As String Try If e.FullPath.ToUpper.IndexOf("FILEWATCHERFILES") > -1 OrElse _ (e.FullPath.ToUpper.IndexOf("~WRD") > -1 And _ e.FullPath.ToUpper.IndexOf(".TMP") > -1) Then Exit Sub End If Catch Exit Sub End Try Try FileTime = FileDateTime(e.FullPath).ToString Catch FileTime = Now.ToString End Try Try LogFilesAndErrors("TM:" & vbTab & FileTime & vbTab & "FN: " & _ vbTab & e.FullPath) Catch ' an error here is caused by the log method, and there is nothing to do End Try End Sub |
| Private Sub LogFilesAndErrors(ByVal FullPath As String, _ Optional ByVal Time As String = "") ' this method will open the sql error file and append the sql to the file Dim i As Integer Dim start As Integer Dim h As Integer Dim sLine As String If Time.Length = 0 Then Time = Now.ToString sLine = FullPath For i = 1 To 100 If System.IO.File.Exists(TxtFilePath) Then ' file renamed, create a new one. Try h = FreeFile() FileOpen(h, TxtFilePath, OpenMode.Output, OpenAccess.Write, _ OpenShare.LockWrite) PrintLine(h, sLine) FileClose(h) Exit Sub Catch End Try Else Try h = FreeFile() FileOpen(h, TxtFilePath, OpenMode.Append, OpenAccess.Write, _ OpenShare.LockWrite) ' we have the file, write the sql and close the file PrintLine(h, sLine) FileClose(h) Exit Sub Catch End Try End If End If start = Microsoft.VisualBasic.Timer Do While Microsoft.VisualBasic.Timer - start < 1 DoEvents() Loop Next i End Sub |