Currently I work on a web application and part of the solution is some kind of a CMS functionality.
The main part is data driven – so content (of pages) is handled via database entries.
But there are some other things (css files, images and so on) which must be handled as what they are – as files.
Like in most of my web projects I use a control suite from telerik.
For more than 5 years I’m a customer of this company.
And their RadControls for ASP.NET AJAX helped me a lot.
And (I’m the lucky one :)) telerik made a new control at the right time.
This control adds “Explorer Feeling” to a webpage. You can see a demo here.
Anyhow – since this control is brand new there are some things missing.
But the design of the control makes it easy to add missing functionality.
My Approach was to add:
- Backup functionality (make copies of deleted / overwritten files)
- Copy files with drag and drop (the control does a move for this)
- Protect files from being deleted
- Add server side events when a file / directory is selected (the control is almost pure client Ajax)
So the first thing was to think about a way to backup files.
The solution – I encode the backup time as well as the original directory in the filename.
This allows me to have one single backup directory – and it provides a way to have multiple backups of one single file.
The encoder looks like this:
Snippet created with CBEnhancer /// <summary> /// builds a filename including directory, name and datetime /// used to build backup file names /// Example: /XFiles/Styles/Test.css becomes XFiles_Styles_Test.css_090409182223.css /// 090409182223 is datetime and will be different depending on the time the function is called /// IMPORTANT: take care of the possible filename / path length /// --if the file is in a deep path and will later be stored in a deep path the things can become long /// </summary> /// <remarks> /// The decoding could fail for files with $$u$$ in the name / path /// this sequence is used to replace underscore characters since we use these later as replacement of directory separator /// </remarks> /// <param name="strFileURL">application root started Url. examples: /Test.css /Dir1/xx.vv</param> /// <returns></returns> public static string EncodeFileURL(
string strURL) {
if (strURL ==
null) {
return (
null);
}
//a lot of the things could be done "faster" (without some declarations) - but I do it "most readable DateTime dtNow =
DateTime.Now;
string strFileDT = dtNow.ToString(
"yyMMddHHmmss");
//seconds should be enough //now the "dirty part" - we replace _ with $$u$$ since we will after it replace / with _ //the "save way" would be to encode path - part lengths also //or simply reject files with an underscore in the name :) strURL = strURL.Replace(
"_",
"$$u$$");
//we need the extension later string strExtension =
Path.GetExtension(strURL);
//now replace path separators with _ strURL = strURL.Replace(
"/",
"_");
//now build the filename - first add the encoded filename string strFinalName = strURL;
//add encoded datetime strFinalName +=
"_" + strFileDT;
//and the saved extension as last part to keep the file "functional" strFinalName += strExtension;
return (strFinalName.Substring(1));
//leave out the leading _ }
To search for files backed up from a specific directory is also easy – just reverse the path encoding
string strSearchURL = strCurURL.Replace("_", "$$u$$");
strSearchURL = strSearchURL.Replace("/", "_");
strSearchURL = strSearchURL.Substring(1); //remove leading _
strSearchURL += "*";
string[] straFiles = Directory.GetFiles(strBackupPath, strSearchURL);
strBackupPath is the file system path of the backup directory and strCurURL is the directory to search for.
To restore a file is also easy (I don’t take care about “missing directories at the moment).
There is also no need to check for it – since the function is called from a selected directory – which for sure exists.
/// <summary>
/// Restores a given file -- TODO: handle non (no longer) existing directories
/// </summary>
/// <returns></returns>
public bool RestoreFile() {
try {
string strDestPath = HttpContext.Current.Server.MapPath(FullURL);
File.Copy(BackupFilePath, strDestPath, true);
return (true);
}
catch {
return (false);
}
}
This was the “backup logic” – in the next step I’ll describe how to use this mechanism.