我使用以下类来获得更多 content-disposition header 的选项。
它的工作方式与 Marnix 答案 相当相似,但是它不是完全使用 ContentDisposition 类生成头部,而是调整 MVC 生成的头部(该头部符合 RFC),因为当文件名必须 utf-8 编码时,ContentDisposition 类不遵守 RFC。
(最初,我在 回答其他问题时 写了这一部分,并且还有 另一个。)
using System;
using System.IO;
using System.Web;
using System.Web.Mvc;
namespace Whatever
{
public class FilePathResultEx : FilePathResult
{
public bool Inline { get; set; }
public bool IncludeSize { get; set; }
public FilePathResultEx(string fileName, string contentType) : base(fileName, contentType) { }
public override void ExecuteResult(ControllerContext context)
{
FileResultUtils.ExecuteResultWithHeadersRestoredOnFailure(context, base.ExecuteResult);
}
protected override void WriteFile(HttpResponseBase response)
{
if (Inline)
FileResultUtils.TweakDispositionAsInline(response);
if (IncludeSize && File.Exists(FileName))
{
var fileInfo = new FileInfo(FileName);
FileResultUtils.TweakDispositionSize(response, fileInfo.Length);
}
base.WriteFile(response);
}
}
public class FileStreamResultEx : FileStreamResult
{
public bool Inline { get; set; }
public long Size { get; set; }
public FileStreamResultEx(Stream fileStream, string contentType) : base(fileStream, contentType) { }
public override void ExecuteResult(ControllerContext context)
{
FileResultUtils.ExecuteResultWithHeadersRestoredOnFailure(context, base.ExecuteResult);
}
protected override void WriteFile(HttpResponseBase response)
{
if (Inline)
FileResultUtils.TweakDispositionAsInline(response);
FileResultUtils.TweakDispositionSize(response, Size);
base.WriteFile(response);
}
}
public class FileContentResultEx : FileContentResult
{
public bool Inline { get; set; }
public bool IncludeSize { get; set; }
public FileContentResultEx(byte[] fileContents, string contentType) : base(fileContents, contentType) { }
public override void ExecuteResult(ControllerContext context)
{
FileResultUtils.ExecuteResultWithHeadersRestoredOnFailure(context, base.ExecuteResult);
}
protected override void WriteFile(HttpResponseBase response)
{
if (Inline)
FileResultUtils.TweakDispositionAsInline(response);
if (IncludeSize)
FileResultUtils.TweakDispositionSize(response, FileContents.LongLength);
base.WriteFile(response);
}
}
public static class FileResultUtils
{
public static void ExecuteResultWithHeadersRestoredOnFailure(ControllerContext context, Action<ControllerContext> executeResult)
{
if (context == null)
throw new ArgumentNullException("context");
if (executeResult == null)
throw new ArgumentNullException("executeResult");
var response = context.HttpContext.Response;
var previousContentType = response.ContentType;
try
{
executeResult(context);
}
catch
{
if (response.HeadersWritten)
throw;
response.ContentType = previousContentType;
response.Headers.Remove(ContentDispositionHeader);
throw;
}
}
private const string ContentDispositionHeader = "Content-Disposition";
public static void TweakDispositionAsInline(HttpResponseBase response)
{
var disposition = response.Headers[ContentDispositionHeader];
const string downloadModeToken = "attachment;";
if (string.IsNullOrEmpty(disposition) || !disposition.StartsWith(downloadModeToken, StringComparison.OrdinalIgnoreCase))
return;
response.Headers.Remove(ContentDispositionHeader);
response.Headers.Add(ContentDispositionHeader, "inline;" + disposition.Substring(downloadModeToken.Length));
}
public static void TweakDispositionSize(HttpResponseBase response, long size)
{
if (size <= 0)
return;
var disposition = response.Headers[ContentDispositionHeader];
const string sizeToken = "size=";
if (string.IsNullOrEmpty(disposition) || disposition.Contains(sizeToken))
return;
response.Headers.Remove(ContentDispositionHeader);
response.Headers.Add(ContentDispositionHeader, disposition + "; " + sizeToken + size.ToString());
}
}
}
使用示例:
public FileResult Download(int id)
{
...
return
new FilePathResultEx(filepath, System.Web.MimeMapping.GetMimeMapping(filename))
{
FileDownloadName = filename,
Inline = true
};
}
请注意,使用
Inline
指定文件名在Internet Explorer中无法正常工作(包括11版和Windows 10 Edge版,在某些pdf文件上进行了测试),而在Firefox和Chrome中可以正常工作。Internet Explorer将忽略文件名。对于Internet Explorer,您需要修改URL路径,这在我看来相当糟糕。请参见
this answer。