locked
WCF return PDF file from database RRS feed

  • Question

  • I have done some basic WCF programming  prior to my current problem.  I have a windows application that calls a WCF service which returns a class with properties as string array's.  I have everything working over a WSHttpBinding...all except for one portion of the application where I need to pull a PDF file from a SQL Server database.

    The file is saved in the database as a varbinary data type.  I call the service and populate a data grid view with the file information along with some metadata about that file.  For now I have the file saving in the same directory of the application.  It creates the PDF file with the correct name, extension, etc. but the file size is only 1 KB.  I have tried other files in case I have some corrupt files but no matter what I do I always end up with a 1 KB file.  Below I have included my code I have on the client application that gets the file from the data grid view and writes it to my hard drive.

    Dim oFileStream As System.IO.FileStream
                Dim bytedata As Byte()
                Dim encoding As New System.Text.UTF8Encoding
                bytedata = encoding.GetBytes(dgvAttachment.SelectedCells.Item(5).ToString)
                oFileStream = New System.IO.FileStream(dgvAttachment.SelectedCells(2).Value.ToString, IO.FileMode.Create, IO.FileAccess.Write)
                oFileStream.Write(bytedata, 0, bytedata.Length)
                oFileStream.Flush()
                oFileStream.Close()

    Is there something obviously wrong with the code?  I have looked at the possibility of creating MTOM endpoint to retrieve the file from the database but I'm not sure if that's necessary...at least from what I have read about MTOM.  All of the PDF files are under 1 MB that are stored in the database.

    If you need more information to diagnose the problem I can share more code.  Thanks in advance to anyone who can help out.

    Monday, February 13, 2012 3:59 AM

Answers

  • Hello... tbbook

    You not need to create an endpoint which allows you to pass stream. 

    as per your post, you are saving your file as VARBINARY. so whenever you get your data or retrive data from database(using ADO.NET and stored procedure)

    when you get your file field, store it in byte[] field or property and then just pass from service to client.

    Ex:

    [DataContract]
    public class FileDetails
    {
      
      byte[] _fileContent;
      string _fileName;
    
      [DataMember]
      public byte[] FileContent
      {
         get{ return _fileContent ; }
         set{ _fileContent = value ; }
      }
    
      [DataMember]
      public byte[] FileName
      {
         get{ return _fileName ; }
         set{ _fileName = value ; }
      }
    }

    In the above class there is one property named FileContent, use this to store file bytes which comes from database in your data access code.

    now just pass this class obj from service to client.


    Regards, Hiren Bharadwa

    • Marked as answer by tbbook Tuesday, February 14, 2012 1:00 PM
    Tuesday, February 14, 2012 5:13 AM

All replies

  • Check this line in debug mode:

    encoding.GetBytes(dgvAttachment.SelectedCells.Item(5).ToString)

    Why do you do 'ToString' on PDF content? The PDF content should be kept as binary data. Write the binary data to the fileStream.

    If this post answers your quenstion, please mark it as such. If this post is helpful, click 'Vote as helpful'.

    Monday, February 13, 2012 7:09 AM
  • Since it's a file you should return a Stream, for example check out these links:

    Enabling Streaming (Example):

    http://msdn.microsoft.com/en-us/library/ms789010.aspx

    More info:

    http://msdn.microsoft.com/en-us/library/ms733742.aspx

    To retrieve VARBINARY data from SQL (Example):

    http://randypaulo.wordpress.com/2011/06/21/storing-files-to-database-and-downloading-using-asp-net/


    Randy Aldrich Paulo

    MCTS(BizTalk 2010/2006,WCF NET4.0), MCPD | My Blog


    BizTalk Message Archiving - SQL and File
    Automating/Silent Installation of BizTalk Deployment Framework using Powershell >
    Sending IDOCs using SSIS



    • Edited by Randy Paulo Monday, February 13, 2012 11:59 AM
    Monday, February 13, 2012 11:57 AM
  • Hello,

    When you fetch data from database at that in which format you get your file content? Is it of byte[] (bytes array)?

    If your answer is yes then you dont need to get bytes by using System.Text.Encoding.GetBytes method

    just using FileStream method create file and do further process using 

    GetBytes() method of System.Text.Encoding will gives you an array of byte (byte[])


    Regards, Hiren Bharadwa

    Monday, February 13, 2012 12:13 PM
  • Peter,

    Thank you for the reply.  The data gets returned from the service in a string array.  The array is parsed into additional strings.  I was thinking I should have another endpoint that returns the file alone in binary.  If possible?

    Tuesday, February 14, 2012 12:06 AM
  • Hiren,

    The data comes out of the database as a string[].  I'm thinking I should create a endpoint that has streaming enabled.  I was looking at the link that Randy supplied in the above post.  Where I have a method return the byte[] data type through the endpoint.  This looks like it would be the quickest method although I will have to modify the service and the IIS host for this method to work.  Unless you know of a way to salvage my current code.

    Tuesday, February 14, 2012 12:35 AM
  • Hello... tbbook

    You not need to create an endpoint which allows you to pass stream. 

    as per your post, you are saving your file as VARBINARY. so whenever you get your data or retrive data from database(using ADO.NET and stored procedure)

    when you get your file field, store it in byte[] field or property and then just pass from service to client.

    Ex:

    [DataContract]
    public class FileDetails
    {
      
      byte[] _fileContent;
      string _fileName;
    
      [DataMember]
      public byte[] FileContent
      {
         get{ return _fileContent ; }
         set{ _fileContent = value ; }
      }
    
      [DataMember]
      public byte[] FileName
      {
         get{ return _fileName ; }
         set{ _fileName = value ; }
      }
    }

    In the above class there is one property named FileContent, use this to store file bytes which comes from database in your data access code.

    now just pass this class obj from service to client.


    Regards, Hiren Bharadwa

    • Marked as answer by tbbook Tuesday, February 14, 2012 1:00 PM
    Tuesday, February 14, 2012 5:13 AM
  • Hiren,

    I started down that path last night.  I have yet to finish the modifications but it looks like it will work.  Thank you for all your help.

    Tim

    Tuesday, February 14, 2012 1:00 PM