Displaying the Creation and Last Modification Dates
The last two columns we want to fill are
the Created
and Last
Modified columns. We're lucky here as there's almost nothing to do, since this information is returned
by the CreationTime
and LastWriteTime
properties exposed by the DirectoryInfo and FileInfo
classes.
Here's the code to add:
foreach (DirectoryInfo childDir in
childDirs)
{
//
create the required cells and controls
...
cellCreated = new TableCell();
cellLastModified = new TableCell();
...
//
set the created and last modified date
cellCreated.Text = String.Format("{0:MM/dd/yy hh:mm tt}",
childDir.CreationTime);
cellLastModified.Text = String.Format("{0:MM/dd/yy hh:mm tt}",
childDir.LastWriteTime);
//
add the cells to the new row
...
rowItem.Cells.Add(cellCreated);
rowItem.Cells.Add(cellLastModified);
//
add the new row to the table
...
}
foreach (FileInfo
childFile in childFiles)
{
// create the required cells
...
cellCreated = new TableCell();
cellLastModified = new TableCell();
...
// set the created and last modified date
cellCreated.Text =
String.Format("{0:MM/dd/yy hh:mm tt}", +
childFile.CreationTime);
cellLastModified.Text =
String.Format("{0:MM/dd/yy hh:mm tt}", +
childFile.LastWriteTime);
// add the cells to the new row
...
rowItem.Cells.Add(cellCreated);
rowItem.Cells.Add(cellLastModified);
// add the new row to the table
...
}
We're finally done with
the code for displaying the information about items! If you now recompile the
assembly, and refresh the page in the browser, you should see something similar
to the screenshot below:
Downloading Files
When you click on an item's link, the file manager opens a
new browser window and redirects to that file. If the file is an image or HTML
file then you'll see it loaded and displayed by the browser. Instead, if it is
a file that the browser is not able to open, such as a ZIP file, it
will ask you if you want to download it. However, there are other file types
that the browser will neither load nor allow you to download. For example, with
web.config
or global.asax
you'll get an error page containing the message "This type of
page is not served". And other files, particularly ASPX
files, are processed on the server so you'll see the result of the
processing, not the source code.
We need to find a way to download a file or view its content
without resorting to FTP. We can solve this with streams.
Using streams, we can provide a file to the user 'as
is' without the interference of IIS.
We need a separate ASPX file, called download.aspx.
This takes a filename as a parameter, and returns the content of that file
unprocessed by the web server. The ASPX file has no user interface everything
is done in the code-behind. Here's the code for download.aspx.cs
Page_Load
method:
private void Page_Load(object sender, System.EventArgs e)
{
//
retrieve the path of the file to download, and create
//
a FileInfo object to read its properties
string path = Server.MapPath(Request.Params["File"]);
System.IO.FileInfo file = new System.IO.FileInfo(path);
//
clear the current output content from the buffer
Response.Clear();
//
add the header that specifies the default filename for the
//
Download/SaveAs dialog
Response.AddHeader("Content-Disposition",
"attachment;
filename=" + file.Name);
//
add the header that specifies the file size, so that the browser
//
can show the download progress
Response.AddHeader("Content-Length", file.Length.ToString());
//
specify that the response is a stream that cannot be read by the
//
client and must be downloaded
Response.ContentType = "application/octet-stream";
//
send the file stream to the client
Response.WriteFile(file.FullName);
//
stop the execution of this page
Response.End();
}
We now need to add a download button to our BrowseFiles.aspx
table. The button needs to point to Download.aspx with the appropriate
parameter:
In the BrowseFiles.aspx file we need to add a new column to the FoldersAndFiles
table:
<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 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>
In FillFoldersAndFilesTable in the code-behind we have to
create and add an empty cell for the first row, which points to the parent
folder, and for all the child directories. We've seen how to do this
previously, so we aren't going to repeat the code here. For the file rows we
create a new cell and an image that links to Download.aspx, with the appropriate
parameter:
// declare the required cells and controls
...
TableCell cellDownload;
HyperLink linkDownload;
...
// add an
empty cell for all the rows that display a directory and to
// the row
that points to the parent directory
...refer
back to see how to add empty cells to the rows...
foreach (FileInfo childFile in childFiles)
{
//
create the required cells and controls
...
cellDownload = new TableCell();
linkDownload = new HyperLink();
//
set the other cells and controls
...
//
add the link to download the file
linkDownload.Text = "<img
src=\"./Images/Download.gif\" border=\"0\ +
" height=\"16\" width=\"16\"
Alt=\"Download\">";
linkDownload.NavigateUrl = "Download.aspx?File=" + location;
cellDownload.Controls.Add(linkDownload);
//
add the cells to the new row
rowItem.Cells.Add(cellItemIcon);
rowItem.Cells.Add(cellItemLink);
rowItem.Cells.Add(cellDownload);
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(styleFileRow);
FoldersAndFiles.Rows.Add(rowItem);
}
Now when we click the download icon, the source file will be
downloaded regardless of the file type.
Uploading Files
In addition to downloading files, we also want to upload files. Although we would certainly
use FTP if we had to upload lots of files, this tool can be quite handy if you just need
to upload a couple of files.
To select the file to upload we can use the standard HTML
input control of type file. This comprises a textbox and a Browse
button, which when pressed opens the Choose File dialog that allows the
user to select a file. This control can be used and accessed in ASP.NET by
adding the
runat="server"
attribute.
In order to accept the submitted file, the form
must be declared with the attribute enctype="multipart/form-data".
Let's update our BrowseFiles.aspx page by adding this
control and a button to submit the file:
<form
id="BrowseFiles" method="post" runat="server"
enctype="multipart/form-data">
<!-- other controls as above here -->
...
<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 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>
<br>
<asp:Table
runat="server">
<asp:TableRow>
<asp:TableCell Width="80px"
Font-Bold="True" Text="Upload file:" />
<asp:TableCell>
<input type="file"
ID="UploadedFile" runat="server" size="35">
</asp:TableCell>
<asp:TableCell>
<asp:Button ID="Upload"
runat="server" Text="Upload"
CssClass="Button"
OnClick="Upload_Click"
/>
</asp:TableCell>
</asp:TableRow>
</asp:Table>
<!-- other controls as above here -->
...
</form>
If we now save the file, VS.NET should add the following
declaration to the code-behind:
public
class BrowseFiles : System.Web.UI.Page
{
protected
System.Web.UI.HtmlControls.HtmlInputFile UploadedFile;
// other controls below
...
The following code is for the Upload_Click
event handler, whose function is to upload the selected file to the current
directory, but only if a file has been selected:
protected void
Upload_Click(object
sender, EventArgs e)
{
// proceed only if a file has been specified
if (UploadedFile.PostedFile != null
&&
UploadedFile.PostedFile.FileName.Length
> 0 )
{
string destDir =
Server.MapPath(folderPath);
try
{
// save to the current directory
string fileName =
Path.GetFileName(UploadedFile.PostedFile.FileName);
UploadedFile.PostedFile.SaveAs(Path.Combine(destDir, fileName));
//
refresh the page
Response.Redirect("BrowseFiles.aspx?Folder=" + folderPath);
}
catch (Exception exc)
{
StatusMessage.Text = exc.Message;
StatusMessage.Visible = true;
}
}
}
The code is straightforward, but you should note one point:
after the file is uploaded to the server, we refresh the table by reloading the
entire page. This is necessary because in Page_Load
the table was filled, so if we called FillFoldersAndFilesTable again here
we would get all the rows twice. Since the redirection is done on the server
before any HTML code is sent to the client browser, this does not cause much
overhead.
Also note that the code that uploads the file is protected
by a try...catch
block. In case an exception occurs, for example because the current user does
not have permission to write on this directory, an error message is shown in
the StatusMessage
label.
Note
that by default the maximum size of the uploaded file is 4MB. If you try to
upload a bigger size you'll get an error page. You may want to increase this
value, for example because you have
ZIP, AVI, or MP3 files bigger than 4MB. To do so, set the maxRequestLength
attribute of the <httpRuntime> setting in the ThePhile's web.config
file. The size is specified in KB, so <httpRuntime maxRequestLength="8192"
/> sets the maximum file size to 8MB.
It's time to recompile everything and jump to the browser to
test the updated file manager. In the screenshot below you can see both the new
icons added to the files to download or open them, as well as the file input
control and the Choose file dialog: