使用FileResult在Asp.Net MVC中下载任何类型的文件?

And*_*ers 219 c# asp.net-mvc-2

我已经告诉过我应该使用FileResult来允许用户从我的Asp.Net MVC应用程序下载文件.但我能找到的唯一例子总是与图像文件有关(指定内容类型image/jpeg).

但是,如果我不知道文件类型怎么办?我希望用户能够从我网站的文件区下载几乎任何文件.

我已经阅读了一个这样做的方法(参见前面的代码文章),实际上工作正常,除了一件事:"另存为"对话框中出现的文件名与带有下划线的文件路径连接在一起( folder_folder_file.ext).此外,似乎人们认为我应该返回一个FileResult而不是使用我找到BinaryContentResult的自定义类.

有人知道在MVC中进行这种下载的"正确"方式吗?

编辑:我得到了答案(下面),但我想如果其他人感兴趣我应该发布完整的工作代码:

public ActionResult Download(string filePath, string fileName)
{
    string fullName = Path.Combine(GetBaseDir(), filePath, fileName);

    byte[] fileBytes = GetFile(fullName);
    return File(
        fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

byte[] GetFile(string s)
{
    System.IO.FileStream fs = System.IO.File.OpenRead(s);
    byte[] data = new byte[fs.Length];
    int br = fs.Read(data, 0, data.Length);
    if (br != fs.Length)
        throw new System.IO.IOException(s);
    return data;
}
Run Code Online (Sandbox Code Playgroud)

Ian*_*nry 407

您只需指定通用八位字节流MIME类型:

public FileResult Download()
{
    byte[] fileBytes = System.IO.File.ReadAllBytes(@"c:\folder\myfile.ext");
    string fileName = "myfile.ext";
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
Run Code Online (Sandbox Code Playgroud)

  • 因为这个答案差不多有五年了,是的.如果您这样做是为了提供非常大的文件,请不要这样做.如果可能,请使用单独的静态文件服务器,这样就不会占用应用程序线程,也不会为自2010年以来添加到MVC的文件提供许多新技术之一.这只显示MIME类型未知时要使用的正确MIME类型.几年后,在一个编辑中添加了"ReadAllBytes".为什么这是我第二个最受欢迎的答案?那好吧. (13认同)
  • 得到此错误:`non-invocable member"File"不能像方法一样使用 (10认同)
  • 这会将整个文件加载到内存中以便将其流出; 对于大文件,这是一头猪.一个更好的解决方案是下面的解决方案,不必先将文件加载到内存中. (5认同)
  • 好的,我可以尝试一下,但是byte []数组是什么? (4认同)
  • 没关系,我想我想通了.我将文件名(完整路径)读入FileStream,然后读入字节数组,然后它像魅力一样工作!谢谢! (3认同)

Jon*_*han 104

MVC框架原生支持这一点.所述System.Web.MVC.Controller.File控制器提供的方法通过返回一个文件//阵列.

例如,使用文件的虚拟路径,您可以执行以下操作.

return File(virtualFilePath, System.Net.Mime.MediaTypeNames.Application.Octet,  Path.GetFileName(virtualFilePath));
Run Code Online (Sandbox Code Playgroud)


Sal*_*han 34

如果您使用的是.NET Framework 4.5,那么您可以使用MimeMapping.GetMimeMapping(字符串FileName)来获取文件的MIME类型.这就是我在行动中使用它的方式.

return File(Path.Combine(@"c:\path", fileFromDB.FileNameOnDisk), MimeMapping.GetMimeMapping(fileFromDB.FileName), fileFromDB.FileName);
Run Code Online (Sandbox Code Playgroud)


Man*_*ous 11

Phil Haack有一篇很好的文章,他在那里创建了一个Custome File Download Action Result类.您只需指定文件的虚拟路径和要保存的名称.

我用了一次,这是我的代码.

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Download(int fileID)
        {
            Data.LinqToSql.File file = _fileService.GetByID(fileID);

            return new DownloadResult { VirtualPath = GetVirtualPath(file.Path),
                                        FileDownloadName = file.Name };
        }
Run Code Online (Sandbox Code Playgroud)

在我的例子中,我存储了文件的物理路径,所以我使用了这个帮助器方法 - 我找到了一个我记不起来的地方 - 将它转换为虚拟路径

        private string GetVirtualPath(string physicalPath)
        {
            string rootpath = Server.MapPath("~/");

            physicalPath = physicalPath.Replace(rootpath, "");
            physicalPath = physicalPath.Replace("\\", "/");

            return "~/" + physicalPath;
        }
Run Code Online (Sandbox Code Playgroud)

这是完整的课程,取自Phill Haack的文章

public class DownloadResult : ActionResult {

    public DownloadResult() {}

    public DownloadResult(string virtualPath) {
        this.VirtualPath = virtualPath;
    }

    public string VirtualPath {
        get;
        set;
    }

    public string FileDownloadName {
        get;
        set;
    }

    public override void ExecuteResult(ControllerContext context) {
        if (!String.IsNullOrEmpty(FileDownloadName)) {
            context.HttpContext.Response.AddHeader("content-disposition", 
            "attachment; filename=" + this.FileDownloadName)
        }

        string filePath = context.HttpContext.Server.MapPath(this.VirtualPath);
        context.HttpContext.Response.TransmitFile(filePath);
    }
}
Run Code Online (Sandbox Code Playgroud)


Dev*_*per 5

感谢Ian Henry

如果您需要从MS SQL Server获取文件,这里是解决方案。

public FileResult DownloadDocument(string id)
        {
            if (!string.IsNullOrEmpty(id))
            {
                try
                {
                    var fileId = Guid.Parse(id);

                    var myFile = AppModel.MyFiles.SingleOrDefault(x => x.Id == fileId);

                    if (myFile != null)
                    {
                        byte[] fileBytes = myFile.FileData;
                        return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, myFile.FileName);
                    }
                }
                catch
                {
                }
            }

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

其中AppModelEntityFramework模型,而MyFiles在数据库中显示的FileDatavarbinary(MAX)MYFILES表。