【问题标题】:Displaying pdf files in a web page from a sql database directly without needing to save them to the server file system直接从sql数据库在网页中显示pdf文件,无需保存到服务器文件系统
【发布时间】:2011-12-06 13:29:27
【问题描述】:

我目前正在使用 html 嵌入标签来显示保存在本地服务器上的 pdf 文件。有没有一种方法可以在我的页面上显示 pdf 文件而无需将其保存到服务器的本地文件系统中?我只是想将它从控制器传递给视图,这样它就可以在页面中显示为 pdf 而无需直接存储在文件系统中。

或者,一旦用户离开他们正在查看的页面,是否有办法调用从服务器中删除 pdf 文件的方法?我如何判断用户是否已离开页面以及如何导致它触发将删除文件的方法?

【问题讨论】:

  • 你可以从内存中流式传输它......虽然这不会很好地扩展......
  • 您对第三方工具持开放态度吗?
  • 您正在生成我假设的这个 PDF 文件?如果是这样,您应该能够将其从您正在处理的任何格式(例如 iTextSharp)直接流式传输到响应中。
  • 我正在上传 pdf 文件并将其存储在数据库中,并且想知道如何正确存储和检索它们以便在我的视图中显示,而无需将它们保存到文件系统中。在我看来,必须暂时将它们保存到文件系统中,这违背了让数据库开始的目的。

标签: c# sql asp.net-mvc-3 pdf embed


【解决方案1】:

我创建了一个名为 PdfResult 的 MVC 类,它以 PDF 文件的形式返回一个字节数组。

目的如下(无法上传源代码,抱歉):

  1. PdfResult 继承自 FileStreamResult
  2. Content-Type 标头设置为application/pdf
  3. Content-Disposition 设置为attachmentinline,并设置适当的文件名
  4. 将您的数据转换为Stream——如果您的数据是字节数组,则将其写入MemoryStream

请参阅https://stackoverflow.com/a/16673120/272072,了解如何执行此操作的一个很好的示例。

然后,您的嵌入代码只需要指向操作方法,就好像它是一个 PDF 文件一样。
这是一个例子:

public ActionResult ShowPdf() {
    // Note: the view should contain a tag like <embed src='MyController/GetPdf'>
    return View(); 
}

public ActionResult GetPdf() {
    byte[] pdfBytes = dataRepo.GetPdf(...);
    return new PdfResult(pdfBytes, "Filename.pdf", false) ;
} 

【讨论】:

  • 我想这就是我要找的东西,但是如何将此 pdf 传递给嵌入代码?我只需将方法的路径和名称键入为“/controller/method”并将其放在嵌入代码的 src“”标签中?
  • 没错。要将 PDF 嵌入页面,您需要 2 个Action 方法。第一个将返回一个普通的View,其中包含&lt;embed&gt; 代码,src 标记将指向第二个GetPdf 操作,就好像它是一个实际的PDF 文件一样。
  • 我没有该方法的任何依赖项,我的编译器甚至不理解语法。我正在使用 asp.net mvc3,这可能是个问题吗?我应该如何构建自己的 getPDF 方法;需要什么?是否需要返回 HttpPostedFileBase 类型的对象?
  • 错误 3 找不到类型或命名空间名称“ContentDisposition”(您是否缺少 using 指令或程序集引用?) C:\Users\Aaron Patten\Documents\Visual Studio 2010\Projects \MyApp\MyApp\Controllers\MyController.cs 17 16 我的应用程序
  • PdfResult 类使用ContentDisposition 类,它需要引用System.Net.Mime。抱歉,为简洁起见,代码中缺少该部分。我放了整个PdfResult.cs file here,大家看看吧。
【解决方案2】:

这里是标题为 Download and Upload Images from SQL Server via ASP.NET MVC 的 CodeProject 文章和代码示例的链接。这提供了一个通过 MVC 将内容流式传输到 SQL Server 和从 SQL Server 流式传输的有效方法的示例。

您可以轻松地调整代码以流式传输您的 PDF 文件下载。

更新

文章使用了DataReader,但是可以很方便的适配到Linq2Sql或者EF。例如,这里是 Read 方法,我从数据库中读取并复制到流中:

public override int Read(byte[] buffer, int offset, int count)
{
    result = _attachments.ExecuteStoreQuery<byte[]>(
             "SELECT SUBSTRING(AttachmentBytes, " + position.ToString() +
             ", " + count.ToString() + ") FROM Attachments WHERE Id = {0}",
             id).First();

    var bytesRead = result.Length;
    Buffer.BlockCopy(result, 0, buffer, 0, bytesRead);

    position += bytesRead;
    return (int)bytesRead;
}

【讨论】:

  • 我正在使用 linq to sql 和 explenation 对我来说真的没有意义。我也无法让示例项目运行。有什么建议吗?
  • 我更新了我的答案,以展示我如何调整它以使用 EF。您可以使用 Linq2Sql 执行类似的操作,以便将数据库中的块读入流中。
  • 问题的真正症结在于没有将它放在服务器上的任何位置,就可以将其带到视图页面。我也会看看这个项目是如何做到这一点的,但目前 Scott 的解决方案相对简单且有效。
【解决方案3】:

您可以将 PDF 作为字节流从数据库中读取并将其保存到 http 响应流中。如果您已将内容类型正确设置为 application/pdf,则浏览器将加载 PDF 插件中的文档。

更新 (14/Oct/2011):您需要将字节流写入 Response.OutputStream 对象。如何创建和写入字节流取决于您在数据库中的存储方式以及检索方式。以下代码 sn-p 来自我们网站上的一篇文章 - Generate PDF Forms In ASP.NET Using PDFOne .NET v3

// 准备好页面的输出流 响应。清除(); Response.BufferOutput = true; // 让浏览器显示表单文档 // 使用 PDF 插件。 (如果没有可用的插件, // 浏览器将显示文件 -> 另存为对话框。 Response.ContentType = "应用程序/pdf"; // 将表单文档写入浏览器 doc.Save(Response.OutputStream); doc.Close(); doc.Dispose();

doc 对象来自我们的组件。你不需要使用它。这段代码 sn -p 仅供您理解。对于您的要求,我猜您可能需要像 bytestream.save(Response.OutputStream) 这样的东西。顺便说一句,此代码适用于普通 ASP.NET,而不是 MVC。

免责声明:我为 Gnostice 工作。

【讨论】:

  • 您能否指导我找到一个资源,该资源将解释如何执行所有这三个步骤?
  • 如何将其保存到 http 响应中?一旦它在 http 响应中,如何在视图中显示它?如何以字节流格式从数据库中获取?
  • 在普通的ASP.NET中,将内容类型设置为application/pdf后,将字节流写入Response.OutputStream。响应代码可以在单独的页面或 IFRAME 中工作。 PDF 通常存储为数据库中的 blob 对象。您需要先检索该 blob 并从中创建一个字节流。它还取决于您如何将 PDF 存储在数据库中。如果已经编写了代码存储它,那么您将很容易知道如何提取它。
【解决方案4】:

如果您想 100% 动态创建 PDF,您可以在内存中完全生成它,然后将其直接流式传输到请求的 Web 浏览器,而不将其保存为文件。使用正确的工具很容易做到这一点。我会推荐 Persits.com 的 AspPDF 作为一种非常容易做到这一点的方法。看看他们的在线文档,看看这是多么简单,无需在您的服务器上创建一堆渲染的 PDF 文件。

如果您无法执行此类操作,则只需合并一个进程,根据它们的年龄从您的服务器文件系统中清除“过期”的 PDF 文件。例如,在您创建本地 PDF 文件后,您只需查看包含临时 PDF 的文件夹并删除您找到的任何超过一定期限的文件。您无法可靠地判断用户是否或何时离开您的页面或站点。

【讨论】:

  • 我没有生成 pdf。我正在从用户上传它。它作为文件上传,我希望 eto 知道如何在视图中显示它而不必将其保存到文件系统中,以便我可以将其保存在数据库中并检索它以便稍后显示而无需占用服务器空间或担心必须清理旧文件。
  • @AaronPatten,如果它首先作为文件上传,为什么不将文件存储到可通过 URL 访问的某个位置,并将文件名存储在数据库中。这样的可扩展性要大得多,而且与数据库空间相比,Web 服务器空间通常要便宜得多。
  • PDF 必须保密,未经注册的人无法访问。
【解决方案5】:

对于问题的第一部分,如 cmets 中所述,使用某种类型的流对象来传递 PDF 数据。现在,您正在将文件流式传输到本地文件系统,然后再次将其流式传输到嵌入式标签以进行显示。只需取消保存到文件系统的中间步骤,并在内存中完成整个操作(尽管这并不是真正的效率模型,并且可能无法很好地扩展)。

关于您问题的第二部分,这并不简单。 MVC 确实没有状态的概念(视图状态等),因此它没有可以从状态更改(例如,导航离开页面)中触发的事件。

您可以使用 Javascript 来检测离开您的页面 (windows.onunload) 的用户,这会调用 (C#/VB) 方法从文件系统中删除文件。您可能必须使用 AJAX 与服务器进行通信,使用 HTTP POST 方法,并在该 URL 端点监听某些东西以触发删除文件的方法。

【讨论】:

  • 对于您回复的第一部分:这正是我想知道的。你知道我可以阅读哪些好的资源来帮助我学习如何做到这一点吗?
  • 与其等待 Javascript 调用来发出文件删除的信号,顺便说一句,这确实不可靠,最好只根据某个时间戳删除文件,比如一天后,或者可能2小时大?当然,这个选项需要一些计划任务来检查文件。
  • @Amry 同意 Javascript 解决方案可能不可靠,尽管如前所述,它确实满足了他的要求。计划任务会更可靠,但如果你要走这条路,你不妨使用 PowerShell 或 DOS/VB/CMD 类型的脚本,并使用任务计划程序安排它运行(我发现,有时也不是那么可靠)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-10
相关资源
最近更新 更多