It's been a long time since I've had to work with WebForms but I'm having to update an old website. I'm trying to make a page that will allow the user to download a file to their machine. I can get the list of files in a directory as well as display it in a table, however, I'm trying to assign the file name to the command argument of a button so that I'll know the name of the file to go get in the button event. I can't seem to find the correct way to get the value out of the folder object to populate the command argument. No errors, it's just blank. Any suggestions?
var listFiles = dir.GetFiles();
<%
foreach(var file in listFiles) { %>
<tr>
<td> </td>
<td><%= file.Name %></td>
<td><%= file.Length %></td>
<td><%= file.CreationTime.ToString("MM/dd/yyyy HH:mm") %></td>
<td>
<asp:LinkButton ID="btnDownload" runat="server"
CommandArgument='<%#Eval("file.Name") %>'
CommandName="DownloadTechFile"
OnCommand="DownloadFile"
ToolTip="Downloaded file">
<span aria-hidden="true" class="fa fa-download"></span>
</asp:LinkButton>
</td>
</tr>
<% } %>
protected void DownloadFile(object sender, CommandEventArgs e)
{
Alert.Hide();
var fileName = e.CommandArgument.ToString();
var fileFullPath = Path.Combine(FileFolderPath, fileName);
if (string.IsNullOrWhiteSpace(fileName) == false)
{
WebClient req = new WebClient();
HttpResponse response = HttpContext.Current.Response;
try
{
response.Clear();
response.ClearContent();
response.ClearHeaders();
response.Buffer = true;
response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
byte[] data = req.DownloadData(fileFullPath);
//byte[] data = req.DownloadData(Server.MapPath(fileFullPath));
response.BinaryWrite(data);
response.End();
Alert.Show(AlertType.Success, "File downloaded.");
}
catch (Exception ex)
{
logger.Error("Error downloading file from {0}. {1} | {2} | {3}", fileFullPath, ex.Message, ex.StackTrace, ex.InnerException);
Alert.Show(AlertType.Error, string.Format("Error trying to download file: {0}", fileName));
}
}
}
UPDATE: This is what I came up with in case someone else could use it.
<asp:GridView ID="gvFiles" runat="server" AutoGenerateColumns="false" CssClass="table borderless" HeaderStyle-CssClass="fileheader">
<Columns>
<asp:BoundField DataField="FileName" HeaderText="File Name" />
<asp:BoundField DataField="FileSize" HeaderText="File Size" />
<asp:BoundField DataField="Date" HeaderText="Created On" />
<asp:TemplateField HeaderText="">
<ItemTemplate>
<asp:LinkButton ID="btnDownload" runat="server"
CommandArgument='<%# Eval("FileName") %>'
OnClick="DownloadFile"
ToolTip="Downloaded file">
<span aria-hidden="true" class="fa fa-download"></span>
</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
void LoadGrid()
{
// create a table for the files, populate, and then bind.
DataTable dtFiles = new DataTable();
dtFiles.Columns.Add("Date", typeof(string));
dtFiles.Columns.Add("FileSize", typeof(string));
dtFiles.Columns.Add("FileName", typeof(string));
DirectoryInfo fileDirectory = new DirectoryInfo(FileFolderPath);
foreach (FileInfo file in fileDirectory.GetFiles("*.txt"))
{
DataRow dr = dtFiles.NewRow();
dr["Date"] = file.CreationTime.ToString("MM/dd/yyyy HH:mm");
dr["FileSize"] = Utility.GetBytesReadable(file.Length);
dr["FileName"] = file.Name;
dtFiles.Rows.Add(dr);
}
dtFiles.DefaultView.Sort = "Date DESC";
gvFiles.DataSource = dtFiles;
gvFiles.DataBind();
}
protected void DownloadFile(object sender, EventArgs e)
{
var fileName = (sender as LinkButton).CommandArgument;
var fileFullPath = Path.Combine(FileFolderPath, fileName);
string mineType = MimeMapping.GetMimeMapping(fileFullPath);
if (string.IsNullOrWhiteSpace(fileName) == false)
{
byte[] binFile = File.ReadAllBytes(fileFullPath);
Response.ContentType = mineType;
Response.AppendHeader("Content-Disposition", "attachment; filename=" + fileName);
Response.BinaryWrite(binFile);
Response.End();
}
}