ASP.Net核心内容 - 处置附件/内联

Ted*_*sen 31 c# asp.net-core

我从WebAPI控制器返回一个文件.Content-Disposition标头值自动设置为"attachment".例如:

性格:依恋; 文件名= "30956.pdf"; 文件名*= UTF-8''30956.pdf

当它设置为附件时,浏览器将要求保存文件而不是打开它.我想打开它.

如何将其设置为"内联"而不是"附件"?

我正在使用此方法发送文件:

public IActionResult GetDocument(int id)
{
    var filename = $"folder/{id}.pdf";
    var fileContentResult = new FileContentResult(File.ReadAllBytes(filename), "application/pdf")
    {
        FileDownloadName = $"{id}.pdf"
    };
    // I need to delete file after me
    System.IO.File.Delete(filename);

    return fileContentResult;
}
Run Code Online (Sandbox Code Playgroud)

Ash*_*Lee 55

我找到的最好方法是手动添加内容处理标头.

private IActionResult GetFile(int id)
{
       var file = $"folder/{id}.pdf";

       // Response...
       System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
       {
              FileName = file,
              Inline = displayInline  // false = prompt the user for downloading;  true = browser to try to show the file inline
       };
       Response.Headers.Add("Content-Disposition", cd.ToString());
       Response.Headers.Add("X-Content-Type-Options", "nosniff");

       return File(System.IO.File.ReadAllBytes(file), "application/pdf");
}
Run Code Online (Sandbox Code Playgroud)

  • 快速检查任何努力使其工作的人:确保在构造`FileStreamResult`时不传递`fileDownloadName`参数,否则它将覆盖您的自定义'Content-Disposition'标头! (26认同)
  • 不要使用 `ContentDisposition.ToString()`!!!如果包含单个特殊字符,则所有字符都将进行 Base64 编码并拆分为每个 42 个字符块的新行,例如 `"1234567890123456789012345789012345678ä.pdf"` → `"=?utf-8?B?MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTc4OTAxMjM0NTY3 OMOkLnBk?=\r\n = ?utf-8?B?Zg==?="` 并向 `Response.Headers` 添加新行 → *System.InvalidOperationException*: '标头中的控制字符无效:0x0D' (14认同)
  • 不要使用此方法。正如 Marcel 上面提到的,“System.Net.Mime.ContentDisposition”可能会生成无效的 HTTP 标头值。使用“Microsoft.Net.Http.Headers.ContentDispositionHeaderValue”,如[此答案](/sf/answers/2834309481/)所示。`ContentDispositionHeaderValue` 是 ASP 的一部分,适用于 HTTP,而 `ContentDisposition` 是 dotnet 运行时的一部分,不仅仅适用于 HTTP。 (5认同)

Jon*_*son 19

AspNetCore和的2.0.0版本中AspNetCore.Mvc,我发现以前的答案都不可接受。对我来说,简单地省略filename参数File足以触发内联内容处置。

return File(fileStream, contentType, fileName); // attachment
return File(fileStream, contentType);           // inline
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果用户将文件保存在浏览器中,建议的文件名将是 url 中指定的 id,而不是可能更好的文件名。 (6认同)
  • 在我的 .NET 6 webapi 控制器中,“return File(fileStream, contentType);”不会触发内联内容处置。它根本不生成“Content-Dispositon”响应标头。也许这个接受的答案已经过时了? (4认同)

Cod*_*ter 8

鉴于您不希望在字节数组中一次读取内存中的文件(使用各种File(byte[]...)重载或使用FileContentResult),您可以使用File(Stream, string, string)重载,其中最后一个参数指示文件将在何处下载以供下载:

return File(stream, "content/type", "FileDownloadName.ext");
Run Code Online (Sandbox Code Playgroud)

或者,您可以利用支持流式传输的现有响应类型(例如a)FileStreamResult,并自行设置内容处置.如图所示,执行此操作的规范方法FileResultExecutorBase是在操作方法中简单地在响应上设置标题:

// Set up the content-disposition header with proper encoding of the filename
var contentDisposition = new ContentDispositionHeaderValue("attachment");
contentDisposition.SetHttpFileName("FileDownloadName.ext");
Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();

// Return the actual filestream
return new FileStreamResult(@"path\to\file", "content/type");
Run Code Online (Sandbox Code Playgroud)

  • OP 说“我怎样才能将其设置为“内联”而不是“附件”?”。“File()”和更详细的示例都会强制模式为“attachment”,尽管后者很容易被破解为“inline” (4认同)

huy*_*itw 7

您可以覆盖默认FileContentResult类,以便您可以在代码中使用它,只需进行最少的更改:

public class InlineFileContentResult : FileContentResult
{
    public InlineFileContentResult(byte[] fileContents, string contentType)
        : base(fileContents, contentType)
    {
    }

    public override Task ExecuteResultAsync(ActionContext context)
    {
        var contentDispositionHeader = new ContentDispositionHeaderValue("inline");
        contentDispositionHeader.SetHttpFileName(FileDownloadName);
        context.HttpContext.Response.Headers.Add(HeaderNames.ContentDisposition, contentDispositionHeader.ToString());
        FileDownloadName = null;
        return base.ExecuteResultAsync(context);
    }
}
Run Code Online (Sandbox Code Playgroud)

可以对以下内容执行相同的操作FileStreamResult

public class InlineFileStreamResult : FileStreamResult
{
    public InlineFileStreamResult(Stream fileStream, string contentType)
        : base(fileStream, contentType)
    {
    }

    public override Task ExecuteResultAsync(ActionContext context)
    {
        var contentDispositionHeader = new ContentDispositionHeaderValue("inline");
        contentDispositionHeader.SetHttpFileName(FileDownloadName);
        context.HttpContext.Response.Headers.Add(HeaderNames.ContentDisposition, contentDispositionHeader.ToString());
        FileDownloadName = null;
        return base.ExecuteResultAsync(context);
    }
}
Run Code Online (Sandbox Code Playgroud)

而不是返回FileContentResultor FileStreamResult,只需返回InlineFileContentResultor InlineFileStreamResult。铁:

public IActionResult GetDocument(int id)
{
    var filename = $"folder/{id}.pdf";
    return new InlineFileContentResult(File.ReadAllBytes(filename), "application/pdf")
    {
        FileDownloadName = $"{id}.pdf"
    };
}
Run Code Online (Sandbox Code Playgroud)

警告

正如makman99所指出的,不要使用ContentDisposition该类来生成标头值,因为它会在标头值中插入换行符以获得更长的文件名。


Sil*_*tre 7

这些解决方案都不适合我。唯一对我有用的是更新后端的 Cors:

        services.AddCors(o => o.AddPolicy("MyPolicy", b =>
        {
            b.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader()
                   .WithExposedHeaders("Content-Disposition");
        }));
Run Code Online (Sandbox Code Playgroud)

所以标题会被暴露。此后,我不需要向响应添加任何额外的标头。

如果您不想更新 Startup.cs,您可以手动允许该响应的标头:

        HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
        HttpContext.Response.Headers.Add("Content-Disposition", <your_header_value>);
Run Code Online (Sandbox Code Playgroud)


myr*_*yro 5

由于File()会忽略Content-Disposition我使用了这个:

Response.Headers[HeaderNames.ContentDisposition] = new MimeKit.ContentDisposition { FileName = fileName, Disposition = MimeKit.ContentDisposition.Inline }.ToString();
return new FileContentResult(System.IO.File.ReadAllBytes(filePath), "application/pdf");
Run Code Online (Sandbox Code Playgroud)

它有效:-)