see the below handler :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FileExplorer
{
/// <summary>
/// Summary description for HandlerForMyFE
/// </summary>
public class HandlerForMyFE : IHttpHandler, System.Web.SessionState.IRequiresSessionState
{
private HttpContext _context;
private HttpContext Context
{
get
{
return _context;
}
set
{
_context = value;
}
}
public void ProcessRequest(HttpContext context)
{
Context = context;
string filePath = context.Request.QueryString["Downloadpath"];
filePath = context.Server.MapPath(filePath);
if (filePath == null)
{
return;
}
System.IO.StreamReader streamReader = new System.IO.StreamReader(filePath);
System.IO.BinaryReader br = new System.IO.BinaryReader(streamReader.BaseStream);
byte[] bytes = new byte[streamReader.BaseStream.Length];
br.Read(bytes, 0, (int)streamReader.BaseStream.Length);
if (bytes == null)
{
return;
}
streamReader.Close();
br.Close();
string fileName = System.IO.Path.GetFileName(filePath);
string MimeType = GetMimeType(fileName);
string extension = System.IO.Path.GetExtension(filePath);
char[] extension_ar = extension.ToCharArray();
string extension_Without_dot = string.Empty;
for (int i = 1; i < extension_ar.Length; i++)
{
extension_Without_dot += extension_ar[i];
}
//if (extension == ".jpg")
//{ // Handle *.jpg and
// WriteFile(bytes, fileName, "image/jpeg jpeg jpg jpe", context.Response);
//}
//else if (extension == ".gif")
//{// Handle *.gif
// WriteFile(bytes, fileName, "image/gif gif", context.Response);
//}
if (HttpContext.Current.Session["User_ID"] != null)
{
WriteFile(bytes, fileName, MimeType + " " + extension_Without_dot, context.Response);
}
}
private void WriteFile(byte[] content, string fileName, string contentType, HttpResponse response)
{
response.Buffer = true;
response.Clear();
response.ContentType = contentType;
response.AddHeader("content-disposition", "attachment; filename=" + fileName);
response.BinaryWrite(content);
response.Flush();
response.End();
}
private string GetMimeType(string fileName)
{
string mimeType = "application/unknown";
string ext = System.IO.Path.GetExtension(fileName).ToLower();
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
if (regKey != null && regKey.GetValue("Content Type") != null)
mimeType = regKey.GetValue("Content Type").ToString();
return mimeType;
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
i use this handler for downloading my files without opening them directly in browser -> (using query string path)
how can i make my files resumeable ?
i don’t have that option in internet download manager!
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
As requested, here’s a “cleaned up” version of the answer:
public static bool DownloadFileMethod(HttpContext httpContext, string filePath, long speed)
{
// Many changes: mostly declare variables near use
// Extracted duplicate references to HttpContext.Response and .Request
// also duplicate reference to .HttpMethod
// Removed try/catch blocks which hid any problems
var response = httpContext.Response;
var request = httpContext.Request;
var method = request.HttpMethod.ToUpper();
if (method != "GET" &&
method != "HEAD")
{
response.StatusCode = 501;
return false;
}
if (!File.Exists(filePath))
{
response.StatusCode = 404;
return false;
}
// Stream implements IDisposable so should be in a using block
using (var myFile = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var fileLength = myFile.Length;
if (fileLength > Int32.MaxValue)
{
response.StatusCode = 413;
return false;
}
var lastUpdateTiemStr = File.GetLastWriteTimeUtc(filePath).ToString("r");
var fileName = Path.GetFileName(filePath);
var fileNameUrlEncoded = HttpUtility.UrlEncode(fileName, Encoding.UTF8);
var eTag = fileNameUrlEncoded + lastUpdateTiemStr;
var ifRange = request.Headers["If-Range"];
if (ifRange != null && ifRange.Replace(""", "") != eTag)
{
response.StatusCode = 412;
return false;
}
long startBytes = 0;
// Just guessing, but I bet you want startBytes calculated before
// using to calculate content-length
var rangeHeader = request.Headers["Range"];
if (rangeHeader != null)
{
response.StatusCode = 206;
var range = rangeHeader.Split(new[] {'=', '-'});
startBytes = Convert.ToInt64(range[1]);
if (startBytes < 0 || startBytes >= fileLength)
{
// TODO: Find correct status code
response.StatusCode = (int) HttpStatusCode.BadRequest;
response.StatusDescription =
string.Format("Invalid start of range: {0}", startBytes);
return false;
}
}
response.Clear();
response.Buffer = false;
response.AddHeader("Content-MD5", GetMD5Hash(filePath));
response.AddHeader("Accept-Ranges", "bytes");
response.AppendHeader("ETag", string.Format(""{0}"", eTag));
response.AppendHeader("Last-Modified", lastUpdateTiemStr);
response.ContentType = "application/octet-stream";
response.AddHeader("Content-Disposition", "attachment;filename=" +
fileNameUrlEncoded.Replace("+", "%20"));
var remaining = fileLength - startBytes;
response.AddHeader("Content-Length", remaining.ToString());
response.AddHeader("Connection", "Keep-Alive");
response.ContentEncoding = Encoding.UTF8;
if (startBytes > 0)
{
response.AddHeader("Content-Range",
string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
}
// BinaryReader implements IDisposable so should be in a using block
using (var br = new BinaryReader(myFile))
{
br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
const int packSize = 1024*10; //read in block,every block 10K bytes
var maxCount = (int) Math.Ceiling((remaining + 0.0)/packSize); //download in block
for (var i = 0; i < maxCount && response.IsClientConnected; i++)
{
response.BinaryWrite(br.ReadBytes(packSize));
response.Flush();
// HACK: Unexplained sleep
var sleep = (int) Math.Ceiling(1000.0*packSize/speed); //the number of millisecond
if (sleep > 1) Thread.Sleep(sleep);
}
}
}
return true;
}
Method 2
here is the answer!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.IO;
using System.Threading;
using System.Security.Cryptography;
namespace NiceFileExplorer.Classes
{
public class DownloadFile
{
public static bool DownloadFileMethod(HttpContext httpContext, string filePath, long speed)
{
bool ret = true;
try
{
switch (httpContext.Request.HttpMethod.ToUpper())
{ //support Get and head method
case "GET":
case "HEAD":
break;
default:
httpContext.Response.StatusCode = 501;
return false;
}
if (!File.Exists(filePath))
{
httpContext.Response.StatusCode = 404;
return false;
}
//#endregion
var fileInfo = new FileInfo(filePath);
long startBytes = 0;
int packSize = 1024 * 10; //read in block,every block 10K bytes
string fileName = Path.GetFileName(filePath);
FileStream myFile = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader br = new BinaryReader(myFile);
long fileLength = myFile.Length;
int sleep = (int)Math.Ceiling(1000.0 * packSize / speed);//the number of millisecond
string lastUpdateTiemStr = File.GetLastWriteTimeUtc(filePath).ToString("r");
string eTag = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + lastUpdateTiemStr;
//validate whether the file is too large
if (myFile.Length > Int32.MaxValue)
{
httpContext.Response.StatusCode = 413;
return false;
}
if (httpContext.Request.Headers["If-Range"] != null)
{
if (httpContext.Request.Headers["If-Range"].Replace(""", "") != eTag)
{
httpContext.Response.StatusCode = 412;
return false;
}
}
//#endregion
try
{
httpContext.Response.Clear();
httpContext.Response.Buffer = false;
httpContext.Response.AddHeader("Content-MD5", GetMD5Hash(fileInfo));
httpContext.Response.AddHeader("Accept-Ranges", "bytes");
httpContext.Response.AppendHeader("ETag", """ + eTag + """);
httpContext.Response.AppendHeader("Last-Modified", lastUpdateTiemStr);
httpContext.Response.ContentType = "application/octet-stream";
httpContext.Response.AddHeader("Content-Disposition", "attachment;filename=" +
HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace("+", "%20"));
httpContext.Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
httpContext.Response.AddHeader("Connection", "Keep-Alive");
httpContext.Response.ContentEncoding = Encoding.UTF8;
if (httpContext.Request.Headers["Range"] != null)
{
httpContext.Response.StatusCode = 206;
string[] range = httpContext.Request.Headers["Range"].Split(new char[] { '=', '-' });
startBytes = Convert.ToInt64(range[1]);
if (startBytes < 0 || startBytes >= fileLength)
{
return false;
}
}
if (startBytes > 0)
{
httpContext.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
}
//#endregion
//send data
br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
int maxCount = (int)Math.Ceiling((fileLength - startBytes + 0.0) / packSize);//download in block
for (int i = 0; i < maxCount && httpContext.Response.IsClientConnected; i++)
{
httpContext.Response.BinaryWrite(br.ReadBytes(packSize));
httpContext.Response.Flush();
if (sleep > 1) Thread.Sleep(sleep);
}
//#endregion
}
catch
{
ret = false;
}
finally
{
br.Close();
myFile.Close();
}
}
catch
{
ret = false;
}
return ret;
}
private static string GetMD5Hash(FileInfo file)
{
var stream = file.OpenRead();
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(stream);
stream.Close();
var sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
}
}
Method 3
And here’s the official implementation provided by MSDN:
http://code.msdn.microsoft.com/Implement-resume-in-aspnet-c1bbde36/view/SourceCode
Downloader.cs
using System;
using System.IO;
using System.Text;
using System.Web;
namespace CSASPNETResumeDownload
{
public class Downloader
{
public static void DownloadFile(HttpContext httpContext, string filePath)
{
if (!IsFileExists(filePath))
{
httpContext.Response.StatusCode = 404;
return;
}
FileInfo fileInfo = new FileInfo(filePath);
if (fileInfo.Length > Int32.MaxValue)
{
httpContext.Response.StatusCode = 413;
return;
}
// Get the response header information by the http request.
HttpResponseHeader responseHeader = GetResponseHeader(httpContext.Request, fileInfo);
if (responseHeader == null)
{
return;
}
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
try
{
SendDownloadFile(httpContext.Response, responseHeader, fileStream);
}
catch (HttpException ex)
{
httpContext.Response.StatusCode = ex.GetHttpCode();
}
finally
{
fileStream.Close();
}
}
/// <summary>
/// Check whether the file exists.
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private static bool IsFileExists(string filePath)
{
bool fileExists = false;
if (!string.IsNullOrEmpty(filePath))
{
if (File.Exists(filePath))
{
fileExists = true;
}
}
return fileExists;
}
/// <summary>
/// Get the response header by the http request.
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="fileInfo"></param>
/// <returns></returns>
private static HttpResponseHeader GetResponseHeader(HttpRequest httpRequest, FileInfo fileInfo)
{
if (httpRequest == null)
{
return null;
}
if (fileInfo == null)
{
return null;
}
long startPosition = 0;
string contentRange = "";
string fileName = fileInfo.Name;
long fileLength = fileInfo.Length;
string lastUpdateTimeStr = fileInfo.LastWriteTimeUtc.ToString();
string eTag = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + " " + lastUpdateTimeStr;
string contentDisposition = "attachment;filename=" + HttpUtility.UrlEncode(fileName, Encoding.UTF8).Replace("+", "%20");
if (httpRequest.Headers["Range"] != null)
{
string[] range = httpRequest.Headers["Range"].Split(new char[] { '=', '-' });
startPosition = Convert.ToInt64(range[1]);
if (startPosition < 0 || startPosition >= fileLength)
{
return null;
}
}
if (httpRequest.Headers["If-Range"] != null)
{
if (httpRequest.Headers["If-Range"].Replace(""", "") != eTag)
{
startPosition = 0;
}
}
string contentLength = (fileLength - startPosition).ToString();
if (startPosition > 0)
{
contentRange = string.Format(" bytes {0}-{1}/{2}", startPosition, fileLength - 1, fileLength);
}
HttpResponseHeader responseHeader = new HttpResponseHeader();
responseHeader.AcceptRanges = "bytes";
responseHeader.Connection = "Keep-Alive";
responseHeader.ContentDisposition = contentDisposition;
responseHeader.ContentEncoding = Encoding.UTF8;
responseHeader.ContentLength = contentLength;
responseHeader.ContentRange = contentRange;
responseHeader.ContentType = "application/octet-stream";
responseHeader.Etag = eTag;
responseHeader.LastModified = lastUpdateTimeStr;
return responseHeader;
}
/// <summary>
/// Send the download file to the client.
/// </summary>
/// <param name="httpResponse"></param>
/// <param name="responseHeader"></param>
/// <param name="fileStream"></param>
private static void SendDownloadFile(HttpResponse httpResponse, HttpResponseHeader responseHeader, Stream fileStream)
{
if (httpResponse == null || responseHeader == null)
{
return;
}
if (!string.IsNullOrEmpty(responseHeader.ContentRange))
{
httpResponse.StatusCode = 206;
// Set the start position of the reading files.
string[] range = responseHeader.ContentRange.Split(new char[] { ' ','=', '-' });
fileStream.Position = Convert.ToInt64(range[2]);
}
httpResponse.Clear();
httpResponse.Buffer = false;
httpResponse.AppendHeader("Accept-Ranges", responseHeader.AcceptRanges);
httpResponse.AppendHeader("Connection", responseHeader.Connection);
httpResponse.AppendHeader("Content-Disposition", responseHeader.ContentDisposition);
httpResponse.ContentEncoding = responseHeader.ContentEncoding;
httpResponse.AppendHeader("Content-Length", responseHeader.ContentLength);
if (!string.IsNullOrEmpty(responseHeader.ContentRange))
{
httpResponse.AppendHeader("Content-Range", responseHeader.ContentRange);
}
httpResponse.ContentType = responseHeader.ContentType;
httpResponse.AppendHeader("Etag", """ + responseHeader.Etag + """);
httpResponse.AppendHeader("Last-Modified", responseHeader.LastModified);
Byte[] buffer = new Byte[10240];
long fileLength = Convert.ToInt64(responseHeader.ContentLength);
// Send file to client.
while (fileLength > 0)
{
if (httpResponse.IsClientConnected)
{
int length = fileStream.Read(buffer, 0, 10240);
httpResponse.OutputStream.Write(buffer, 0, length);
httpResponse.Flush();
fileLength = fileLength - length;
}
else
{
fileLength = -1;
}
}
}
}
/// <summary>
/// Respresent the HttpResponse header information.
/// </summary>
class HttpResponseHeader
{
public string AcceptRanges { get; set;}
public string Connection { get; set; }
public string ContentDisposition { get; set; }
public Encoding ContentEncoding { get; set; }
public string ContentLength { get; set; }
public string ContentRange { get; set; }
public string ContentType { get; set; }
public string Etag { get; set; }
public string LastModified { get; set; }
}
}
DownloadHttpHandler.ashx.cs
using System;
using System.Configuration;
using System.Web;
namespace CSASPNETResumeDownload
{
public class DownloadHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string filePath = ConfigurationManager.AppSettings["FilePath"];
Downloader.DownloadFile(context, filePath);
}
public bool IsReusable
{
get { return false; }
}
}
}
Method 4
Now, with the new version of asp.net you can use this sample code:
[HttpGet]
[Route(nameof(DownloadFileStream))]
public async Task<FileStreamResult> DownloadFileStream(string pathFile, CancellationToken cancellationToken)
{
FileStream destination = new FileStream(pathFile,...);
return new FileStreamResult(destination, "application/octet-stream")
{
FileDownloadName = "fileName",
EnableRangeProcessing = true // this enable the resume abality
};
}
Method 5
If you can consider using ASP.NET Web API, take a look at my post
ASP.NET Web API file download service with resume support
It provides a solution using two different approaches: FileStream class and memory mapped files (this may offer some performance benefits).
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0