HttpHandler 在下载时不保留文件名

HttpHandler not retaining filenames on download

我正在使用 HttpHandler 在我的 ASP.NET 网络应用程序中提供文档。我可以让它正常工作,但有一个我不太清楚的问题 -- 文件名未保留。

例如,如果我尝试提供一个名为 "New Patient Information Form.docx" 的文档,而我的处理程序名为 "GetDocument.ashx",则文件将下载为 "GetDocument.docx" 和 "GetDocument(1).docx","GetDocument(2).docx"等我每次下载文件。

出于安全原因,我想使用处理程序而不是直接链接到文件。我将实际文档保存在 App_Data 文件夹中,因此无法直接浏览它们。

这是我正在使用的代码。我已经在 "attachment" 和 "inline" 之间切换了内容配置,但似乎都没有对更正此问题产生任何影响。

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();
}

我的代码中的 "document" 对象是 class 具有与文档元数据相关的属性(例如文件名、ID 等)

我同时使用 Chrome 和 Edge 作为浏览器,并且都表现出相同的行为。有没有办法让 HttpHandler 保留原始文件名?

更新:我用简化的代码创建了一个新项目,试图缩小问题的原因。这是代码:

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;
        }
    }

文件名不包含空格,浏览器尝试将文件保存为 "DownloadFile.ashx" 而不是 "NoSpaces.docx"。我开始怀疑浏览器是否应该受到指责,因为我记得最后一次这项工作是在五月份。

尝试用双引号括起文件名,如下所示:

context.Response.AppendHeader("Content-Dispositon", $"attachment; filename=\"{document.Filename}\"");

我发现了问题,这完全解释了为什么所有浏览器的行为方式都相同。我有点惊讶没有其他人发现这个但它是:

我把 "Content-Disposition" 拼成了 "Content-Dispositon"。它忽略了文件名,因为 header 名称不正确。

我将需要检查所有其他处理程序并确保它也拼写正确!