Downloading a File on ASP.net C# - c#

I have a serious Problem with Download in my ASP.net Project.
I used the same code in 2 pages to download a file :
private bool DownloadAnhang_Tracking(string fileName, string filepath)
{
////File Path and File Name
string filePath = filepath;
string downloadableFileName = fileName;
System.IO.FileInfo filename;
FileStream myFile;
try
{
filename = new System.IO.FileInfo(filePath);
myFile = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
catch (IOException ex)
{
this.ShowErrorNotification("Fehler: " + ex.Message);
throw;
}
////Reads file as binary values
BinaryReader binaryReader = new BinaryReader(myFile);
////Check whether file exists in specified location
if (filename.Exists)
{
try
{
long startBytes = 0;
string lastUpdateTiemStamp = File.GetLastWriteTimeUtc(filePath).ToString("r");
string encodedData = HttpUtility.UrlEncode(downloadableFileName, Encoding.UTF8) + lastUpdateTiemStamp;
Response.Clear();
Response.Buffer = false;
Response.AddHeader("Accept-Ranges", "bytes");
Response.AppendHeader("ETag", "\"" + encodedData + "\"");
Response.AppendHeader("Last-Modified", lastUpdateTiemStamp);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + filename.Name);
Response.AddHeader("Content-Length", (filename.Length - startBytes).ToString());
Response.AddHeader("Connection", "Keep-Alive");
Response.ContentEncoding = Encoding.UTF8;
////Send data
binaryReader.BaseStream.Seek(startBytes, SeekOrigin.Begin);
////Dividing the data in 1024 bytes package
int maxCount = (int)Math.Ceiling((filename.Length - startBytes + 0.0) / 1024);
////Download in block of 1024 bytes
int i;
for (i = 0; i < maxCount && Response.IsClientConnected; i++)
{
Response.BinaryWrite(binaryReader.ReadBytes(1024));
Response.Flush();
}
////if blocks transfered not equals total number of blocks
if (i < maxCount)
{
return false;
}
else
{
return true;
}
}
catch
{
return false;
}
finally
{
Response.End();
binaryReader.Close();
myFile.Close();
}
}
else
{
this.ShowErrorNotification("Der Anhang wurde nicht gefunden!");
}
return false;
}
So used this code in another page, but it doesn't work anymore! I pass the same information to the method but it doesn't work! The Error is from MSAjax:
0x800a139e - Runtime Error in JavaScript:
Sys.WebForms.PageRequestManagerParserErrorException: The message
received from the server could not be parsed. Common causes for this
error are when the response is modified by calls to Response.Write(),
response filters, HttpModules, or server trace is enabled.
I don't get why this code works on page 1 but not on page 2.
Im using ASP.Net 4.5 WebForms with C#

Related

File download in chunks in http-context response C#

I have a below scenario.
Client send request to Server-1 for file download
Server-1 send request to Server-2 for file.
To make this work I need to create a mechanism where once client send request to the Server-1, Server-1 will request to Server-2 which will send file as response output-stream in chunks. Server-1 will send this file chunks to client browser continuously as it keep receiving from server-2.
I have done code as below, theoretically it looks fine but still it is not working.
It is not downloading entire file in client browser, it seems like last chunk is not transferred to the Server-1 or it is not downloading to client browser from Server-1
Server-1 Code (Where client request for File download)
private void ProccesBufferedResponse(HttpWebRequest webRequest, HttpContext context)
{
char[] responseChars = null;
byte[] buffer = null;
if (webRequest == null)
logger.Error("Request string is null for Perfios Docs Download at ProccesBufferedResponse()");
context.Response.Buffer = false;
context.Response.BufferOutput = false;
try
{
WebResponse webResponse = webRequest.GetResponse();
context.Response.ContentType = "application/pdf";
context.Response.AddHeader("Content-disposition", webResponse.Headers["Content-disposition"]);
StreamReader responseStream = new StreamReader(webResponse.GetResponseStream());
while (!responseStream.EndOfStream)
{
responseChars = new char[responseStream.ToString().ToCharArray().Length];
responseStream.Read(responseChars, 0, responseChars.Length);
buffer = Encoding.ASCII.GetBytes(responseChars);
context.Response.Clear();
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.Flush();
}
}
catch (Exception ex)
{
throw;
}
finally
{
context.Response.Flush();
context.Response.End();
}
}
Server-2 Code (Where Server-1 will send request for file)
private void DownloadInstaPerfiosDoc(int CompanyID, string fileName, string Foldertype)
{
string folderPath;
string FilePath;
int chunkSize = 1024;
int startIndex = 0;
int endIndex = 0;
int length = 0;
byte[] bytes = null;
DirectoryInfo dir;
folderPath = GetDocumentDirectory(CompanyID, Foldertype);
FilePath = folderPath + "\\" + fileName;
dir = new DirectoryInfo(folderPath);
HttpContext.Current.Response.Buffer = false;
HttpContext.Current.Response.BufferOutput = false;
if (dir.Exists && dir.GetFiles().Length > 0)
{
foreach (var file in dir.GetFiles(fileName))
{
FilePath = folderPath + "\\" + file.Name;
FileStream fsReader = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("Content-disposition", string.Format("attachment; filename = \"{0}\"", fileName));
int totalChunks = (int)Math.Ceiling((double)fsReader.Length / chunkSize);
for (int i = 0; i < totalChunks; i++)
{
startIndex = i * chunkSize;
if (startIndex + chunkSize > fsReader.Length)
endIndex = (int)fsReader.Length;
else
endIndex = startIndex + chunkSize;
length = (int)endIndex - startIndex;
bytes = new byte[length];
fsReader.Read(bytes, 0, bytes.Length);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.OutputStream.Write(bytes, 0, bytes.Length);
HttpContext.Current.Response.Flush();
}
}
}
}
Please help me to resolve this issue.
It is possible and feasible. I'll give a pseudo procedure for you to understand the overall idea.
Server1
download action gets hit
create a request to server2
get the response stream of your server2 request
read the response stream in desired chunk sizes until it's consumed completely
write each chunk (as soon as you read) to current response stream
Server2
download action gets hit
write your stream onto your current response stream however you like

Uri encoding, file download doesn't work with , and whitespace

I have an asp.net webpage that allows downloading files.
When i had the problem of downloading a file with whitespace(Test 1 4 3.txt) it will turn the file into: Test+1+4+3.txt
I used:
_Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(_fileName, System.Text.Encoding.UTF8));
And it solved the issue.
Now i have a new issue:
When a file contains , it changes it into %2c and i the UrlEncode doesn't fix it.
i Tried using:
_Response.AddHeader("Content-Disposition", "attachment;filename=" + Uri.EscapeDataString(_fileName));
But it's the old setting and it doesn't support whitespace.
What can i do to solve such a case?
Should i use regex / switch?
This is my function:
public static bool ResponseFile(HttpRequest _Request, HttpResponse _Response, string _fileName, string _fullPath, long _speed = 1024000)
{
try
{
FileStream myFile = new FileStream(_fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader br = new BinaryReader(myFile);
try
{
_Response.AddHeader("Accept-Ranges", "bytes");
_Response.Buffer = false;
long fileLength = myFile.Length;
long startBytes = 0;
int pack = 10240; //10K bytes
int sleep = (int)Math.Floor((double)(1000 * pack / _speed)) + 1;
if (_Request.Headers["Range"] != null)
{
_Response.StatusCode = 206;
string[] range = _Request.Headers["Range"].Split(new char[] { '=', '-' });
startBytes = Convert.ToInt64(range[1]);
}
_Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
if (startBytes != 0)
{
_Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
}
_Response.AddHeader("Connection", "Keep-Alive");
_Response.ContentType = "application/octet-stream";
//Old didn't work with both + and ,
//_Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(_fileName, System.Text.Encoding.UTF8));
_Response.AddHeader("Content-Disposition", "attachment;filename=" + Uri.EscapeDataString(_fileName));
br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
int maxCount = (int)Math.Floor((double)((fileLength - startBytes) / pack)) + 1;
for (int i = 0; i < maxCount; i++)
{
if (_Response.IsClientConnected)
{
_Response.BinaryWrite(br.ReadBytes(pack));
Thread.Sleep(sleep);
}
else
{
i = maxCount;
}
}
}
catch
{
return false;
}
finally
{
br.Close();
myFile.Close();
}
}
catch
{
return false;
}
return true;
}
This solved it:
_Response.AddHeader("Content-Disposition", "attachment;filename=\"" + _fileName + "\"");

Epplus Use Template on Web Project

I have been working with epplus on .NET desktop projects (C#) and using templates like this:
var package = new ExcelPackage(new FileInfo("C:\\Templates\\FormatoReporteSamsung.xlsx"))
But now I'working with a .NET Web Project (C#) and i don't know what make to refer to the template that exist like a web resource where the URI of that resource like this:
http://myownweb:29200/Content/excelTemplates/Formato.xlsx
At the end I pass the excel template as a stream using this code.
using (var package = new ExcelPackage(new MemoryStream(GetBytesTemplate(FullyQualifiedApplicationPath + "Content/excelTemplates/Format.xlsx"))))
{
//Write data to excel
//Read file like byte array to return a response
Response.Clear();
Response.ContentType = "application/xlsx";
Response.AddHeader("content-disposition", "attachment; filename=" + "myFileName" + ".xlsx");
Response.BinaryWrite(package.GetAsByteArray());
Response.End();
}
To read the excel file has bytes I use this
Error "This stream does not support seek operations" in C#
private byte[] GetBytesTemplate(string url)
{
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
WebResponse myResp = myReq.GetResponse();
byte[] b = null;
using (Stream stream = myResp.GetResponseStream())
using (MemoryStream ms = new MemoryStream())
{
int count = 0;
do
{
byte[] buf = new byte[1024];
count = stream.Read(buf, 0, 1024);
ms.Write(buf, 0, count);
} while (stream.CanRead && count > 0);
b = ms.ToArray();
}
return b;
}
And to get the name of the website i use
http://devio.wordpress.com/2009/10/19/get-absolut-url-of-asp-net-application/
public string FullyQualifiedApplicationPath
{
get
{
//Return variable declaration
string appPath = null;
//Getting the current context of HTTP request
HttpContext context = HttpContext.Current;
//Checking the current context content
if (context != null)
{
//Formatting the fully qualified website url/name
appPath = string.Format("{0}://{1}{2}{3}",
context.Request.Url.Scheme,
context.Request.Url.Host,
context.Request.Url.Port == 80
? string.Empty : ":" + context.Request.Url.Port,
context.Request.ApplicationPath);
}
if (!appPath.EndsWith("/"))
appPath += "/";
return appPath;
}
}

Download function failing with big file sizes

Hi my download function.
protected void downloadFunction(string fileName)
{
string filePath = #"D:\SoftwareFiles\";
LogMessageToFile("Download started " + filePath + fileName);
byte[] array = File.ReadAllBytes(filePath + fileName);
Response.Clear();
Response.ContentType = "application/x-newton-compatible-pkg";
Response.AppendHeader("Content-Disposition",
"attachment;filename=" + fileName);
Response.BinaryWrite(array);
Response.End();
}
When handling filesize of 20, 200mb no problem.
When handling 1gb file, an exception is thrown:
Overflow or underflow in the arithmetic operation.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArithmeticException: Overflow or underflow in the arithmetic operation.
What to do?
My guess is that you're running out of memory in the byte[] array.
You can try breaking the file down and reading it in chunks.
I found a code example from a Google search to get you started:
C# file downloader AKA Response.BinaryWrite
using System;
using System.IO;
using System.Web;
public class Download
{
public static void SmallFile(string filename, string filepath, string contentType)
{
try
{
FileStream MyFileStream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
long FileSize;
FileSize = MyFileStream.Length;
byte[] Buffer = new byte[(int)FileSize];
MyFileStream.Read(Buffer, 0, (int)MyFileStream.Length);
MyFileStream.Close();
HttpContext.Current.Response.ContentType = contentType;
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));
HttpContext.Current.Response.BinaryWrite(Buffer);
}
catch
{
HttpContext.Current.Response.ContentType = "text/html";
HttpContext.Current.Response.Write("Downloading Error!");
}
HttpContext.Current.Response.End();
}
public static void LargeFile(string filename, string filepath, string contentType)
{
Stream iStream = null;
// Buffer to read 10K bytes in chunk
//byte[] buffer = new Byte[10000];
// Buffer to read 1024K bytes in chunk
byte[] buffer = new Byte[1048576];
// Length of the file:
int length;
// Total bytes to read:
long dataToRead;
try
{
// Open the file.
iStream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
// Total bytes to read:
dataToRead = iStream.Length;
HttpContext.Current.Response.ContentType = contentType;
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));
// Read the bytes.
while (dataToRead > 0)
{
// Verify that the client is connected.
if (HttpContext.Current.Response.IsClientConnected)
{
// Read the data in buffer.
length = iStream.Read(buffer, 0, 10000);
// Write the data to the current output stream.
HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the HTML output.
HttpContext.Current.Response.Flush();
buffer = new Byte[10000];
dataToRead = dataToRead - length;
}
else
{
//prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception ex)
{
// Trap the error, if any.
//HttpContext.Current.Response.Write("Error : " + ex.Message);
HttpContext.Current.Response.ContentType = "text/html";
HttpContext.Current.Response.Write("Error : file not found");
}
finally
{
if (iStream != null)
{
//Close the file.
iStream.Close();
}
HttpContext.Current.Response.End();
HttpContext.Current.Response.Close();
}
}
public static void ResumableFile(string filename, string fullpath, string contentType)
{
try
{
FileStream myFile = new FileStream(fullpath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader br = new BinaryReader(myFile);
try
{
HttpContext.Current.Response.AddHeader("Accept-Ranges", "bytes");
HttpContext.Current.Response.Buffer = false;
long fileLength = myFile.Length;
long startBytes = 0;
//int pack = 10240; //10K bytes
int pack = 1048576; //1024K bytes
if (HttpContext.Current.Request.Headers["Range"] != null)
{
HttpContext.Current.Response.StatusCode = 206;
string[] range = HttpContext.Current.Request.Headers["Range"].Split(new char[] { '=', '-' });
startBytes = Convert.ToInt64(range[1]);
}
HttpContext.Current.Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
if (startBytes != 0)
{
HttpContext.Current.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
}
HttpContext.Current.Response.AddHeader("Connection", "Keep-Alive");
HttpContext.Current.Response.ContentType = contentType;
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));
br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
int maxCount = (int)Math.Floor((double)((fileLength - startBytes) / pack)) + 1;
for (int i = 0; i < maxCount; i++)
{
if (HttpContext.Current.Response.IsClientConnected)
{
HttpContext.Current.Response.BinaryWrite(br.ReadBytes(pack));
}
else
{
i = maxCount;
}
}
}
catch
{
HttpContext.Current.Response.ContentType = "text/html";
HttpContext.Current.Response.Write("Error : file not found");
}
finally
{
br.Close();
myFile.Close();
}
}
catch
{
HttpContext.Current.Response.ContentType = "text/html";
HttpContext.Current.Response.Write("Error : file not found");
}
}
}

Can't download word document, throwing exception

I'm using response object to download word document which is stored in database as a content. It is throwing the following exception :
SubStatusCode 'Response.SubStatusCode' threw an exception of type 'System.PlatformNotSupportedException'
base {"This operation requires IIS integrated pipeline mode."} System.NotSupportedException {System.PlatformNotSupportedException}
Headers 'Response.Headers' threw an exception of type 'System.PlatformNotSupportedException'
I cannot able to view my file.. My code is as follows:
protected void btnResumedload_Click(object sender, EventArgs e)
{
DataTable dtResumeInfo = new DataTable();
dtResumeInfo = bc.ConvertByteToDataTable(objservice.getResumeInfo(int.Parse(Session["LoginId"].ToString())));
if (dtResumeInfo.Rows.Count > 0)
{
string doctype = dtResumeInfo.Rows[0]["ContentType"].ToString();
string docname = dtResumeInfo.Rows[0]["FileName"].ToString();
//
try
{
Response.Buffer = false;
Response.ClearHeaders();
Response.ContentType = doctype;
Response.AddHeader("Content-Disposition",
"attachment; filename=" + docname);
//
//Code for streaming the object while writing
const int ChunkSize = 1024;
byte[] buffer = new byte[ChunkSize];
byte[] binary = (dtResumeInfo.Rows[0]["ContentData"]) as byte[];
MemoryStream ms = new MemoryStream(binary);
int SizeToWrite = ChunkSize;
for (int i = 0; i < binary.GetUpperBound(0) - 1; i = i + ChunkSize)
{
if (!Response.IsClientConnected) return;
if (i + ChunkSize >= binary.Length)
SizeToWrite = binary.Length - i;
byte[] chunk = new byte[SizeToWrite];
ms.Read(chunk, 0, SizeToWrite);
Response.BinaryWrite(chunk);
Response.Flush();
}
Response.Close();
}
catch (Exception ex)
{
lblmsg.Visible = true;
lblmsg.Text = ex.Message;
}
}
else
{
lblmsg.Visible = true;
lblmsg.Text = "No Resume Information Found.";
}
}
It appears as though you are using the Response.Headers property which is only supported by the IIS 7.0 integrated pipeline mode. See: IIS6 + HttpModule: This operation requires IIS integrated pipeline mode

Categories

Resources