Creating Directories
So far we've seen the features of a typical file explorer
(with the addition of a file uploader), but since we're building a file
manager, we should also add functionality that will allow us to change the content and the structure of
the site. We're going to implement many features in this category of commands;
the first we'll see is the command to create a new directory.
Our designers want to create a toolbar with a link that,
when pressed, pops up a dialog and asks for the name of the directory to
create. As you might guess, this is not done by ASP.NET code, but rather by client-side
JavaScript code, through the prompt function. If the user presses Cancel,
nothing happens, but if the user types the name of the folder they want to create and
presses OK,
we have to pass this parameter back to the ASP.NET page that will actually
create the directory and refresh the table.
The first thought might be to redirect to the current page
and add the folder to create as a parameter in the URL. But ASP.NET is great
because of its event procedures that handle the postbacks generated by specific
controls, so why not use this cool feature? To do so, we need to have a clear
understanding about the way the form is posted back when a button or a
hyperlink control is pressed.
To demonstrate this we created a test page, which is not
part of the final application. In it we placed a HyperLink
control, as follows:
<asp:LinkButton ID="test"
runat="server" Text="Demo" OnClick="Test_Click" />
Next, we wrote an empty Test_Click
procedure in the code-behind, compiled and then ran the page. This is the HTML
code produced:
...
<a id="Test"
href="javascript:__doPostBack('Test','')">Demo</a>
...
<input type="hidden"
name="__EVENTTARGET"
value="" />
<input type="hidden"
name="__EVENTARGUMENT"
value="" />
<script
language="javascript">
<!--
function __doPostBack(eventTarget,
eventArgument) {
var theform = document.BrowseFiles;
theform.__EVENTTARGET.value
= eventTarget;
theform.__EVENTARGUMENT.value
= eventArgument;
theform.submit();
}
// -->
</script>
...
As you can see, there is nothing magic here. When the link
is pressed, instead of redirecting to another page, the __doPostBack
JavaScript function is called. The first parameter that the function requires
is the name of the control that is going to post back the form and generate the
event on the server. The second parameter may contain additional information
for the event, but it is empty in this case, and in fact the Click
event has no additional information in the standard e
parameter.
What the __doPostBack actually does is to set
two hidden input controls, with the values passed in the input. Then it submits
the form. On the server, the ASP.NET engine extracts the values of those two
hidden controls, and calls the server event handler. Again, nothing magic
but
very cool!
In conclusion, all the server controls do to post back the
form is to call the __doPostBack
function, but we can also do this by writing the HTML code by hand.
Back to our original problem: we can create a link that,
when clicked, calls a JavaScript function. This function pops up the prompt
dialog asking for a name. If the user presses OK,
the function can save the specified folder name in a hidden field, and call the
__doPostBack
function to post back the form. All done then? Almost. Remember that the first
parameter of the function is the name of the server control whose Click
event (in this case, it might be a different event for other controls) will be
raised. This control must actually exist on the page, but we can avoid setting
its Text
property and so make it invisible, and we add it just to use its associated Click
event.
Let's look at the code in the ASP.NET page, BrowseFiles.aspx,
to better explain how to do this. The code contains the JavaScript that asks
for the new directory, the LinkButton, and the hidden control
declaration:
...
<html>
<head>
<title>FileManager: Browse Files</title>
<link rel="stylesheet" href="/ThePhile/Styles/ThePhile.css"
TYPE="text/css" />
<meta name="CODE_LANGUAGE"
Content="C#">
<script language="javascript">
function CreateDir()
{
dirName = prompt('Type the name of the directory you want to
create:','');
if ((dirName) && (dirName!=""))
{
document.forms['BrowseFiles'].elements['funcParam'].value =
dirName;
__doPostBack('CreateDir',
'');
}
}
</script>
</head>
<body>
<form id="BrowseFiles" method="post"
runat="server"
enctype="multipart/form-data">
<FileManager:Header ID="Title" runat="server"
/>
<input type="hidden" id="funcParam"
runat="server">
<table class="MenuTable"
border="0" width="100%">
<tr>
<td>
<a href="javascript:CreateDir();">
<img border="0"
src="./Images/NewFolder.gif"
Alt="Create a new directory"
height="28" width="28" />
</a>
<asp:LinkButton ID="CreateDir" runat="server"
OnClick="CreateDir_Click" />
</td>
</tr>
</table>
<br>
<asp:Table runat="server" CssClass="Grid_Header_Thin"
Width="100%" ID="Table1">
<asp:TableRow>
<asp:TableCell Width="36">
<asp:Image runat="server" Height="32"
Width="32"
ImageUrl="./Images/OpenFolder.gif" />
</asp:TableCell>
The rest is unchanged...
You might be wondering
why we completely avoided setting the Text property instead of simply
setting its Visible
property to False.
The reason is that we need at least one control recognized by ASP.NET as a
control that generates postbacks through a call to __doPostBack.
Otherwise ASP.NET detects that there is no need for the __doPostBack
function and does not include it in the generated HTML code for the client,
which would cause an error when our CreateDir function calls it. A
control with the Visible="False" attribute is not created in
the HTML, and so neither is __doPostBack.
Therefore, we need to declare the control, leaving out the Visible
property, so that the JavaScript function is created. Once we have this
control, the other similar LinkButton controls we'll use later
can be made invisible by the Visible="False" attribute.
In the code-behind we first declare the hidden control used
to store the new folder name:
protected
System.Web.UI.HtmlControls.HtmlInputHidden funcParam;
Then we have the Click event handler for the CreateDir
ButtonLink:
protected void CreateDir_Click(object sender,
EventArgs e)
{
//
build the complete path (current path + new dir name)
string path = folderPath;
if
(path.EndsWith("/"))
path += funcParam.Value;
else
path += "/" + funcParam.Value;
try
{
// create the directory
Directory.CreateDirectory(Server.MapPath(path));
// refresh the page
Response.Redirect("BrowseFiles.aspx?Folder=" + folderPath);
}
catch (Exception exc)
{
StatusMessage.Text = exc.Message;
StatusMessage.Visible = true;
}
}
As usual, the possible exception is handled and an error
message is shown. If the new directory is created successfully, the page is
refreshed and the table re-filled with the updated content.
In this example we've taken advantage of both the
client-side script and the ASP.NET event handling mechanism. The following
screenshot shows the updated file manager and its dialog to enter the new
directory name:
Creating Text Files
If we allow the administrator to create directories, we must
also provide the opportunity to create text files (not empty text files of
course, but files with some content). The approach is
exactly the same as we used to implement the last command: manually calling the __doPostBack
function from a JavaScript routine executed by an image link. The new code in the ASPX page is as
follows:
...
<head>
<title>FileManager: Browse Files</title>
<link rel="stylesheet"
href="/ThePhile/Styles/ThePhile.css"
TYPE="text/css" />
<meta name="CODE_LANGUAGE"
Content="C#">
<script language="javascript">
function CreateDir()
{
... unchanged from above ...
}
function CreateFile()
{
fileName = prompt('Type the name of the file you want to create:','');
if ((fileName) && (fileName!=""))
{
document.forms['BrowseFiles'].elements[
'funcParam'].value = fileName;
__doPostBack('CreateFile',
'');
}
}
</script>
</head>
<body>
<form id="BrowseFiles" method="post"
runat="server"
enctype="multipart/form-data">
<FileManager:Header ID="Title" runat="server"
/>
<input type="hidden" id="funcParam"
runat="server">
<table class="MenuTable" border="0"
width="100%">
<tr>
<td>
<a href="javascript:CreateDir();">
<img border="0"
src="./Images/NewFolder.gif"
Alt="Create a new directory"
height="28" width="28" />
</a>
<asp:LinkButton ID="CreateDir" runat="server"
OnClick="CreateDir_Click" />
<a href="javascript:CreateFile();">
<img border="0"
src="./Images/NewFile.gif"
Alt="Create a new text file"
height="28" width="28">
</a>
<asp:LinkButton ID="CreateFile" runat="server"
OnClick="CreateFile_Click" Visible="False"/>
</td>
</tr>
</table>
...
And here's the addition for the code-behind:
protected void CreateFile_Click(object sender,
EventArgs e)
{
string path = folderPath;
if
(path.EndsWith("/"))
path += funcParam.Value;
else
path += "/" + funcParam.Value;
//
if the file already exists, do not go to the text editor
if
(File.Exists(Server.MapPath(path)))
{
StatusMessage.Text = "The file you specified already exists.";
StatusMessage.Visible = true;
}
else
// redirect to the editor page
Response.Redirect("EditFile.aspx?File=" + path +
"&CreateFile=true");
}
The code above first of all checks if the specified file
already exists (the whole path is retrieved by combining the current path and
the name specified). If so, it just shows an error message later in the
chapter we'll add the possibility to edit an existing file. Otherwise it
redirects to EditFile.aspx
with the full virtual path of the file to create as a parameter, and another
parameter, CreateFile,
set to true.
We're going to write this new page in the next section.
Building the Text File Editor
We want to build a very simple text editor that allows us to
create a new file and also to edit an existing file. The editor will just have
a multi-line textbox, a textbox for the destination path, a button to create or
update the file, and another button to discard the changes and go back to the file manager.
In VS.NET create a new web form, named EditFile.aspx,
and edit its content as follows:
<%@ Page language="c#"
Codebehind="EditFile.aspx.cs" AutoEventWireup="false"
Inherits="Wrox.WebModules.FileManager.Web.EditFile" %>
<%@ Register
TagPrefix="FileManager" TagName="Header"
src="Header.ascx" %>
<%@ Register
TagPrefix="FileManager" TagName="Footer"
src="Footer.ascx" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD
HTML 4.0 Transitional//EN" >
<html>
<head>
<title>FileManager: text editor</title>
<link rel="stylesheet"
href="/ThePhile/Styles/ThePhile.css"
TYPE="text/css" />
<meta name="CODE_LANGUAGE"
Content="C#">
</head>
<body>
<FileManager:Header ID="Title" runat="server"
/>
<form ID="EditFile" method="post"
runat="server">
<asp:Table runat="server" CssClass="Grid_General"
Width="100%">
<asp:TableRow CssClass="Grid_Header">
<asp:TableCell HorizontalAlign="Center" Text="EDIT
TEXT FILE" />
</asp:TableRow>
<asp:TableRow>
<asp:TableCell HorizontalAlign="Center">
<asp:TextBox runat="server" Width="99%"
Rows="20"
TextMode="MultiLine"
ID="FileContent" CssClass="TextBox" />
</asp:TableCell>
</asp:TableRow>
<asp:TableRow>
<asp:TableCell HorizontalAlign="Right" Text="Save
As:">
<asp:TextBox runat="server" Width="350px"
ID="SaveAsPath"
CssClass="TextBox" />
<asp:Button runat="server" Text="Save"
ID="Save"
CssClass="Button"
Width="80px" OnClick="Save_Click"
/>
<asp:Button runat="server" Text="Back to
FileManager" ID="Back"
CssClass="Button" Width="150px"
OnClick="Back_Click"
CausesValidation="False" />
</asp:TableCell>
</asp:TableRow>
<asp:TableRow>
<asp:TableCell HorizontalAlign="Right">
<asp:RequiredFieldValidator ID="ValidateSaveAsPath"
runat="server" ControlToValidate="SaveAsPath"
Display="dynamic">* The Save As path
is required
</asp:RequiredFieldValidator>
<asp:Label runat="server" ID="StatusMessage"
CssClass="StatusMessage"
Visible="False" Width="100%" />
</asp:TableCell>
</asp:TableRow>
</asp:Table>
<br>
</form>
<FileManager:Footer ID="Footer" runat="server"
/>
</body>
</html>
We added a RequiredFieldValidator control
that ensures that the SaveAsPath field is not empty when the form is
submitted. Also, when we press the Back to
FileManager button the form should not be validated, and that's why we set its CausesValidation
property to False.
The Code-behind for EditFile.aspx
The code-behind for this page is not long, and is quite
simple, but we'll show it piece by piece, starting from the beginning and including the Page_Load
procedure:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
namespace Wrox.WebModules.FileManager.Web
{
public class EditFile : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label StatusMessage;
protected System.Web.UI.WebControls.TextBox SaveAsPath;
protected System.Web.UI.WebControls.TextBox FileContent;
protected System.Web.UI.WebControls.Button
Save;
protected System.Web.UI.WebControls.Button
Back;
private void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string filePath =
Request.Params["File"];
if (filePath != null)
{
if
(Request.Params["CreateFile"] == null ||
Request.Params["CreateFile"]=="false")
{
// load the content of the
specified text file
try
{
StreamReader sr = new
StreamReader (File.Open(
Server.MapPath(filePath), FileMode.Open) );
FileContent.Text =
sr.ReadToEnd();
sr.Close();
}
catch (Exception exc)
{
StatusMessage.Text =
exc.Message;
StatusMessage.Visible = true;
}
}
// set the Save As textbox with the
path
// specified in the QueryString
SaveAsPath.Text = filePath;
}
}
The Page_Load
procedure extracts the path of the file to create or edit from the QueryString.
Then it checks if there is a CreateFile parameter set to false,
or not present at all. In both these cases it means that the file is already
present and the user does not want to create it, but rather to edit it. So the procedure opens the file,
reads its content, and shows it in a large textbox (this code is protected
within a try
catch
block as usual).
The next block of code is the procedure called when the Back to
FileManager button is pressed. Basically, it extracts the parent
folder of the file passed in the QueryString, and redirects to BrowseFiles.aspx,
pointing to the folder to browse:
protected void Back_Click(object sender, EventArgs e)
{
// redirect to the referrer URL or to
the BrowseFiles.aspx page
// if the referrer is null
string filePath =
Request.Params["File"];
if (filePath != null && filePath
!= "/")
{
int lastSlashIndex =
filePath.LastIndexOf("/");
string folderPath =
filePath.Substring(0, lastSlashIndex+1);
Response.Redirect("BrowseFiles.aspx?Folder="
+ folderPath);
}
else
Response.Redirect("BrowseFiles.aspx");
}
Finally, the last procedure is executed when the user
presses the Save
button. The file is created or updated with the new content:
protected void Save_Click(object sender, EventArgs e)
{
// save the text to the specified file
// (the file is created from scratch
even if it already exists)
try
{
string filePath = SaveAsPath.Text;
if (!filePath.StartsWith("/"))
filePath = "/" + filePath;
StreamWriter sw =
File.CreateText(Server.MapPath(filePath));
sw.Write(FileContent.Text);
sw.Close();
StatusMessage.Text = "File
successfully saved";
}
catch (Exception exc)
{
StatusMessage.Text = exc.Message;;
}
StatusMessage.Visible = true;
}
// ... other code created by default by
VS.NET for the Designer support
}
}
Note that the file is created from scratch in all cases. In
other words, if the file already exists it is overwritten by a new file.
At this point we can recompile the assembly with the new
page and switch to the browser. Click the Create a new text file icon on the
toolbar, specify any file name you want (for example MyTestFile.txt)
and confirm. This displays a page like this:
Editing Files
So, we've developed a page that allows the user to create
and edit a new text file. We will now go back to the BrowseFiles.aspx
page and add a new column with a link
to the file editor for all the
text files.
Here's the new column for the FoldersAndFilesTable
table (this is the last time you need to change it, I promise):
<asp:Table ID="FoldersAndFiles"
runat="server"
CssClass="Grid_General"
Width="100%">
<asp:TableRow CssClass="Grid_Header">
<asp:TableCell Width="36px" />
<asp:TableCell Text="Index" />
<asp:TableCell Width="25px" />
<asp:TableCell
Width="45px" />
<asp:TableCell Text="Attribs" Width="50px" />
<asp:TableCell Text="Size" Width="80px"
HorizontalAlign="Right" />
<asp:TableCell Text="Created" Width="140px" />
<asp:TableCell Text="Last Modified" Width="140px"
/>
</asp:TableRow>
</asp:Table>
Then, in the FillFoldersAndFilesTable
routine in the code-behind file, add a new empty column (cellOperations)
for the first row, which links to the parent folder, and for
all directory rows. (This is not shown here, look at the code earlier in the
chapter to see how to add columns, for example in the Displaying the Item Attributes section). We're going to add a link
for any text files that are not read-only or system files. We won't add a link
for the other files (we can't edit a GIF with a text editor).
The easiest way to decide whether a file is a text file is
by looking at its extension. If the extension is .txt,
.log,
.bat,
.cs,
.config,
.aspx,
or some other well-known text file extension, then we should be reasonably sure
that the file is a text file. We define an array - private for the entire
class -
of known extensions, as we did for associating the extensions with an icon:
private string[] textExtensions = new
string[]{".asa", ".asax",
".ascx", ".asmx", ".asp",
".aspx", ".bat", ".config", ".cs",
".css", ".disco", ".htm", ".html",
".inc", ".ini", ".log",
".sys", ".txt", ".vb", ".vbs",
".vsdisco", ".xls", ".xml"};
We could handle the list of text files in other ways, which
would integrate with the system of assigning icons to extensions. We would
create an XML file that lists the extensions for which we have an icon, where
the tag has the name of the extension, and can have a "text"
attribute that tells whether the files with that extension are editable through
our text editor. Here is an example XML file:
<extensions>
<.aspx
text="true"><aspx.gif></.aspx>
<.bmp><bmp.gif></.bmp>
<.gif><gif.gif></.gif>
<.html
text="true"><html.gif></.html>
<.zip><zip.gif></.zip>
</extensions>
This solution would provide the flexibility to add, edit and
delete extensions without the need to recompile the assembly. However, working
with an XML file is much slower than working with an array in a local private
variable, and requires more code and resources. Considering that once you've
set up a complete list of extensions you want to support you won't need to
update it frequently, employing the XML solution is probably not worth the
effort but it's an option if you want the maximum flexibility and ease of use
for the site administrator.
Now, code block that adds the child files to the table, we
declare the new cell, and check if the current file's extension is listed in
the array and if the file is write-enabled. If both conditions are satisfied the
new icon link is added to the column:
...
TableCell
cellOperations;
...
foreach (FileInfo childFile in childFiles)
{
//
create the required cells and controls
...
cellOperations = new TableCell();
int extIndex;
//
set the other cells and controls
...
//
if this file is a text file and is write-enabled, add an image
//
link that points to EditFile.aspx with its path as the parameter
extIndex = Array.IndexOf(textExtensions, childFile.Extension.ToLower());
if
(extIndex > -1 &&
(childFile.Attributes & FileAttributes.ReadOnly) !=
FileAttributes.ReadOnly &&
(childFile.Attributes & FileAttributes.System) !=
FileAttributes.System)
{
// create the link and set its properties
HyperLink linkEditFile = new HyperLink();
linkEditFile.Text = "<img src=\"./Images/Write.gif\"
height=\"16\ +
" width=\"16\" border=\"0\" alt=\"Edit
this file\">";
linkEditFile.NavigateUrl = "EditFile.aspx?File=" + location;
cellOperations.Controls.Add(linkEditFile);
}
//
add the cells to the new row
rowItem.Cells.Add(cellItemIcon);
rowItem.Cells.Add(cellItemLink);
rowItem.Cells.Add(cellDownload);
rowItem.Cells.Add(cellOperations);
...
}
Renaming Files and Directories
The next command to implement is one for renaming files or
directories. We're going to add a new button to each row in the table, except the first one, if it is the one that points to the
parent folder. When pressed, the button will pop up a prompt dialog. If the new
name is confirmed then an event will be raised on the server and handled by the
proper procedure.
We've already seen how to use JavaScript for postbacks when
we showed how to create a new directory or file. What's new here is that we're going to have an unknown
number of buttons (one for each row, used to rename the item represented by the
row where it is located) that will all raise the same event on the server. This
does not make any difference to the actual implementation we don't need to identify which row was clicked, just the original
path name.
The other difference is that we need to submit two pieces of
information the original path name, and the new name. Although we could pack
both of these parameters into a single control, adding a new hidden control
produces no overhead and makes it simpler to extract the information.
In the ASPX page we just create the new hidden control, the
JavaScript function that asks for the new name, and the invisible LinkButton
control. The links that call this function are dynamically created in the
code-behind for each file and directory.
Here's the additional code for BrowseFiles.aspx:
...
<head>
<title>FileManager: Browse Files</title>
<link rel="stylesheet"
href="/ThePhile/Styles/ThePhile.css"
TYPE="text/css" />
<meta name="CODE_LANGUAGE"
Content="C#">
<script language="javascript">
function CreateDir()
{
...
}
function CreateFile()
{
...
}
function Rename(path)
{
newName = prompt('Type the new name for this file/folder:','');
if ((newName) && (newName!=""))
{
document.forms['BrowseFiles'].elements['funcParam'].value = path;
document.forms['BrowseFiles'].elements['funcExtraParam'].value =
newName;
__doPostBack('Rename',
'');
}
}
</script>
</head>
<body>
<form id="BrowseFiles" method="post"
runat="server"
enctype="multipart/form-data">
<FileManager:Header ID="Title" runat="server"
/>
<input type="hidden" id="funcParam"
runat="server">
<input type="hidden" id="funcExtraParam"
runat="server">
<table class="MenuTable" border="0"
width="100%">
<tr>
<td>
... other LinkButtons and links for the Toolbar commands
<asp:LinkButton ID="Rename" runat="server"
OnClick="Rename_Click"
Visible="False" />
</td>
</tr>
</table>
...
We don't need to add a new column, as we're going to add the
new link to the column with the Edit File icon. However, in the
code-behind we need to create and add this column for the directories too,
because the last time we modified it we just added an empty column.
Here are the additions for the code-behind, starting with FillFoldersAndFilesTable:
...
TableCell cellOperations;
// declare the new HyperLink control
HyperLink
linkRename;
...
foreach (DirectoryInfo childDir in
childDirs)
{
...
cellOperations = new TableCell();
//
create the new link
linkRename = new HyperLink();
//
create the other columns and controls
...
//
add the Rename link. The 'D' before the file location
//
will be used to determine that the path identifies a directory
linkRename.Text = "<img src=\"./Images/Rename.gif\"
border=\"0\ +
" height=\"16\" width=\"16\"
Alt=\"Rename\">";
linkRename.NavigateUrl = "javascript:Rename('D" + location +
"');";
cellOperations.Controls.Add(linkRename);
//
add the cells to the new row
rowItem.Cells.Add(cellItemIcon);
rowItem.Cells.Add(cellItemLink);
rowItem.Cells.Add(new TableCell());
rowItem.Cells.Add(cellOperations);
rowItem.Cells.Add(cellAttributes);
rowItem.Cells.Add(cellSize);
rowItem.Cells.Add(cellCreated);
rowItem.Cells.Add(cellLastModified);
//
add the new row to the table
rowItem.ApplyStyle(styleFolderRow);
FoldersAndFiles.Rows.Add(rowItem);
}
// now add each child file
foreach (FileInfo childFile in childFiles)
{
...
cellOperations = new TableCell ();
//
create the new link
linkRename = new HyperLink();
//
create the other columns and controls
...
//
add the Rename link. The 'F' before the file location will be used
//
to determine that the path identifies a file
linkRename.Text = "<img src=\"./Images/Rename.gif\"
border=\"0\ +
" height=\"16\" width=\"16\"
Alt=\"Rename\">";
linkRename.NavigateUrl = "javascript:Rename('F" + location +
"');";
cellOperations.Controls.Add(linkRename);
//
add the Edit File icon, if the file is write-enabled
...
//
add the cells to the new row, and add the row
...
}
The only peculiarity in the code above is that a 'D' or 'F'
letter is added to the path passed to the JavaScript Rename
function. The whole string will then be passed to the server event handler,
which will determine if the path identifies a file or a folder by extracting
the first letter. This is, of course, necessary because there are two different classes one for
working with folders and one for files.
You can see this in the following procedure:
protected void Rename_Click(object sender, EventArgs e)
{
//
the first char of the first param is F if the path identifies a file,
//
D otherwise. Extract the first char to determine this
bool isFile = funcParam.Value.StartsWith("F");
//
extract the source path
string sourcePath = Server.MapPath(funcParam.Value.Substring(1));
string destPath;
try
{
if (isFile)
{
FileInfo sourceFile = new FileInfo(sourcePath);
// create the destination path: source path dir + new name
destPath = Path.Combine(sourceFile.Directory.FullName, +
funcExtraParam.Value);
// move the file = rename
sourceFile.MoveTo(destPath);
}
else
{
DirectoryInfo sourceDir = new DirectoryInfo(sourcePath);
// create the destination path: source path dir + new name
destPath = Path.Combine(sourceDir.Parent.FullName, +
funcExtraParam.Value);
// move the directory = rename
sourceDir.MoveTo(destPath);
}
// refresh the page
Response.Redirect("BrowseFiles.aspx?Folder=" + folderPath);
}
catch
(Exception exc)
{
StatusMessage.Text = exc.Message;
StatusMessage.Visible = true;
}
}
The item is moved to the current path but with a different
name, therefore it is renamed. At the end of the procedure, if no exceptions
have been raised, the table is filled with the updated content. The exception
handling is very important here: you may have loaded the page with the list of
files fifteen minutes ago, and in the meantime another administrator might have
deleted or moved some files. But you still see the old content as long as you
don't refresh the page, and if you try to rename a file/directory that no
longer exists an exception will be generated. In that case it is handled and a
message explaining the problem is shown.