我正在尝试在MVC中实现文件下载。这是当前的代码:
Response.Clear();
Response.Charset = "utf8";
Response.ContentType = string.IsNullOrEmpty(dokument.mimeType) ? MimeHelper.GetMimeFromBytes(dokument.Bin) : dokument.mimeType;
Response.AddHeader("Content-Disposition", "attachment; filename*=UTF-8''" + dokument.Nazwa.Replace(" ", "_").Replace(";", "%3B").Replace(",", "%2C"));
Response.BinaryWrite(dokument.Bin);
Response.Flush();
Response.End();
它工作得很好但是一些文件是以其数据库ID作为名称下载的。此值作为参数传递给Action。其他文件正确下载,我找不到它的原因。有谁知道可能有什么问题?
如果我删除'* = UTF-8''“逗号和分号代码未更改。
答案 0 :(得分:1)
在某些情况下,很可能你的标题有问题。
生成正确的Content-Disposition
标头比这复杂一点。最好从框架中已有的实现开始,只有在需要时才会选择 RFC 2231 ,如下所示:
public class ContentDispositionUtil
{
public static string GetContentDisposition(string fileName)
{
try
{
return (new ContentDisposition() { FileName = fileName }).ToString();
}
catch (FormatException)
{
return GetRfc2231ContentDisposition(fileName);
}
}
}
GetRfc2231ContentDisposition
的实施是棘手的部分。通常,如果文件名中的每个字符对标题有效,并且如果没有正确编码,则需要检查它们。检查可以通过以下方法完成:
private static bool IsValidRfc2231ContentDispositionCharacter(byte character)
{
if ((byte)'0' <= character && character <= (byte)'9')
return true;
if ((byte)'a' <= character && character <= (byte)'z')
return true;
if ((byte)'A' <= character && character <= (byte)'Z')
return true;
switch (character)
{
case (byte)'-':
case (byte)'.':
case (byte)'_':
case (byte)'~':
case (byte)':':
case (byte)'!':
case (byte)'$':
case (byte)'&':
case (byte)'+':
return true;
}
return false;
}
简单的实现,但它显示了允许的字符。现在你可以进行这样的编码:
private const string _hexDigits = "0123456789ABCDEF";
private static string EncodeInvalidRfc2231ContentDispositionCharacter(int character)
{
return "%" + _hexDigits[character >> 4] + _hexDigits[character % 16];
}
现在我们已准备好生成标题:
private static string GetRfc2231ContentDisposition(string filename)
{
StringBuilder contentDispositionBuilder = new StringBuilder("attachment; filename*=UTF-8''");
byte[] filenameBytes = Encoding.UTF8.GetBytes(filename);
foreach (byte character in filenameBytes)
{
if (IsValidRfc2231ContentDispositionCharacter(character))
contentDispositionBuilder.Append((char)character);
else
{
contentDispositionBuilder.Append(EncodeInvalidRfc2231ContentDispositionCharacter((int)character));
}
}
return contentDispositionBuilder.ToString();
}
现在你应该总是得到合适的标题。
P.S。当然,只有在需要的时候才能做到这一切,并尽可能使用FileResult
提供的内置行动结果;)
答案 1 :(得分:0)
实际上我已经将标题生成更改为return File()
并且它工作正常,尽管tpeczek提供的算法也可以。