我从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;
}
答案 0 :(得分:44)
我找到的最好方法是手动添加内容处理标题。
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");
}
答案 1 :(得分:9)
对于AspNetCore
和AspNetCore.Mvc
的2.0.0版本,我发现以前的答案都不可接受。对我来说,只需将File
的filename参数省略就足以触发内联内容处置。
return File(fileStream, contentType, fileName); // attachment
return File(fileStream, contentType); // inline
答案 2 :(得分:8)
鉴于您不希望在字节数组中一次读取内存中的文件(使用各种File(byte[]...)
重载或使用FileContentResult
),您可以使用File(Stream, string, string)
overload,其中最后一个参数表示文件的下载名称:
return File(stream, "content/type", "FileDownloadName.ext");
或者您可以利用支持流式传输的现有响应类型,例如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");
答案 3 :(得分:3)
由于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");
它有效: - )
答案 4 :(得分:1)
使用HttpResponseMessage
public IActionResult GetDocument(int id)
{
var filename = $"folder/{id}.pdf";
Response.Headers["Content-Disposition"] = $"inline; filename={id}.pdf";
var fileContentResult = new FileContentResult(System.IO.File.ReadAllBytes(filename), "application/pdf")
{
FileDownloadName = $"{id}.pdf"
};
// I need to delete file after me
System.IO.File.Delete(filename);
return fileContentResult;
}
答案 5 :(得分:1)
使用与@ ashley-lee类似的方法的Asp.Net MVC方法
注意:Chrome下载附件。请参阅Ctrl-J列表。但是,如果用户选择“打开”,它将在“浏览器”中打开,用户将不得不选择“在系统查看器中打开”。例如,在基于浏览器的PDF查看器中看不到PDF签名字段。
[HttpGet]
public ActionResult GenericForm()
{
return new DownloadFileAsAttachmentResult(@"GenericForm.pdf", @"\Content\files\GenericForm.pdf", "application/pdf");
}
public class DownloadFileAsAttachmentResult : ActionResult
{
private string _filenameWithExtension { get; set; }
private string _filePath { get; set; }
private string _contentType { get; set; }
// false = prompt the user for downloading; true = browser to try to show the file inline
private const bool DisplayInline = false;
public DownloadFileAsAttachmentResult(string FilenameWithExtension, string FilePath, string ContentType)
{
_filenameWithExtension = FilenameWithExtension;
_filePath = FilePath;
_contentType = ContentType;
}
public override void ExecuteResult(ControllerContext context)
{
HttpResponseBase response = context.HttpContext.Response;
response.Buffer = false;
response.ContentType = _contentType;
response.AddHeader("Content-Disposition", "attachment; filename=" + _filenameWithExtension); // force download
response.AddHeader("X-Content-Type-Options", "nosniff");
response.TransmitFile(_filePath);
}
}
答案 6 :(得分:0)
您可以覆盖默认的FileContentResult
类,以便可以在代码中使用它,而只需进行很少的更改:
public class InlineFileContentResult : FileContentResult
{
public InlineFileContentResult(byte[] fileContents, string contentType)
: base(fileContents, contentType)
{
}
public override Task ExecuteResultAsync(ActionContext context)
{
var contentDispositionHeader = new ContentDisposition
{
FileName = FileDownloadName,
Inline = true,
};
context.HttpContext.Response.Headers.Add("Content-Disposition", contentDispositionHeader.ToString());
FileDownloadName = null;
return base.ExecuteResultAsync(context);
}
}
对于FileStreamResult
可以这样做:
public class InlineFileStreamResult : FileStreamResult
{
public InlineFileStreamResult(Stream fileStream, string contentType)
: base(fileStream, contentType)
{
}
public override Task ExecuteResultAsync(ActionContext context)
{
var contentDispositionHeader = new ContentDisposition
{
FileName = FileDownloadName,
Inline = true,
};
context.HttpContext.Response.Headers.Add("Content-Disposition", contentDispositionHeader.ToString());
FileDownloadName = null;
return base.ExecuteResultAsync(context);
}
}
返回FileContentResult
或FileStreamResult
而不是返回InlineFileContentResult
或InlineFileStreamResult
。 F.e。:
public IActionResult GetDocument(int id)
{
var filename = $"folder/{id}.pdf";
return new InlineFileContentResult(File.ReadAllBytes(filename), "application/pdf")
{
FileDownloadName = $"{id}.pdf"
};
}
答案 7 :(得分:0)
基于Ashley Lee的回答,但使用的是ASP.Net Core东西,可以解决某些文件名模式的问题。请注意,内联是默认的内容处理方式,因此,如果您不需要指定文件名(如果用户在浏览器中单击“保存”,则会建议使用该文件名),您可以按照Jonathan Wilson的建议简单地省略内容处理方式。>
private IActionResult GetFile(int id)
{
var file = $"folder/{id}.pdf";
// Response...
var cd = new ContentDispositionHeaderValue("inline");
cd.SetHttpFileName(file);
Response.Headers[HeaderNames.ContentDisposition] = cd.ToString();
Response.Headers.Add("X-Content-Type-Options", "nosniff");
return File(System.IO.File.ReadAllBytes(file), "application/pdf");
}
答案 8 :(得分:0)
我遵循了@myro's的回答。对于我的.net core 3.1 Web API,我在System.Net.Mime命名空间中找到了ContentDisposition类和常量。
var result = new FileContentResult(System.IO.File.ReadAllBytes(filePath), mimeType);
var dispositionType = asAttachment
? System.Net.Mime.DispositionTypeNames.Attachment
: System.Net.Mime.DispositionTypeNames.Inline;
Response.Headers[HeaderNames.ContentDisposition] = new
System.Net.Mime.ContentDisposition { FileName = "file.text",
DispositionType = dispositionType }.ToString();
return result;
答案 9 :(得分:0)
在经典的Razor页面(在ASP.NET Core 3.1中测试)中尝试此代码。对于强制下载,使用查询参数“?download = 1”。如您所见,有必要将参数“ attachment”添加到特定位置的“ Content-Disposition”标题中。
public class FilesModel : PageModel
{
IWebHostEnvironment environment;
public FilesModel(IWebHostEnvironment environment)
{
this.environment = environment;
}
public PhysicalFileResult OnGet()
{
// Query params
string fileName = Request.Query["filename"];
bool forcedDownload = Request.Query["download"] == "1";
// File Path
string filePath = Path.Combine(env.ContentRootPath, "secret-files", fileName);
if (!System.IO.File.Exists(filePath)) return null; // File not exists
// Make sure that the user has permissions on the file...
// File info
string mime = "image/png"; // Choose the right mime type...
long fileSize = new FileInfo(filePath).Length;
string sendType = forcedDownload ? "attachment" : "inline";
// Headers
Response.Headers.Add("Content-Disposition", $"{sendType};filename=\"{fileName}\"");
Response.Headers.Add("Content-Length", fileSize.ToString());
Response.Headers.Add("X-Content-Type-Options", "nosniff");
// Result
return new PhysicalFileResult(filePath, mime);
}
}
答案 10 :(得分:0)
对于ASP.NET Core 3.1,似乎没有任何内置方法可以返回带有“ Content-Disposition:inline”和文件名的文件。我创建了以下效果很好的帮助程序类。
public class InlineFileActionResult : IActionResult
{
private readonly Stream _stream;
private readonly string _filename;
private readonly string _contentType;
public InlineFileActionResult(Stream stream, string filename, string contentType)
{
_stream = stream;
_filename = filename;
_contentType = contentType;
}
public InlineFileActionResult(byte[] file, string filename, string contentType)
: this(new MemoryStream(file), filename, contentType) {}
public async Task ExecuteResultAsync(ActionContext context)
{
byte[] file;
if (_stream is MemoryStream memoryStream)
file = memoryStream.ToArray();
else
{
await using var ms = new MemoryStream();
await _stream.CopyToAsync(ms);
file = ms.ToArray();
}
context.HttpContext.Response.Headers[HeaderNames.ContentType] = _contentType;
context.HttpContext.Response.Headers[HeaderNames.ContentLength] = file.Length.ToString();
context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] =
$"{System.Net.Mime.DispositionTypeNames.Inline}; filename=\"{_filename}\";";
await context.HttpContext.Response.Body.WriteAsync(file, 0, file.Length);
}
}
要使用,请从控制器返回类(其返回方法必须为IActionResult)。一个示例如下所示:
[HttpGet]
public IActionResult Index()
{
var filepath = "C:\Path\To\Document.pdf";
return new InlineFileActionResult(new FileStream(filepath, FileMode.Open),
Path.GetFileName(filepath), "application/pdf");
}
答案 11 :(得分:0)
这些解决方案都不适合我。唯一对我有用的是更新后端的 Cors:
services.AddCors(o => o.AddPolicy("MyPolicy", b =>
{
b.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.WithExposedHeaders("Content-Disposition");
}));
所以标题会被暴露。在此之后,我不需要在响应中添加任何额外的标头。
如果您不想更新 Startup.cs,您可以手动允许该响应的标头:
HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
HttpContext.Response.Headers.Add("Content-Disposition", <your_header_value>);
答案 12 :(得分:0)
这在 asp.net core 5.0 中仅适用于我,希望这也适用于以前的版本,因为我在 asp.net 4.8 中使用相同
Response.ContentType = "application/pdf";
Response.Headers.Add("pragma", "no-cache, public");
Response.Headers.Add("cache-control", "private, nocache, must-revalidate, maxage=3600");
Response.Headers.Add("content-disposition", "inline;filename=" + fileName);
返回文件(字节,“应用程序/pdf”);