Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

File Watcher that Auto Moves Your Working Files from the VS.NET Project Folder

0.00/5 (No votes)
23 Feb 2006 1  
An article on separating your working file from Visual Studio .NET 2003 solutions.

Sample Image - WenjunSFW.jpg

Introduction

Visual Studio .NET 2003 and its earlier versions are great, and are becoming the first choices for .NET application developers. You create a new project, and then develop and compile the code. But, there is a pain when you want to deploy your working file to production. Although you can create a deployment project to build the MSI installation, in many cases, you don't want to build the MSI. Instead of a bunch of junk files mixed with your working files in your project folder, you simply want to have a clean folder containing only the working folders/files and hand it over to your clients.

When you create a project with Visual Studio .NET 2003, it will generate several files automatically:

xxx.csproj
xxx.csproj.user
xxx.sln
xxx.suo
AssemblyInfo.cs
...

If your project is linking with SourceSafe, you will have more junk files. These files normally need not be included in your application when you ship your application to clients.

Suppose you have a very big project that consists of several projects; to separate the working files from these projects/solutions is a big pain.

This article tries to demonstrate how to solve this issue. I have built a file watcher object to monitor the project root folder; whenever a file/folder created, deleted, renamed, or hanged, it will move this file/folder to a separate destination (project release folder).

In this case, the working files/folders will be moved to the destination while your are developing. At the time your development is done, your clean working folder has been created. You just copy the whole destination folder and deploy it to your client. Sounds good?

Background

The general ideas to solve this issue are:

  1. Define two folders:
    • FROM: the root folder of your developing project.
    • TO: the deployment folder to which you want to deploy your application.

      This folder contains two sub folders: Engine and Bin. Engine is used for content files and related folders. Bin is used for all .dll and .pdb files.

  2. Create a configuration file indicating where and how to process your project. The configuration file is in XML format as follows:
    <Watchers>
      <Watcher>
       <Source>c:\filewatcher\testfolder\from</Source>
       <ProjectDestination>c:\filewatcher\testfolder
                      \to\Bin</ProjectDestination>
       <EngineDestination>c:\filewatcher\testfolder
                      \to\Engine</EngineDestination>
       <FileExtensions>dll,pdb,ascx,xml,gif,jpeg,dis,js,xsl,
                       xls,htc,txt,config,asp,aspx,asmx</FileExtensions>
       <Events>Created,Changed,Renamed,Deleted</Events>
       <Trace>yes</Trace>
      </Watcher>
    </Watchers>
  3. Build a file watcher to monitor the FROM folder; based on the configuration file, it moves/changes the files/folders from the source folder to the destination folder.

Using the code

There is only one class to perform the file monitoring job: FileWatcher. There are three important methods in this class: ProcessWatcher, ProcessTask, and CopyDeleteFile. I will describe these methods one by one.

ProcessWatcher creates the instance of the watcher object. It creates four events: FileChanged, FileCreated, FileReNamed, and FileDeleted. In the configuration file, you specify which event you want to track.

/// <summary>

/// Create the instance of the watcher object

/// and fire the monitoring events.

/// After this method has executed,

/// the process is ready to monitor

/// </summary>

private void ProcessWatcher()
{
    sourcePath = GetWatcherInfo("Source");
    pDestinationPath = GetWatcherInfo("ProjectDestination");
    eDestinationPath = GetWatcherInfo("EngineDestination");
    watchFileExtension = GetWatcherInfo("FileExtensions");
    trace = GetWatcherInfo("Trace").ToLower();
    string eventName = GetWatcherInfo("Events");
    string [] arrEvents = eventName.Split(",".ToCharArray());
    int i = 0;

    pDest = pDestinationPath.Split(";".ToCharArray());

    WatchFile = new FileSystemWatcher(sourcePath, "*");
    WatchFile.IncludeSubdirectories = true;
    WatchFile.NotifyFilter = NotifyFilters.Size | 
              NotifyFilters.LastWrite | 
              NotifyFilters.FileName | 
              NotifyFilters.DirectoryName;

    for (i=0;i<arrEvents.Length;i++)
    {
        switch(arrEvents[i])
        {
            case "Changed":
                WatchFile.Changed += new 
                       FileSystemEventHandler(FileChanged);
                break;
            case "Created":
                WatchFile.Created += new 
                       FileSystemEventHandler(FileCreated);
                break;
            case "Renamed":
                WatchFile.Renamed += new 
                       RenamedEventHandler(FileReNamed);
                break;
            case "Deleted":
                WatchFile.Deleted += new 
                       FileSystemEventHandler(FileDeleted);    
                break;
        }
    }

    WatchFile.EnableRaisingEvents = true;
}

Whenever the watcher fires an event, it then goes here to check what kind of process to execute.

/// <summary>

/// Decide what kind of process needs to perform

/// </summary>

/// <param name="e">FileSystemEventArgs event argument</param>

/// <param name="checkType">Fired event type</param>

/// <param name="fileOrFolder">Is this a file or folder?</param>

private void ProcessTask(FileSystemEventArgs e, 
                         string checkType, string fileOrFolder)
{
    string fileName = string.Empty;
    fileName = GetNameOnly(e.Name);

    switch(checkType)
    {
        case "Created":
            CheckFolder(e.Name, fileName, fileOrFolder);
            CopyDeleteFile(e.FullPath, e.Name, fileName, 
                           "", fileOrFolder, false);
            break 
        case "Changed":
            CopyDeleteFile(e.FullPath, e.Name, fileName, 
                           "", fileOrFolder, false);
            break 
        case "Deleted":
            if (fileOrFolder == "file")
            {
                for (int i=0;i<pDest.Length;i++)
                {
                    File.Delete(pDest[i] + "\\" + fileName);
                    File.Delete(pDest[i] + "\\" + e.Name);
                }
            }
            else
            {
                Directory.Delete(eDestinationPath + 
                                 "\\" + e.Name, true);
            }
            break 
        default:
            break 
    }

    if (trace == "yes")
        WriteLog(e, checkType);
}

Finally, the execution method CopyDeleteFile: if it's a rename request, this method deletes the mapping file in the destination folder first, then copies the renamed file to the destination mapped folder. If the file type is a folder, it does the same behavior as for a file.

/// <summary>

/// Whenever a file/folder has been renamed, deleted, created or modified, 

/// the destination will do the same process accordingly.

/// </summary>

/// <param name="source">The folder path is been monitoring</param>

/// <param name="watchedNamePath">The changed file/folder path</param>

/// <param name="fileName">Destination file path to be mapped</param>

/// <param name="oldName">Destination file/folder

///       path before the name changing.</param>

/// <param name="fileOrFolder">Indicates the

///           monitored object is a file or folder</param>

/// <param name="isRename">Is this fried for rename?</param>

private void CopyDeleteFile(string source, string watchedNamePath, 
        string fileName, string oldName, 
        string fileOrFolder, bool isRename)
{
    //Copy to project directory

    if(fileName.IndexOf(".dll") > 0 || fileName.IndexOf(".pdb") > 0)
    {
        for (int i=0;i<pDest.Length;i++)
        {
            File.Delete(pDest[i] + "\\" + fileName);
            File.Copy(source, pDest[i] + "\\" + fileName, true);
            File.SetAttributes(pDest[i] + "\\" + fileName, 
                                   FileAttributes.Normal);
        }
    }
    else
    {
        //Copy to engine directory. Only copy when file changed
        if (oldName == "" && fileOrFolder == "file")
        {
            File.Copy(source, eDestinationPath + "\\" + 
                              watchedNamePath, true);
            File.SetAttributes(eDestinationPath + "\\" + 
                               watchedNamePath, FileAttributes.Normal);
        }
        else
        {
            if (fileOrFolder == "file")
            {
                File.Delete(eDestinationPath + "\\" + oldName);

                if (isRename)
                    File.Copy(source, eDestinationPath + 
                          "\\" + watchedNamePath, true);
            }
            else if (fileOrFolder == "folder" && oldName != "")
            {
                Directory.Move(eDestinationPath + "\\" + oldName, 
                      eDestinationPath + "\\" + watchedNamePath);
            }
        }
    }
}

To Run the Demo Program

Download the demo Zip file and unzip it to your c: drive. Open the root FileWatchDemo folder, you should see the following files and folders:

c:\FileWatcherDemo\TestFolder
C:\FileWatcherDemo\CustomWatcher.config
C:\FileWatcherDemo\FileWatcher.exe

Double click the FileWatcher.exe, and copy a DLL to the C:\FileWatcherDemo\TestFolder\From folder. You should see that this DLL has been added into the C:\FileWatcherDemo\TestFolder\To\bin folder.

Copy a GIF file to the C:\FileWatcherDemo\TestFolder\From folder, you should see this GIF file has been added into the C:\FileWatcherDemo\TestFolder\To\engine folder.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here