我有一个像这样定义的MVC控制器方法:
public ActionResult GetPdf(string filename)
{
var pdfDownload = File("~/Content/GeneratedReports/report1.pdf", "application/pdf", Server.UrlEncode("report1.pdf"));
return pdfDownload;
}
如果我将第一个参数更改为托管在单独的云服务器上的服务器的URL,那么我会收到错误:
'我的文件路径'不是有效的虚拟路径。
我只是希望我的客户能够下载文件。这似乎比它需要的要复杂得多。
我有一个指向PDF的网址。我希望我的客户在不点击任何内容的情况下下载该pdf。 (下载将在成功的服务响应后启动)
为什么这么难,我该如何解决?
我不在乎解决方案是在JS还是MVC ....
答案 0 :(得分:8)
为什么这么难,我该如何解决?
实际上,并不难:
public ActionResult GetPdf(string filename)
{
using (var client = new WebClient())
{
var buffer = client.DownloadData("http://foo.com/bar.pdf");
return File(buffer, "application/pdf", "report1.pdf");
}
}
现在显然这个方法有一个严重的缺陷,因为它会将文件缓存在内存中。虽然这对小报告很有用,但对于大文件来说可能会有问题,如果你有很多用户不耐烦地掌握这个伟大的报告,那就更有问题了。
第一个控制器动作还有另一个严重的缺陷。它混合了责任。它包含基础设施代码,我挑战你单独测试它。
因此,让我们通过编写自定义操作结果解决这两个严重问题:
public class ReportResult : ActionResult
{
private readonly string _filename;
public ReportResult(string filename)
{
_filename = filename;
}
public override void ExecuteResult(ControllerContext context)
{
var cd = new ContentDisposition
{
FileName = _filename,
Inline = false
};
var response = context.HttpContext.Response;
response.ContentType = "application/pdf";
response.Headers["Content-Disposition"] = cd.ToString();
using (var client = new WebClient())
using (var stream = client.OpenRead("http://foo.com/" + _filename))
{
// in .NET 4.0 implementation this will process in chunks
// of 4KB
stream.CopyTo(response.OutputStream);
}
}
}
你会这样使用:
public ActionResult GetPdf(string filename)
{
return new ReportResult(filename);
}
并在您看来:
@Html.ActionLink("Download report", "GetPdf", new { filename = "report.pdf" })
或者您可以完全质疑控制器操作的有用性,因为在您的视图中而不是:
@Html.ActionLink("Download report", "GetPdf")
你可以直接:
<a href="http://foo.com/bar.pdf">Download report</a>
假设客户端当然可以访问此服务器。
备注:请谨慎对待您在Content-Disposition
标题中发送的文件名。我在你的问题中看到你使用了像Server.UrlEncode("report1.pdf")
这样的东西。查看following question以了解可能变成的噩梦。
答案 1 :(得分:2)
您可以在远程报告中重定向用户;如果这不是一个选项,你需要代理它:
byte[] blob;
using(var client = new WebClient()) {
blob = client.DownloadData(remoteUrl);
}
return File(blob, "application/pdf", "report1.pdf");
以上假设文件不是很大;一个更健壮的实现将以块的形式获取和发送。
答案 2 :(得分:0)
我正在做类似的例行公事。现在我让它从本地驱动器访问图像
byte [] cimage = new WebClient()。DownLoadData(System.Web.HttpContent.Server.MapPath(“〜/ Content / koala.jpg”));
我如何访问SQL Server上的共享。我在SQL Server上的文件夹中有想要检索的图像。
byte [] cimage = new WebClient()。DownLoadData(“Server share”+ /Files/koala.jpg“);