问题
I am using an HttpHandler to serve documents within my ASP.NET web application. I can get it to work just fine with one issue which I can't quite figure out -- the filename isn't retained.
For example, if I am trying to serve a document called "New Patient Information Form.docx" and my handler is called "GetDocument.ashx" the file is downloaded as "GetDocument.docx" and "GetDocument(1).docx", "GetDocument(2).docx" etc. each time I download the file.
I want to use a handler instead of linking to the files directly for security reasons. I'm keeping the actual documents in the App_Data folder so they can't be browsed to directly.
Here's the code I'm using. I've switched the content disposition between "attachment" and "inline" but neither seem to have any affect on correcting this problem.
public void ProcessRequest(HttpContext context)
{
if (!int.TryParse(context.Request.QueryString["ID"], out var id))
throw new Exception($"Invalid DocumentID value ({id}).");
var document = DocumentsHelper.GetByID(id);
if (document == null)
throw new Exception($"Invalid DocumentID value ({id}).");
var documentDownloadDirectory = AppSettingsHelper.DocumentDownloadDirectory(); // "App_Data"
var filePath = Path.Combine(documentDownloadDirectory, document.Filename);
var fileBytes = File.ReadAllBytes(filePath);
// A content disposition of "attachment" will force a "Save or Open" dialog to appear when
// navigating directly to this URL, and "inline" will just show open the file in the default viewer
context.Response.AppendHeader("Content-Dispositon", $"attachment; filename={document.Filename}");
context.Response.AppendHeader("Content-Length", fileBytes.Length.ToString());
context.Response.ContentType = document.ContentType;
context.Response.BinaryWrite(fileBytes);
context.Response.Flush();
}
The "document" object in my code is a class with properties relating to the document metadata (such as the filename, ID, etc.)
I am using both Chrome and Edge as the browser and both exhibit this same behavior. Is there a way for an HttpHandler to retain the original filename?
Update: I've created a new project with simplified code to try to narrow down the cause of the problem. Here's the code:
public class DownloadFile : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var fileName = "NoSpaces.docx";
var basePath = context.Request.MapPath("~/App_Data");
var filePath = Path.Combine(basePath, fileName);
var fileBytes = File.ReadAllBytes(filePath);
context.Response.AppendHeader("Content-Dispositon", $"attachment; filename={fileName}");
context.Response.AppendHeader("Content-Length", fileBytes.Length.ToString());
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
context.Response.BinaryWrite(fileBytes);
context.Response.Flush();
}
public bool IsReusable
{
get
{
return false;
}
}
The filename does not contain spaces and the browser attempts to save the file as "DownloadFile.ashx" instead of "NoSpaces.docx". I am starting to wonder if the browsers are to blame as the last time I remember this working was back in May.
回答1:
Try wrapping the filename inside double quotes like this:
context.Response.AppendHeader("Content-Dispositon", $"attachment; filename=\"{document.Filename}\"");
回答2:
I found the problem and this totally makes sense why all browsers behave the same way. I'm a bit surprised nobody else caught this but here it is:
I spelled "Content-Disposition" as "Content-Dispositon". It was ignoring the filename because the header name was incorrect.
I'm going to need to check all other handlers and make sure it's spelled correctly there too!
来源:https://stackoverflow.com/questions/51714522/httphandler-not-retaining-filenames-on-download