ASHX handler throwing value cannot be null error - c#

I wanted to display a list of files in a specific folder as hyperlinks, and when the user click on the link, it will open the respective file to prompt the user to download or view but there is a constant error saying:
{"Value cannot be null.\r\nParameter name: filename"} at the line context.Response.WriteFile(context.Request.QueryString["files"]);
I've tried lots of ways but to no avail.
ASHX file:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var directory = new DirectoryInfo("C:\\temp\\Safety&Security");
var files = (from f in directory.GetFiles()
orderby f.LastWriteTime descending
select f).First();
//string[] files = Directory.GetFiles(#"C:\temp\Safety&Security");
//files = files.Substring(files.LastIndexOf(("\\")) + 1);
rpt.DataSource = files;
rpt.DataBind();
}
if (!Page.IsPostBack)
{
string[] files = Directory.GetFiles(#"C:\temp\marketing");
Repeater1.DataSource = files;
Repeater1.DataBind();
}
if (!Page.IsPostBack)
{
string[] files = Directory.GetFiles(#"C:\temp\IT");
Repeater2.DataSource = files;
Repeater2.DataBind();
}
}
protected void rpt_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
string file = e.Item.DataItem as string;
HyperLink hyp = e.Item.FindControl("hyp") as HyperLink;
hyp.Text = file;
hyp.NavigateUrl = string.Format("~/Handlers/FileHandler.ashx?file={0}", file);
FileInfo f = new FileInfo(file);
FileStream s = f.Open(FileMode.OpenOrCreate, FileAccess.Read);
}
}
public void ProcessRequest(HttpContext context)
{
//Track your id
//string id = context.Request.QueryString["id"];
context.Response.Clear();
context.Response.Buffer = true;
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + context.Request.QueryString["files"]);
context.Response.WriteFile(context.Request.QueryString["files"]);
context.Response.End();
}
public bool IsReusable
{
get { return false; }
}
This is the index page codes:
<li class='has-sub'><a href='#'><span>Safety, QA & Security</span></a>
<ul>
<asp:Repeater ID="rpt" runat="server" OnItemDataBound="rpt_ItemDataBound">
<ItemTemplate>
<asp:HyperLink ID="hyp" runat="server" target="_blank" a href="/Handlers/FileHandler.ashx?id=7"/>
<%-- another method of listing all files in specific folder --%>
<%--<% foreach(var file in Directory.GetFiles("C:\\temp\\Safety&Security", "*.*", SearchOption.AllDirectories)) { %>
<li><%= file.Substring(file.LastIndexOf(("\\"))+1) %></li>
<% } %> --%>
</ItemTemplate>
</asp:Repeater>
</ul>
</li>

You've made a silly mistake!
hyp.NavigateUrl = string.Format("~/Handlers/FileHandler.ashx?file={0}", file);
context.Response.WriteFile(context.Request.QueryString["files"]);
You're setting the querystring as 'file' but reading the querystring as 'files' which doesn't exist. Try
context.Response.WriteFile(context.Request.QueryString["file"]);
EDIT:
Try this code. First add a file in your c:\temp called test.txt and put some text in there. In your aspx:
<li class='has-sub'><a href='/Handlers/FileHandler.ashx?file=c:\temp\test.txt'><span>Safety, QA & Security</span></a></li>
In your handler:
public void ProcessRequest(HttpContext context)
{
//Track your id
//string id = context.Request.QueryString["id"];
context.Response.Clear();
context.Response.Buffer = true;
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + context.Request.QueryString["file"]);
context.Response.WriteFile(context.Request.QueryString["file"]);
context.Response.End();
}
public bool IsReusable
{
get { return false; }
}
Set a breakpoint in your handler and make sure your handler gets hit when you debug. This code won't work as you need it to because of the other problem I mentioned in the comments about your data binding not working but you should at least get the querystring in your handler and the text file will download.

Related

How to open a pdf file in a WebForm application by search?

When I click on the listbox which search a PDF file, it's not opening.
The code is below. Any thoughts?
protected void Button1_Click(object sender, EventArgs e)
{
ListBox1.Items.Clear();
string search = TextBox1.Text;
if (TextBox1.Text != "")
{
string[] pdffiles = Directory.GetFiles(#"\\192.168.5.10\fbar\REPORT\CLOTHO\H2\REPORT\", "*" + TextBox1.Text + "*.pdf", SearchOption.AllDirectories);
foreach (string file in pdffiles)
{
// ListBox1.Items.Add(file);
ListBox1.Items.Add(Path.GetFileName(file));
}
}
else
{
Response.Write("<script>alert('For this Wafer ID Report is Not Generated');</script>");
}
}
protected void ListBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string pdffiles = ListBox1.SelectedItem.ToString();
string.Format("attachment; filename={0}", fileName));
ProcessStartInfo infoOpenPdf = new ProcessStartInfo();
infoOpenPdf.FileName = pdffiles;
infoOpenPdf.Verb = "OPEN";
// Process.Start(file);
infoOpenPdf.CreateNoWindow = true;
infoOpenPdf.WindowStyle = ProcessWindowStyle.Normal;
Process openPdf = new Process();
openPdf.StartInfo = infoOpenPdf;
openPdf.Start();
}
First, you must save the file's full name to get it later. So, you must change from:
ListBox1.Items.Add(Path.GetFileName(file));
To:
ListBox1.Items.Add(new ListItem(Path.GetFileName(file), file));
Then, you should send the file from the server to the client, like this:
protected void ListBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string fileName = ListBox1.SelectedValue;
byte[] fileBytes = System.IO.File.ReadAllBytes(fileName);
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Response.Clear();
context.Response.ClearHeaders();
context.Response.ClearContent();
context.Response.AppendHeader("content-length", fileBytes.Length.ToString());
context.Response.ContentType = "application/pdf";
context.Response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
context.Response.BinaryWrite(fileBytes);
context.ApplicationInstance.CompleteRequest();
}
Note: don't forget to initialize your ListBox with the property AutoPostBack setted to true.

Error in creating download link for files

I am creating a function that displays a list of files from a specific folder and enable the users to download but i am having errors that states:
"An exception of type 'System.ArgumentNullException' occurred in System.Web.dll but was not handled in user code, {"Value cannot be null.\r\nParameter name: filename"}"
in the statement:
context.Response.WriteFile(context.Request.QueryString["files"]);
My code:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string[] files = Directory.GetFiles(#"C:\temp");
rpt.DataSource = files;
rpt.DataBind();
}
}
protected void rpt_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
string file = e.Item.DataItem as string;
HyperLink hyp = e.Item.FindControl("hyp") as HyperLink;
hyp.Text = file;
hyp.NavigateUrl = string.Format("~/Handlers/FileHandler.ashx?file={0}\n" , file);
}
}
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
context.Response.Buffer = true;
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + context.Request.QueryString["files"]);
context.Response.WriteFile(context.Request.QueryString["files"]);
context.Response.End();
}
}
Try Request.QueryString(files) instead
May be a typo, but your code in ItemDataBound is
hyp.NavigateUrl = string.Format("~/Handlers/FileHandler.ashx?file={0}\n" , file);
Here you are setting a querystring parameter 'file'
In your handler, ProcessRequest method you are accessing 'files' parameter
context.Response.WriteFile(context.Request.QueryString["files"]);
Try changing this to
context.Response.WriteFile(context.Request.Params["file"]);

Click event on dynamically created link buttons not working

I want to give option to upload multiple files and then download it. I am creating link buttons Dynamically like:
private void AddLinkButtons()
{
string[] fileNames = (string[])Session["fileNames"];
string[] fileUrls = (string[])Session["fileUrls"];
if (fileNames != null)
{
for (int i = 0; i < fileUrls.Length - 1; i++)
{
LinkButton lb = new LinkButton();
phLinkButtons.Controls.Add(lb);
lb.Text = fileNames[i];
lb.CommandName = "url";
lb.CommandArgument = fileUrls[i];
lb.ID = "lbFile" + i;
//lb.Click +=this.DownloadFile;
lb.Attributes.Add("runat", "server");
lb.Click += new EventHandler(this.DownloadFile);
////lb.Command += new CommandEventHandler(DownloadFile);
phLinkButtons.Controls.Add(lb);
phLinkButtons.Controls.Add(new LiteralControl("<br>"));
}
}
And my DownloadFile event is:
protected void DownloadFile(object sender, EventArgs e)
{
LinkButton lb = (LinkButton)sender;
string url = lb.CommandArgument;
System.IO.FileInfo file = new System.IO.FileInfo(url);
if (file.Exists)
{
try
{
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
Response.AddHeader("Content-Length", file.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(file.FullName);
Response.End();
}
catch (Exception ex)
{
}
}
else
{
Response.Write("This file does not exist.");
}
}
I am getting link buttons on screen but DownloadFile event is never called after clicking. i tried all options that are commented, but its not working. What is wrong in code?
Where and when is AddLinkButtons() called ?
It should be called during init of your page, on each postback.
Depending on the logic of your page, your OnInit should look like this
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
AddLinkButtons();
}
code seems fine ..
dont understand what is lbTest in AddLinkButtons() method.
please remove this line from AddLinkButtons() method.
lb = (LinkButton)lbTest;
Hope that will works...
Add Link button after its properties have been set. Your Code is adding 2 lb buttons
phLinkButtons.Controls.Add(lb); //------1
lb.Text = fileNames[i];
lb.CommandName = "url";
lb.CommandArgument = fileUrls[i];
lb.ID = "lbFile" + i;
//lb.Click +=this.DownloadFile;
lb.Attributes.Add("runat", "server");
lb.Click += new EventHandler(this.DownloadFile);
////lb.Command += new CommandEventHandler(DownloadFile);
phLinkButtons.Controls.Add(lb); //-------------------2
Remove First line

Dynamically added link button click event does not execute

I have dynamically added few link buttons inside a grid view with this code:
protected void gvTicketStatus_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string compositeFiles = e.Row.Cells[3].Text;
// split the string into individual files using delemeter "?"
string[] fileSet = compositeFiles.Split('?');
e.Row.Cells[3].Text = "";
foreach (string str in fileSet)
{
if (str != null)
{
// add a link button to the cell of the data grid.
LinkButton lb = new LinkButton();
lb.Text = "Download File";
lb.ID = str; // str is file URL
lb.Click += new EventHandler(lbStatus_click);
e.Row.Cells[3].Controls.Add(lb);
}
}
}
}
In my event handler, I have read the URL from the ID and downloading the file as octet stream.
private void lbStatus_click(object sender, EventArgs e)
{
string fileName = ((Control)sender).ID;
FileInfo file = new FileInfo(fileName);
if (fileName != string.Empty && file.Exists)
{
Response.Clear();
Response.AddHeader("Content-disposition", "attachment; filename=" + fileName.Substring(fileName.LastIndexOf("\\") + 1));
Response.AddHeader("content-Length", file.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(file.FullName);
Response.Flush();
Response.Close();
}
}
The link bottons appear in the webpage fine, but the problem is when I click on them, the page simply gets refreshed and nothing happens. The event handler code never gets executed.
Is this problem related to postback of the page? if yes then how can I solve it?
You need to suscribe to the command event of the grid view and add whatever information you need to the CommandArgs property.
EDIT: Added example
public void Page_Load(object sender, EventArgs e ){
gvTicketStatus.RowCommand += new EventHandler(RowCommand);
}
protected void gvTicketStatus_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string compositeFiles = e.Row.Cells[3].Text;
// split the string into individual files using delemeter "?"
string[] fileSet = compositeFiles.Split('?');
e.Row.Cells[3].Text = "";
foreach (string str in fileSet)
{
if (str != null)
{
// add a link button to the cell of the data grid.
LinkButton lb = new LinkButton();
lb.Text = "Download File";
lb.CommandName = "download"; //this is useful if you need to add more links with different commands.
lb.CommandArgument = str;// str is file URL
e.Row.Cells[3].Controls.Add(lb);
}
}
}
}
In my event handler, I have read the URL from the ID and downloading the file as octet stream.
private void RowCommand(object sender, GridViewCommandEventArgs e)
{
string fileName = e.CommandArgument;
FileInfo file = new FileInfo(fileName);
if (fileName != string.Empty && file.Exists)
{
Response.Clear();
Response.AddHeader("Content-disposition", "attachment; filename=" + fileName.Substring(fileName.LastIndexOf("\\") + 1));
Response.AddHeader("content-Length", file.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(file.FullName);
Response.Flush();
Response.Close();
}
}
For more information, please read http://msdn.microsoft.com/library/system.web.ui.webcontrols.gridview.rowcommand(v=vs.80).aspx
I've seen this behavior many times before when adding controls dynamically. Make sure that the code which binds your datagrid (which in turn executes your gvTicketStatus_RowDataBound event) runs after each and every page postback. This needs to occur in order for the linkbutton control to persist its click event after the postback.

How to only display certain images in a folder into a Repeater in ASP.NET

I have a Repeater that takes all my images in a folder and display it. But what code changes must I make to only allow lets say Image1.jpg and Image2.jpg to be displayed in my repeater. I don"t want the repeater to display ALL the images in my folder.
My Repeater
<asp:Repeater ID="repImages" runat="server" OnItemDataBound="repImages_ItemDataBound">
<HeaderTemplate><p></HeaderTemplate>
<ItemTemplate>
<asp:HyperLink ID="hlWhat" runat="server" rel="imagebox-bw">
<asp:Image ID="imgTheImage" runat="server" />
</asp:HyperLink>
</ItemTemplate>
<FooterTemplate></p></FooterTemplate>
</asp:Repeater>
My Code behind - PAGE LOAD
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string sBasePath = System.Web.HttpContext.Current.Request.ServerVariables["APPL_PHYSICAL_PATH"];
if ( sBasePath.EndsWith("\\"))
sBasePath = sBasePath.Substring(0,sBasePath.Length-1);
sBasePath = sBasePath + "\\" + "pics";
System.Collections.Generic.List<string> oList = new System.Collections.Generic.List<string>();
foreach (string s in System.IO.Directory.GetFiles(sBasePath, "*.*"))
{
//We could do some filtering for example only adding .jpg or something
oList.Add( System.IO.Path.GetFileName( s ));
}
repImages.DataSource = oList;
repImages.DataBind();
}
}
My Code behind - Repeater's ItemDataBound event code
protected void repImages_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem ||
e.Item.ItemType == ListItemType.Item)
{
string sFile = e.Item.DataItem as string;
//Create the thumblink
HyperLink hlWhat = e.Item.FindControl("hlWhat") as HyperLink;
hlWhat.NavigateUrl = ResolveUrl("~/pics/" + sFile );
hlWhat.ToolTip = System.IO.Path.GetFileNameWithoutExtension(sFile);
hlWhat.Attributes["rel"] = "imagebox-bw";
Image oImg = e.Item.FindControl("imgTheImage") as Image;
oImg.ImageUrl = ResolveUrl("~/createthumb.ashx?gu=/pics/" + sFile + "&xmax=100&ymax=100" );
}
}
ANSWER:
My updated Page Load
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string sBasePath = System.Web.HttpContext.Current.Request.ServerVariables["APPL_PHYSICAL_PATH"];
if ( sBasePath.EndsWith("\\"))
sBasePath = sBasePath.Substring(0,sBasePath.Length-1);
sBasePath = sBasePath + "\\" + "pics";
System.Collections.Generic.List<string> oList = new System.Collections.Generic.List<string>();
string[] extensions = { "*.jpg", "*.png" };
List<string> files = new List<string>();
foreach (string filter in extensions)
{
files.AddRange(System.IO.Directory.GetFiles(sBasePath, filter));
oList.Add(System.IO.Path.GetFileName(filter));
}
repImages.DataSource = oList;
repImages.DataBind();
}
What format are the image names that you want to display? If you know that you can construct a filter to use when listing the contents of the directory:
string[] files = Directory.GetFiles(folder, "*1.jpg");
Will list all the jpg files that end in "1"
EDIT:
Instead of having:
foreach (string s in System.IO.Directory.GetFiles(sBasePath, "*.*"))
{
//We could do some filtering for example only adding .jpg or something
oList.Add( System.IO.Path.GetFileName( s ));
}
You'd have:
string[] files = System.IO.Directory.GetFiles(sBasePath, "*.jpg")
foreach (string s in files)
{
oList.Add( System.IO.Path.GetFileName( s ));
}
EDIT 2:
I've done a quick search and it looks like Get Files won't take multiple extensions, so you'll have to search for each type of extension separately:
string[] extensions = {"*.jpg" , "*.png" };
List<string> files = new List<string>();
foreach(string filter in extensions)
{
files.AddRange(System.IO.Directory.GetFiles(path, filter));
}
foreach (string s in files)
{
oList.Add( System.IO.Path.GetFileName( s ));
}
Easiest way to is load them all into a List<> and then use Linq to filter out the ones you want.
VS2005
public class GetFiles
{
public static void Main(string[] args)
{
FileInfo[] files =
new DirectoryInfo(#"D:\downloads\_Installs").GetFiles();
ArrayList exefiles = new ArrayList();
foreach (FileInfo f in files)
{
if (f.Extension == ".exe") // or whatever matching you want to do.
{
exefiles.Add(f);
}
}
foreach (FileInfo f in exefiles)
{
Console.WriteLine(f.FullName);
}
Console.ReadKey();
}
}
VS2008
public class GetFiles
{
public static void Main(string[] args)
{
FileInfo[] files =
new DirectoryInfo(#"D:\downloads\_Installs").GetFiles();
var exefiles = from FileInfo f in files
where f.Extension == ".exe"
select f;
foreach (FileInfo f in exefiles)
{
Console.WriteLine(f.FullName);
}
Console.ReadKey();
}
}
What you will need to do is filter out all the images you do not wish to display from your list before you bind it to your repeater control.

Categories

Resources