Tuesday, October 21, 2008

Build a DotNetNuke FileManager in ASP.NET

Build a DotNetNuke FileManager in ASP.NET
Tutorial and Code Sample on building a DotNetNuke FileManager in ASP.NET

Introduction

If you have been playing around with DotNetNuke, you can probably agree with me that they have a very good FileManager that you can use it to upload your file,editing your file, downloading your file without have to use FTP or Remote Desktop. All the file manipulation such as Zip, Rename, Delete,Cut and Copy can be done easily using their web based file manager.

In the sample below, I will guide and show you how we can develop a file manager with the same functionality like what you have in your DotNetNuke applications. I also noticed that one of the ASP.NET web hosting company are using a Dotnetnuke like file manager in their control panel. You can test out the demo yourself.


Building DotNetNuke FileManager using DataGrid and ASP.NET 2.

In the example below, we will be using ASP:TreeView Control and ASP:DataGrid Control. You can actually change it to ASP:GridView control if you prefer. Also, I haven't implemented AJAX version for this File Manager, When you got time, you can actually rewrite it yourself and I will be very happy if you could complete the AJAX version and send it to me.

The Filemanager in the example can only be used if you are browsing less than thousands directories and subdirectories,as if you try to browse more than thousand, then it will cause your CPU goes 100%. The reason is because no AJAX yet being implemented, Therefore on every page request, it will actually rebind the whole directories and file into the TreeView and the Grid.

The ScreenShot for the FileManager will be like this. You can actually change the design easily by using CSS.



From the Screen Shot, you can see that we cover up most of the features that you needed inside the FileManager, such as Zip, Unzip, Copy File, Paste File, Cut File,Download File and Delete File.
For the Zip and Unzipping features, we will rely on third party component called ICSharpZipLib.
Search on the Google and you can find free download for the dll.

First, let's start by create new ASPx file called FileManager.aspx. Drag the ASP.NET DataGrid Control and TreeView Control from your toolbox to your web page.

Since the example covers quite a lot of code, and it is impossible for me to explain one by one here. So I will just go through few important code here.

If you can see from the screen shot, Left handside column of the table will host a TreeView Control while the right side will host a DataGrid control

The TreeView Control will only bind to the Directories and SubDirectories and the DataGrid will only bind to the files.

The Code Logic is as follows

private void BindTree()
{
TreeView1.Nodes.Clear();
string rootFolder = BaseDir;
TreeNode rootNode = new TreeNode();
rootNode.Text = BaseDir;
rootNode.Expanded = true;
rootNode.Value = rootFolder.Replace("\\", "~").Replace(" ", "|");
TreeView1.Nodes.Add(rootNode);
TreeView1.ShowLines = true;
BuildTreeDirectory(rootFolder, rootNode);
}

private void BuildTreeDirectory(string dirPath, TreeNode parentNode)
{
string[] subDirectories = Directory.GetDirectories(dirPath);
foreach (string directory in subDirectories)
{
string[] parts = directory.Split('\\');
string name = parts[parts.Length - 1];
TreeNode node = new TreeNode();
node.Text = name;
node.ImageUrl = "images/folder.gif";
node.Expanded = false;
parentNode.ChildNodes.Add(node);
BuildSubDirectory(directory, node);
}
}

private void BuildSubDirectory(string dirPath, TreeNode parentNode)
{
string[] subDirectories = Directory.GetDirectories(dirPath);
foreach (string directory in subDirectories)
{
string[] parts = directory.Split('\\');
string name = parts[parts.Length - 1];
TreeNode node = new TreeNode();
node.Text = name;
node.ImageUrl = "images/folder.gif";
parentNode.ChildNodes.Add(node);
node.Expanded = false;
BuildSubDirectory(directory, node);
}

From the code above, you can see that we are binding the Trees
Recursively and this is actually very resource intensive and not good
if you have lots of nested directories and subdirectories. You can
implement AJAX features for the TreeView Control, so that it only loads

private void BindGrid()
{
DirectoryInfo dirinfo = new DirectoryInfo(GetFolderPath());
FileInfo[] info = dirinfo.GetFiles();
DataTable dt = CreateDataSource();
DataRow dr;
if (info.Length != 0)
{
foreach (FileInfo f in info)
{
dr = dt.NewRow();
dr["filename"] = f.Name;
dr["size"] = (int)f.Length / 1024;
DSize = DSize + (int)f.Length / 1024;
dr["type"] = "1";
dr["Date"] = DateTime.Parse(f.LastWriteTime.ToString()).ToString("MM/dd/yyyy");
dt.Rows.Add(dr);
}
}
else
{
dt.Clear();
lblCounter.Text = "";
lblSpaceUsed.Text = "";
}
dgData.DataSource = dt;
dgData.DataBind();
lblError.Text = "";
lblCounter.Text = dgData.Items.Count.ToString() + " object(s)";
lblSpaceUsed.Text = "Used: " + DSize.ToString() + " Kb";

From the code above, you can see that we are binding the grid using the
DirectoryInfo.GetFiles() Method. And as you probably know GetFiles()
method will list out all the files you have on the directory, and
therefore if you have lots of files under the directory, the
performance of the Filemanager will be very slow. The workaround for
this is to implement Paging. However, Until now, I haven't got time to
find and research how to do this. If you guys are so kind enough,

private void Copy(bool cut)
{
try
{
Hashtable ht = new Hashtable();
foreach (DataGridItem dgi in dgData.Items)
{
CheckBox chkChecked = (CheckBox)dgi.FindControl("chkChecked");
if (chkChecked.Checked)
{
LinkButton lnkName = (LinkButton)dgi.FindControl("lnkName");
int type = 1;
ht.Add(Path.Combine(GetFolderPath(), lnkName.Text), type.ToString());
Session["copiedFiles"] = ht;
Session["copied"] = !cut;
}
}
ShowBufferStatus();
}
catch (Exception ex)
{
lblError.Text = ex.Message;
}
}
private void Paste()
{
try
{
if (Session["copiedFiles"] != null && Session["copied"] != null)
{
Hashtable ht = (Hashtable)Session["copiedFiles"];
bool copied = (bool)Session["copied"];
foreach (DictionaryEntry de in ht)
{
if (int.Parse(de.Value.ToString()) == 0)
{
Directory.CreateDirectory(
Path.Combine(GetFolderPath(), Path.GetFileName(de.Key.ToString())));
CopyDirectory(de.Key.ToString(),
Path.Combine(GetFolderPath(), Path.GetFileName(de.Key.ToString())));
if (!copied)
{
Directory.Delete(de.Key.ToString(), true);
}
}
else
{
if (copied)
{
File.Copy(de.Key.ToString(),
Path.Combine(GetFolderPath(), Path.GetFileName(de.Key.ToString())), true);
}
else
{
File.Move(de.Key.ToString(),
Path.Combine(GetFolderPath(), Path.GetFileName(de.Key.ToString())));
}
}
}
}
BindGrid();
}
catch (Exception ex)
{
lblError.Text = ex.Message;
}

Copy File and Paste File seems quite easy to code. Now, the challenge
comes if you want to write the code for Copying Entire Directory. For

private void CopyDirectory(string from, string to)
{
DirectoryInfo inf = new DirectoryInfo(from);
foreach (FileInfo fileinf in inf.GetFiles())
{
fileinf.CopyTo(Path.Combine(to, fileinf.Name));
}
foreach (DirectoryInfo newinf in inf.GetDirectories())
{
Directory.CreateDirectory(Path.Combine(to, Path.GetFileName(newinf.FullName)));
CopyDirectory(newinf.FullName, Path.Combine(to, Path.GetFileName(newinf.FullName)));
}

From the code above, you can see that the method call itself
recursively to copy the file and subdirectories inside the Directory

Conclusion


You can try the code yourself by download the source code below. I have provided full source code, and if you have time to make the FileManager perform better especially if you can make it AJAX enabled and Paging enabled for the grid, I would be very grateful.Please reply using the Comments features below if you have finished done that.
I have also try to follow the DotNetNuke File manager, although some of the features still not yet there.
But this one should work fine if you plan to use it to browse only small subset of files. And you can also upload this source code to your hosting folder, so you don't need FTP anymore to upload and download file. You can also do zip and unzipping your files.
But please remember to change the Web.config key to point to your home directory.
Good Luck and Happy programming !

Download Source Code

No comments: