Introduction
This is used for copying all files from source directory to destination directory using Build Task. Here it accepts configuration file and reads only destination Key in Application Settings.
Background
You should start with these posts, this should explain more principles for Microsoft.Build.Utilities.Task.
http://msdn.microsoft.com/en-us/library/ms366724.aspx
http://bartdesmet.net/blogs/bart/archive/2008/02/15/the-custom-msbuild-task-cookbook.aspx
Why use central place for templates
To have templates (XSLT, doc, etc.) for generating document in one place is good for editing when you have a lot of different components (services and applications) that uses templates. You do not need to search through servers and folders to find where templates are for simple small changes. If it is on central place you always now where to start.
If it is required to be shared across the network, again you have only one place to allow users to access templates. You will not have to adding several network sharing privileges.
Cons: this centralizing place for templates in one folder is setting build and deploys process for copy these templates to one place. In this article I will try to explain it as best I can.
How to
To set up and use this Copy Files build task you need to set in project dir:
1. Open the *.proj file.
2. Add a UsingTask element to the file and specify the details of your task. For example:
<UsingTask TaskName="FileCopyTask" AssemblyFile="$(ProjectDir)..\Assemblies\drej.CopyFiles.dll" />
3. Save the file.
4. Uncomment <Target Name="AfterBuild"></Target>
5. Add the task element to run your task inside the Target element. For example:
<Target Name="AfterBuild">
<FileCopyTask />
</Target>
6. Then setup parameters of task. It is requred to have source with destination, or source with configuration file and Config key.
Configuration Key is read from AppSettings section in config file. For Example:
<FileCopyTask SourceDirectory="$(ProjectDir)..\Templates" ConfigurationFilePath="$(ProjectDir)\App.config" ConfigurationKey="TemplateFolder" />
or
<FileCopyTask SourceDirectory="$(ProjectDir)..\Templates" DestinationDirectory="c:\DocFolder\Templates" />
7. There is one optional parameter OnlyFileTypes where can you set search pattern like this:
<FileCopyTask SourceDirectory="$(ProjectDir)..\Templates" DestinationDirectory="c:\DocFolder\Templates" OnlyFileTypes="*.xml" />
On search pattern you can find more info here: http://msdn.microsoft.com/en-us/library/wz42302f.aspx
How it is done in C#
There are two parts of solution in coping files:
1. Setup of all parameters - source directory, target directory and file types to copy
2. Coping files from source to target destination
Setup of all parameters
Source directory is set up to folder in project to relative destination. This parameter is set to required.
Required]
public string SourceDirectory { get; set; }
If destination directory is set then nothing more is required to be set up. It is just read from project file.
Other method is when Source directory is setup and also config file and then key. Here is the key that you can use environment (Dev, Testing, Release, etc.) to change value of config key and to use it during build. Here is the code for reading key from configuration file.
this.Source = SourceDirectory;
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap() { ExeConfigFilename = ConfigurationFilePath };
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
if (config.AppSettings.Settings != null
&& config.AppSettings.Settings.Count > 0
&& config.AppSettings.Settings[ConfigurationKey] != null
&& !string.IsNullOrEmpty(config.AppSettings.Settings[ConfigurationKey].Value))
{
this.Destination = config.AppSettings.Settings[ConfigurationKey].Value;
}
Coping files
Coping files after source and destination is setup is very easy. Just read all the files of the specific type (default search pattern is *.*) and copy it to destination:
FileInfo[] filesToCopy = null;
if (string.IsNullOrEmpty(OnlyFileTypes))
filesToCopy = sourceDir.GetFiles("*.*", SearchOption.AllDirectories);
else
filesToCopy = sourceDir.GetFiles(OnlyFileTypes, SearchOption.AllDirectories);
if (filesToCopy != null && filesToCopy.Count() > 0)
{
string pathToCopy = string.Empty;
foreach (var file in filesToCopy)
{
pathToCopy = file.DirectoryName.Replace(sourceDir.FullName, destinationDir.FullName);
if (!Directory.Exists(pathToCopy))
Directory.CreateDirectory(pathToCopy);
pathToCopy = Path.Combine(pathToCopy, file.Name);
try
{
Log.LogMessage(MessageImportance.High, "Copying file\nfrom: {0}\nto: {1}\n********", file.FullName, pathToCopy);
file.CopyTo(pathToCopy, true);
}
catch (Exception ex)
{
Log.LogErrorFromException(ex);
}
}
}
Summary
Why I used Microsoft.Build.Utilities.Task instead of Console App and Post Build Events!? Only one reason is that I am able to fail build from Build Task. It is easier to show info and errors with Microsoft.Build.Utilities Libraries.