0

我使用 iTextSharp(不是说这与 iTextSharp 相关)使用类似于以下的代码生成 PDF 字节:

Function GetFileBytes() as Byte()
Dim result() As Byte
    Using ms As New MemoryStream

        Dim reader As New PdfReader(pdfForm)
        Dim writer As New PdfStamper(reader, ms)

        Dim fields As AcroFields = writer.AcroFields

        fields.SetField("Customer Name", custInfo.FirstName + " " + custInfo.LastName)

        result = ms.GetBuffer
    End Using
End Function

我想让它成为一个异步任务,而是返回 Task(Of Byte()),但是我在弄清楚如何让我的内存流以异步模式写入以及如何返回 Task(Of Byte() ) 进行中。任何提示,建议?谢谢!

编辑 1 我想澄清使用任务和使用此代码的必要性,因为到目前为止,似乎有些评论类似于“你为什么这样做”和“不只是这样做,我想礼貌地说“谢谢,但我想这样做”:)

这是我的场景,想象一个网站在几页上收集数据,然后呈现一个审查屏幕,然后让用户能够查看包含该数据的 PDF。在审阅屏幕上,我需要生成一个 1 MB 的 PDF 文件,将其上传到 BLOB 存储,并在用户选择下载时提供。

我想在用户查看审阅屏幕时而不是在他们选择“查看 PDF”按钮时生成和上传 PDF。该代码将使用我的示例完成,这就是为什么我很好奇如何创建 Byte() 类型的任务。任何帮助总是很感激,再次感谢!

4

4 回答 4

0

如果你真的想要异步,一种更简单的方法是在类中创建一个私有线程,page_init 上的线程将启动进程,然后在 Page_LoadComplete 上,线程将使用 thread.join() 等待,然后你会得到函数结果,但如前所述,相对速度增益很小,考虑线程(或任务)确实很昂贵

选项 2
向返回 pdf 文件数据的通用处理程序创建 ajax 请求,这样不涉及线程并提供更好的用户体验

<%@ WebHandler Language="VB" Class="GetFile" %>

Imports System
Imports System.Web
Imports System.IO

Public Class GetFile : Implements IHttpHandler


    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest        
        context.Response.Clear()        
            If File.Exists(filePath & docName) Then
                context.Response.AddHeader("content-disposition", "attachment; filename=" & HttpContext.Current.Server.UrlEncode(docName))
                context.Response.ContentType = "text/pdf"
                context.Response.WriteFile(filelocation & docName) 'in your case this writes the bites of the generated file, so instead of the path just pass in the data
            End If 
        context.Response.Flush()
        context.Response.End()
    End Sub

    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

End Class
于 2013-10-04T16:44:32.407 回答
0

这是我的场景,想象一个网站在几页上收集数据,然后呈现一个审查屏幕,然后让用户能够查看包含该数据的 PDF。在审阅屏幕上,我需要生成一个 1 MB 的 PDF 文件,将其上传到 BLOB 存储,并在用户选择下载时提供。

由于您提到“blob 存储”,我假设您使用的是 Azure。

您需要一个辅助角色或服务来可靠地执行此操作。辅助角色应该只是从 Azure 队列中读取并生成 PDF。

因此,当您的 Web 角色生成审查屏幕时,在返回响应之前,它还会将该数据放入 Azure 队列中。当您的 Web 角色被通知用户接受评论时,它应该(异步)等到 PDF 文件生成。

于 2013-10-08T20:55:31.723 回答
0

回应您的编辑:这种情况是有道理的。将所有内容打包在一个Task.Run电话中。确保是线程安全的(例如,不要在任务中使用 HttpContext)。还要记录错误,因为它们可能是错误。

但是请注意,使用 ASP.NET 后台工作可以随时中止(例如,当工作进程回收时)。你必须忍受突然消失的背景工作。在您的情况下,当用户尝试访问 PDF 时,它可能会丢失。此外,如果用户尝试下载它时仍在生成它怎么办。必须解决这些问题。

于 2013-10-04T16:34:08.637 回答
-1

(不要在下面使用此代码..请参阅“答案”的结尾以进行推理)..

感谢大家的帮助。最后我接近这个错误。我只需要创建一个异步包装函数来返回我的 Task(Of Byte())

所以如果我的初始代码是这样的:

Function GetFileBytes() as Byte()
    Dim result() As Byte

      Using ms As New MemoryStream

        Dim reader As New PdfReader(pdfForm)
        Dim writer As New PdfStamper(reader, ms)

        Dim fields As AcroFields = writer.AcroFields

        fields.SetField("Customer Name", custInfo.FirstName + " " + custInfo.LastName)

        result = ms.GetBuffer
    End Using
End Function

现在,我创建了一个名为 GetFileBytesAsync 的新方法来返回 Task(Of Byte()) 调用上述相同的 GetFileBytes 方法,它只是使用 Task.Factory.StartNew 调用,如下所示:

Public Shared Async Function GetFileBytesAsync() As Task(Of Byte())
        Dim t As Task(Of Byte()) = Task.Factory.StartNew(Function()
                                                             Return GetFileBytes()
                                                         End Function)

        Return Await t

    End Function

在我的调用函数中,我现在只使用任务对象的 Result 属性来访问字节数组。!

编辑:好的,正如斯蒂芬克利里恰当地指出的那样,我做错了,不推荐使用上面的代码,它没有异步做任何事情..事实上它创建新线程来创建一些阻塞代码. 对不起...

我遇到了这个 TechEd 演讲:http ://channel9.msdn.com/Events/TechEd/NorthAmerica/2013/DEV-B337 - 它是如何使用异步构建 ASP.NET Web 应用程序。在 54 分钟标记处,它实际上表明尝试在 ASP.NET Web 服务器上使用“后台线程”是错误的,因为在 IIS 中没有使用后台线程,本质上您占用的线程可能\应该用于响应网络请求。

于 2013-10-08T20:20:01.140 回答