The File Manager's Main Page
Before starting to write the code for this page, which is
quite long, let's see how the page will look when it is finished. The
screenshot below shows the main page of the finished FileManager while it
is browsing the content of the ThePhile web directory:
The page lists the directories first and then the files.
Clicking the name of an item navigates to that subdirectory or file. For each
item the page shows quite a lot of information, aligned by several columns, and
some image buttons that allow us to rename the item, edit its attributes, edit
a file's content, or download a file. The screenshot describes all the links so
you should have no problems understanding how this interface works.
We can now start writing the page that will actually allow
the administrator to navigate the site. We'll develop it piece by piece,
starting from a simple explorer that just shows the directories and files, and
progressively adding more and more information and commands.
First of all, create a new web form called BrowseFiles.aspx,
and add the following code:
<%@ Page
language="c#" Codebehind="BrowseFiles.aspx.cs"
AutoEventWireup="false"
Inherits="Wrox.WebModules.FileManager.Web.BrowseFiles" %>
<%@ Register
TagPrefix="FileManager" TagName="Footer"
src="Footer.ascx" %>
<%@ Register
TagPrefix="FileManager" TagName="Header"
src="Header.ascx" %>
<!DOCTYPE HTML
PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>FileManager: Browse
Files</title>
<link rel="stylesheet"
href="/ThePhile/Styles/ThePhile.css"
type="text/css">
<meta name="CODE_LANGUAGE"
Content="C#">
</head>
<body>
<form id="BrowseFiles"
method="post" runat="server">
<FileManager:Header
ID="Title" runat="server" />
<br>
<asp:Table runat="server"
CssClass="Grid_Header_Thin"
Width="100%">
<asp:TableRow>
<asp:TableCell
Width="36">
<asp:Image
runat="server" Height="32" Width="32"
ImageUrl="./Images/OpenFolder.gif" />
</asp:TableCell>
<asp:TableCell>
<asp:Label
runat="server" ID="FolderDescription"/>
</asp:TableCell>
</asp:TableRow>
</asp:Table>
<asp:Table
ID="FoldersAndFiles" runat="server"
CssClass="Grid_General"
Width="100%">
<asp:TableRow CssClass="Grid_Header">
<asp:TableCell
Text="Index" />
</asp:TableRow>
</asp:Table>
<br>
<asp:Label
ID="StatusMessage" runat="server"
CssClass="StatusMessage"
Visible="False" Width="100%" />
<asp:Label ID="FolderStyle"
runat="Server"
Text="Grid_Item"
Visible="false" />
<asp:Label ID="FileStyle"
runat="Server"
Text="Grid_AlternatingItem"
Visible="false" />
</form>
<FileManager:Footer ID="Footer"
runat="server" />
</body>
</html>
At this point the page does not contain many controls.
We'll add others along the way, but it's worth describing each of them briefly
here:
q
The table at the top of the page has two columns. The
first one shows an icon representing an open folder, while the cell on the
right has a label that will be set dynamically to show the virtual and physical
path of the folder whose content is currently listed on the page.
q
The second table, named FoldersAndFiles,
is the table where we'll actually show the current folder's subdirectories and
files. At this point it has just one column for the item name (file or
directory). Later in the chapter we'll add more columns for item attributes and
command buttons.
q
The StatusMessage label is used to
display text representing errors and exceptions.
q
The FileStyle and FolderStyle
controls are two invisible labels. They are only used to store the name of the
style for the rows that will be dynamically created from the code-behind class,
to display files or folders respectively. Instead of hard coding such settings
in the compiled assembly, we want to leave them in the ASPX page (which can be
easily modified without the need to recompile anything) and retrieve them later
in the code-behind.
Listing the Contents of a Folder
It's time to write the code that shows the contents of the
selected folder in the table. Most of the following code-behind code, BrowseFile.aspx.cs,
is auto-generated by VS.NET. The procedure we need
to focus on is Page_Load.
The virtual path of the folder to scan is passed along with
the page URL, as a parameter called Folder. If not specified, the website
root is taken as the default. The procedure gets the parameter value, stores it
in a private variable, folderPath, and shows the virtual and
physical path in the description table at the top of the page.
A second routine, called FillFoldersAndFilesTable, is then
executed, and that is the one that finally scans the folder. Even though at
this point the result just shows the folder and file names, with no additional
information, the code for FillFoldersAndFilesTable is quite
long, so we've left it out for the time being. Here is the remainder of the
class:
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 BrowseFiles : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Table FoldersAndFiles;
protected System.Web.UI.WebControls.Label FolderDescription;
protected System.Web.UI.WebControls.Label FolderStyle;
protected System.Web.UI.WebControls.Label FileStyle;
protected System.Web.UI.WebControls.Label StatusMessage;
protected System.Web.UI.WebControls.Table Table1;
private string folderPath;
private void Page_Load(object
sender, EventArgs e)
{
// extract from the querystring the path to scan
folderPath = Request.Params["Folder"];
if (folderPath == null || folderPath=="/")
folderPath = Request.ApplicationPath.ToString();
// if the folder is not "/" but it ends with "/",
remove the last /
else if
(folderPath.EndsWith("/"))
folderPath = folderPath.Substring(0,
folderPath.Length-1);
// write the physical and virtual path
FolderDescription.Text = "Virtual folder: " + folderPath +
"<br>Physical folder: " + Server.MapPath(folderPath);
// actually scan the specified folder
FillFoldersAndFilesTable();
}
private void FillFoldersAndFilesTable()
{
//to be added next...
}
public BrowseFiles()
{
Page.Init += new System.EventHandler(Page_Init);
}
private void Page_Init(object
sender, EventArgs e)
{
InitializeComponent();
}
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
}
}
Let's now fill in the code for the FillFoldersAndFilesTable
procedure, one part at a time. It begins by retrieving the collection of child
files and sub directories for the folder stored in the
private folderPath
variable:
private void
FillFoldersAndFilesTable()
{
string location;
DirectoryInfo parentDir;
DirectoryInfo[] childDirs;
FileInfo[] childFiles;
try
{
parentDir = new DirectoryInfo(Server.MapPath(folderPath));
// get all the child directories and files
childDirs = parentDir.GetDirectories();
childFiles = parentDir.GetFiles();
}
catch (Exception exc)
{
StatusMessage.Text = exc.Message;
StatusMessage.Visible = true;
return;
}
The code is protected within a try
catch
block, so in cases where the folderPath folder does not exist an
error message is shown and the procedure exits gracefully.
Next, the procedure checks whether the current folder is the
site root. If it is not, the first row in the table must be a link to the
parent folder, whose path is retrieved by removing the part after the last
"/"
character (remember that we're working with a virtual path here, so we cannot
use Directory.GetParent
as we would do with a physical path):
TableRow rowItem;
TableCell cellItemLink;
HyperLink linkItem;
Style styleFolderRow = new Style();
styleFolderRow.CssClass = FolderStyle.Text;
Style styleFileRow = new Style();
styleFileRow.CssClass = FileStyle.Text;
Style styleLink = new Style();
styleLink.CssClass = "GridLink";
//
if the current folder is not the root, add the FolderUp icon and link
if
(folderPath != "/")
{
rowItem = new TableRow();
cellItemLink = new TableCell();
linkItem = new HyperLink();
// add the link that points to the parent directory
linkItem.Text = " ...";
int lastSlashIndex = folderPath.LastIndexOf("/");
location = folderPath.Substring(0,lastSlashIndex);
if (location.Length==0) location="/";
linkItem.NavigateUrl = "BrowseFiles.aspx?Folder=" + location;
linkItem.ApplyStyle(styleLink);
cellItemLink.Controls.Add(linkItem);
// add the cell to the new row
rowItem.Cells.Add(cellItemLink);
// add the row to the table
rowItem.ApplyStyle(styleFolderRow);
FoldersAndFiles.Rows.Add(rowItem);
}
Now we cycle through the childDirs collection and add the name
of all the child directories. The name text links to BrowseFiles.aspx,
with the Folder
parameter set to the folderPath plus the name of the childDirs
collection's current folder:
//
add all the child directories first
foreach (DirectoryInfo childDir in childDirs)
{
// create the required cells and controls
rowItem = new TableRow();
cellItemLink = new TableCell();
linkItem = new HyperLink();
// create the link that points to this sub-directory
linkItem.Text = childDir.Name;
location = folderPath;
if (location.EndsWith("/"))
location += childDir.Name;
else
location += "/" + childDir.Name;
linkItem.NavigateUrl = "BrowseFiles.aspx?Folder=" + location;
linkItem.ApplyStyle(styleLink);
cellItemLink.Controls.Add(linkItem);
// add the cell to the new row
rowItem.Cells.Add(cellItemLink);
// add the new row to the table
rowItem.ApplyStyle(styleFolderRow);
FoldersAndFiles.Rows.Add(rowItem);
}
Note that, as for the previous piece of code, the
dynamically created cell is added to a new row, which is added to the table's Rows
collection.
The code that cycles through the collection of child files
is very similar to the code just shown, except that the link behind the name of
each file opens a new window to display the file (letting the web browser
select how to display it):
//
now add each child file
foreach (FileInfo childFile in childFiles)
{
// create the required cells and controls
rowItem = new TableRow();
cellItemLink = new TableCell();
linkItem = new HyperLink();
int extIndex;
// create and add the link that points to this file in a new window
linkItem.Text = childFile.Name;
location = folderPath;
if (location.EndsWith("/"))
location += childFile.Name;
else
location += "/" + childFile.Name;
linkItem.NavigateUrl = location;
linkItem.Target = "_blank";
linkItem.ApplyStyle(styleLink);
cellItemLink.Controls.Add(linkItem);
// add the cell to the new row
rowItem.Cells.Add(cellItemLink);
// add the new row to the table
rowItem.ApplyStyle(styleFileRow);
FoldersAndFiles.Rows.Add(rowItem);
}
}
The code that allows the basic navigation functionality is
now complete, and we can finally compile the assembly and run the page. If you
set BrowseFiles.aspx
as the Start
Page (right click on the file in the Solution Explorer and click
the respective command) the project is automatically compiled and the page is
run when you press F5.
Otherwise open Internet Explorer and navigate to http://localhost/ThePhile/Modules/FileManager/BrowseFiles.aspx.
The screenshot below represents what you should see if you
use the file manager to navigate to the ThePhile folder: