Why a generic handler?

Dec 7, 2010 at 2:59 PM

I'd like to start by thanking you for putting this together.  You clearly illustrated how we can connect the dots between a UIElement to a BMP to a PNG to a PDF.  That bridged a gap for us! 

I was wondering why you might recommend passing byte content in and out of a generic handler versus leveraging a web service call that takes a byte array as input and output.  I was thinking the use of a generic handler comes off as a more obscure approach to attaining a poor man's web service call.  It may simply be a matter of style but I was curious about your reasoning for leaning that way.

Dec 8, 2010 at 5:15 PM

I was able to break the code from the handler out into its own class so that it could easily be leveraged from either a WCF Service, RIA Domain Service, or from a Generic HTTP Handler.  I realize that it could be inefficient in some circumstances relating to moving the data back and forth between a byte array and a memory stream/http response stream.

Namespace Converters
    Public Class PngToPdfConverter
        Private _BufferSize As Integer = 32768
        Private _Margin As Integer = 54

        Public Function ConvertPngToPdf(ByVal pngContents As Byte()) As Byte()
            Dim pdfBytes As Byte()

            Using outStream As New IO.MemoryStream()
                If pngContents.Length > 0 Then
                    Dim img As System.Drawing.Image

                    Using incomingStream As System.IO.Stream = New IO.MemoryStream(pngContents)
                        'Get the incoming stream
                        img = System.Drawing.Image.FromStream(incomingStream)
                        'Create and image from the stream
                    End Using

                    Dim pageHeight As Integer = img.Height + (_Margin * 2)
                    Dim pageWidth As Integer = img.Width + (_Margin * 2)
                    Dim pdfImage As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(img, System.Drawing.Imaging.ImageFormat.Png)
                    Dim pdfStream As New System.IO.MemoryStream()
                    'iTextSharp.text.Font pdfFont = iTextSharp.text.Font.
                    Dim pdfDoc As New iTextSharp.text.Document(New iTextSharp.text.Rectangle(pageWidth, pageHeight))
                    'iTextSharp.text.Document pdfDoc = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4);
                    Dim pdfWriter As iTextSharp.text.pdf.PdfWriter = iTextSharp.text.pdf.PdfWriter.GetInstance(pdfDoc, pdfStream)
                    'Insure this is set otherwise when the close method is called on the iTextSharp.text.Document the memory stream
                    'we are writting to will be closed
                    pdfWriter.CloseStream = False
                    'Open PDF and add image to it
                    pdfDoc.Open()
                    pdfDoc.Add(pdfImage)
                    'Close the PDF document to commit the changes
                    pdfDoc.Close()
                    'Insure the stream is at the beginning
                    pdfStream.Seek(0, IO.SeekOrigin.Begin)
                    'Stream the exported pdf to the client this is needed since the file size could be large in size
                    Dim bytesRead As [Byte]() = New [Byte](_BufferSize - 1) {}
                    Dim toRead As Long = pdfStream.Length
                    'Var used to determine how much to read
                    While toRead > 0
                        'Insure that _BufferSize do not overrun the end of the stream
                        If _BufferSize > toRead Then
                            _BufferSize = CInt(toRead)
                            bytesRead = New [Byte](_BufferSize - 1) {}
                        End If
                        'Write pdf memory stream to bytesRead
                        pdfStream.Read(bytesRead, 0, _BufferSize)
                        'Read read bytes to outputStream
                        outStream.Write(bytesRead, 0, _BufferSize)
                        'Create new byte array to store bytes to read
                        bytesRead = New [Byte](_BufferSize - 1) {}
                        'Update value used to check for end of stream
                        toRead -= _BufferSize
                    End While
                    'Close and displose of the memory stream
                    If pdfStream IsNot Nothing Then
                        pdfStream.Close()
                        pdfStream.Dispose()
                    End If
                End If

                outStream.Seek(0, IO.SeekOrigin.Begin)
                Using reader As New IO.BinaryReader(outStream)
                    pdfBytes = reader.ReadBytes(CInt(outStream.Length))
                End Using
            End Using

            Return pdfBytes
        End Function
    End Class

End Namespace

Oct 4, 2011 at 7:20 AM

Hi Matt Poland

Could you please send me code with wcf to print the pdf in silverlight? I use this wcf code in my project, but don't know how to use it?

I wil very thankfull to you for this.

 

Thanks,

Singh. K

Oct 4, 2011 at 3:48 PM

I'm not sure how strong your knowledge of web services are.  Think of them as a way to pass/receive data to a URL and execute a hosted proccess, i.e. a web-hosted function.  Sometimes you do this because you want to take some functionality and make it a first class citizen in your enterprise.  Sometimes you do this because you need to cross a process/machine boundary, e.g. get out of the Silverlight Runtime to execute some code in the full .Net Runtime.  With Silverlight, you're constrained to a few options.

  • WCF RIA Service
    • This of this as web services made easy for Silverlight
  • Standard WCF Service (BasicHttpBinding)
    • This is Microsoft reinventing their web service platform
    • Supports a vast complex set of capabilities
    • Can get lost in the configuration
      • Some controls are solely for enabling functionality (Do you want response to include exception details on error?)
      • Some controls are solely for describing hosting environment (Does your hosting site have multiple host headers assigned?)
      • Some controls enable functionality but are constrained to a certain hosting environment (Are user credentials passed in the message?  Better have anonymous access turned on!)
  • Legacy ASMX Web Service
    • This of this as the super easy old way of doing things.
    • Supports a very limited set of capabilities
  • Custom HTTP Handler
    • This is a less structured way of being able to pass/recieve data to a URL

There is nothing special about wrapping the function I describe above in a web service.  The needed activities are the same as hosting any functionality in a web service.  I don't think this is the best place to go over how to do that as there are numerous resources available on those topics.  Hopefully the links above help to get you started.  I used a WCF RIA Service if that points you down the path I followed.