If I have a URL to a download, www.website.com/myfile.html
so when that link is clicked it automatically starts a download, which may be myfile.txt for example, how would I get that file into C# for reading..
Is that what Net.WebRequest.Create(url), Net.HttpWebRequest does?
You could achieve this using WebClient:
using (var client = new WebClient())
{
// Download and save the file locally
client.DownloadFile("http://www.website.com/myfile.html", "myfile.html");
}
If you don't want to store the file locally but only read the contents you could try this:
using (var client = new WebClient())
{
string result = client.DownloadString("http://www.website.com/myfile.html");
}
Using C# as an example, here is how one might force the download of a file after clicking a button, link, etc...
public void DownloadFileLink_Click(object sender, EventArgs e)
{
//Get the file data
byte[] fileBytes = Artifacts.Provider.GetArtifact(ArtifactInfo.Id);
//Configure the response header and submit the file data to the response stream.
HttpContext.Current.Response.AddHeader("Content-disposition", "attachment;filename=" + "myDynamicFileName.txt");
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.BinaryWrite(fileBytes);
HttpContext.Current.Response.End();
}
With this in mind, what you need to look for is the Header in the response, the Header will contain an item Content-disposition which will contain the filename of the file being streamed in the response.
Related
I am generating dynamic .pdf file using asp.net, on some browsers e.g firefox displays the pdf as expected but on I.E & Safari its giving a "Save As" rather than displaying it in the browser. I have used an iFrame for the same. Also to display pdf file is it mandate that the client should have adobe reader or some plugin to display the pdf?
protected void bttnpdf_Click(object sender, EventArgs e)
{
string FilePath = Server.MapPath("sample.pdf");
WebClient User = new WebClient();
Byte[] FileBuffer = User.DownloadData(FilePath);
if (FileBuffer != null)
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", FileBuffer.Length.ToString());
Response.BinaryWrite(FileBuffer);
}
}
Any help would be appreciated.
Thanks in advance
in aspx file :
<div>
<iframe id="myFrame" runat="server" style="width:600px; height:500px;" frameborder="0"></iframe>
</div>
in cs file :
myFrame.src="yourPDFPath"
for example
myFrame.Src = "http://docs.google.com/gview?url=http://path.com/to/your/pdf.pdf&embedded=true";
When I have done this I have also added a content disposition. In the code (can't share it all as it is production code) there is a function that finds a record in the database and returns a FileHandle.
The function returns a FileHandle:
FileStream stream = new FileStream(filePath, FileMode.Open);
var fileHandle = new FileHandle
{
FileStream = stream,
ContentType = "application/pdf",
Filename = fileDownloadName
};
where filePath is the path to the file (e.g. Server.MapPath("sample.pdf") ). In the controller action I have:
var cd = new System.Net.Mime.ContentDisposition
{
// for example foo.bak
FileName = fileHandle.Filename,
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(fileHandle.FileStream, fileHandle.ContentType);
Add below line before the line Response.BinaryWrite(FileBuffer);.
Response.AddHeader("Content-Disposition", "inline");
add this header to reponse , so that PDF files will opened in browser itself.
I have an MVC application that shows a list of files for download. The user selects the files with a checkbox and these are generated as PDF"s on the server side using the Pechkin library.
My problem is that when downloading more than one file, I'm getting the error that "Server cannot clear headers after HTTP headers have been sent." which I realise is because I can only send a single HTTP response back to the client, but I'm not sure how to go about fixing this.
public ActionResult Forms(FormsViewModel model)
{
foreach (var item in model.Forms)
{
if (item.Selected)
{
CreatePdfPechkin(RenderRazorViewToString(model.FormType, model.Form), model.Name);
}
}
return View(model);
}
private void CreatePdfPechkin(string html, string filename)
{
var pechkin = Factory.Create(new GlobalConfig());
var pdf = pechkin.Convert(new ObjectConfig()
.SetLoadImages(true).SetZoomFactor(1.1)
.SetPrintBackground(true)
.SetScreenMediaType(true)
.SetCreateExternalLinks(true), html);
Response.Clear();
Response.ClearContent();
// error on the next line for the second file to be downloaded
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}.pdf; size={1}", filename, pdf.Length));
Response.BinaryWrite(pdf);
Response.Flush();
Response.End();
}
What's the pattern that I should be using to accomplish this?
You can zip all selected files and send it across. There is library available for same on codeplex called DotNetZip
This is how you can zip it.
var outputStream = new MemoryStream();
using (var zip = new ZipFile())
{
zip.AddFile("path to file one");
zip.AddFile("path to file two");
zip.AddFile("path to file three");
zip.AddFile("path to file four");
zip.Save(outputStream);
}
outputStream.Position = 0;
return File(outputStream, "application/zip","zip file name.zip");
I have this function that I'm using to compress a list of files from the user's session, and then streaming it to the user's browser for download:
public static void DownloadAllPhotos()
{
HttpContext.Current.Response.AddHeader(
"Content-Disposition", "attachment; filename=Photos.zip");
HttpContext.Current.Response.ContentType = "application/zip";
List<string> photos= new List<string>();
if (HttpContext.Current.Session != null &&
HttpContext.Current.Session["userPhotos"] != null)
{
photos = (List<string>)HttpContext.Current.Session["userPhotos"];
}
using (var zipStream = new
ZipOutputStream(HttpContext.Current.Response.OutputStream))
{
foreach (string photoUrl in photos)
{
byte[] fileBytes = File.ReadAllBytes(photoUrl);
var fileEntry = new ZipEntry(
Path.GetFileName(photoUrl))
{
Size = fileBytes.Length
};
zipStream.PutNextEntry(fileEntry);
zipStream.Write(fileBytes, 0, fileBytes.Length);
}
zipStream.Flush();
zipStream.Close();
// reset session
HttpContext.Current.Session["userPhotos"] = new List<string>();
}
}
When the user has photo urls in their session, and they click a button to call this function, the files are compressed and the download starts in the user's browser.
But when I try to open the compressed file, I get this error:
Windows cannot open the folder.
The compressed folder "{Path to my file}" is invalid.
Am I doing something wrong that's causing this error?
Check out the placement of Response.Flush and ZipEntry.CleanName in this example and see if writing something similar corrects the problem.
Also per the example in #cfeduke 's answer, there is a comment in the 'Create a Zip as a browser download attachment in IIS' that suggests changing Response.ContentType = "application/octet-stream" instead of "application/zip"
// If the browser is receiving a mangled zipfile, IIS Compression may
cause this problem. Some members have found that
//Response.ContentType = "application/octet-stream" has solved this.
May be specific to Internet Explorer.
Worked for me. And it was not IE specific (I use Chrome).
My C# web application resides on the C drive.
However the application receives uploaded documents from users and saves them on the D drive.
How do I specify the path to documents on the D drive in the NavigateUrl property of an HyperLink control in the web application on the C drive.
In server-side, you could load the file inside a Stream and response this object as a byte[]
public void Page_Load(object sender, System.EventArgs e)
{
// create a FileStream from a path from local (D:, C:, E:, etc...)
FileStream file = File.OpenRead(#"d:\folder\yourfile.txt");
//Convert the stream to an array of bytes.
byte[] byteArray = file.ToArray();
// Clear all content output from the buffer stream
Response.Clear();
// Add a HTTP header to the output stream that specifies the default filename
// for the browser's download dialog
Response.AddHeader("Content-Disposition", "attachment; filename=foo.txt");
// Add a HTTP header to the output stream that contains the
// content length(File Size). This lets the browser know how much data is being transfered
Response.AddHeader("Content-Length", byteArray.Length.ToString());
// Set the HTTP MIME type of the output stream
Response.ContentType = "application/octet-stream";
// Write the data out to the client.
Response.BinaryWrite(byteArray);
}
I'm getting a file from a database in byte [] format and want user to see download dialog before Linq will take it from the database. It's in C# and ASP.NET.
Now, it's like this:
User choose a file, click on it.
In code I get id of file clicked and using Linq I'm downloading.
Then I send the file by Response.OutputStream.Write(content, 0,
content.Length);
Before a file is downloaded from the database user won't see any
download dialog.
What can I do if I want users to see the download dialog before file is downloaded?
Code:
Getting file by id:
public static byte[] getFile(Guid id)
{
var linqFile = from file in MyDB.Files
where file.IdPliku.Equals(id)
select new
{
Content = file.Content
};
return linqFile.ToList().FirstOrDefault().Content.ToArray();
}
Saving file:
public void SaveFile(Guid fileID, string filename, string mimeTypes)
{
try
{
byte[] content = FileService.getFile(fileID);
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = mimeTypes;
Response.AppendHeader("Accept-Ranges", "bytes");
Response.AppendHeader("Content-Range", string.Format("0-{0}/{1}", content.Length, content.Length));
Response.AppendHeader("Content-Length", content.Length.ToString());
Response.AppendHeader("Content-Encoding", "utf-8");
Response.AppendHeader("Content-Type", Response.ContentType);
Response.AppendHeader("Content-Disposition", "attachment; filename= " + HttpUtility.UrlEncode(filename));
Response.OutputStream.Write(content, 0, content.Length);
//Response.BinaryWrite(content);
Response.Flush();
}
finally
{
Response.Close();
}
}
You are my hope.
your issue is here:
byte[] content = FileService.getFile(fileID);
because in this line you allocate the whole file in the web server's RAM and put everything in there, all content of the file from the database; what happens later does not matter anymore because you have already downloaded from db to web server in this line!!!
I am having such Deja-vu because I am sure I have given exactly the same comment on a very same question few weeks ago. Can't find it now, search for something like this here in SO.
In fact the solution is to stream directly to the output stream of the Response avoiding your byte[] array allocation above, to get this your data layer should of course support it and if it does not you could add a method for this. You want to use SQL Server filestream or something similar.