Results 1 to 7 of 7

Thread: File upload problem

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Sep 2003
    Location
    Edmonton, AB, Canada
    Posts
    2,629

    File upload problem

    I'm not sure where this should go (I don't know whether it's a database problem, or a code problem), but I think it's a code problem, so I'm posting here.

    I'm working with a database that is storing images (actually, it's a modified version of the AdventureWorks database from Microsoft), and I'm creating a form that will let you upload a file. I've got a business object based on the table that I'm using (Production.ProductPhoto) and I'm using two stored procedures to either get (Production.ProductPhoto_Get) or add (Production.ProductPhoto_Add) an entry from/to the table. The image is being stored as a varbinary field in the database, and a Byte() in my business object.

    The problem I'm having is that when I'm adding a new entry and uploading a file, the length of the file uploaded is correct (so I assume everything is going smoothly), and it gets passed along to my ProductPhotoProvider DAL class where I create a DbCommand and add the parameters for my stored procedure. The information is all added to the database successfully, and I'm returned the identity of the new entry as expected -- however, when I try to read this image back, it seems that the length is 1. I've put in break points and stepped through everything, and I don't know what's going on.

    I think that I know my ProductPhotoProvider class is at least reading things correctly -- I can display other images from the database (that came with the database, that is) just fine. Mine just all come back with a length of 1.

    I'm just hoping someone knows what the hell I'm talking about; I have a lot of programming experience, but this is my first major venture into ASP.NET. I have no idea which parts of my code are relevant, so I'll just post my Add and Lookup functions for now?!

    ProductPhotoProvider.Add:
    vb Code:
    1. Public Shared Function Add(ByVal P As ProductPhoto) As Integer
    2.             Dim Command As DbCommand = GetCommand("Production.ProductPhoto_Add")
    3.             With Command.Parameters
    4.                 .Add(GetParameter("ThumbNailPhoto", DbType.Binary, P.ThumbnailPhoto))
    5.                 .Add(GetParameter("ThumbnailPhotoFileName", DbType.String, P.ThumbnailPhotoFilename))
    6.                 .Add(GetParameter("LargePhoto", DbType.Binary, P.LargePhoto))
    7.                 .Add(GetParameter("LargePhotoFileName", DbType.String, P.LargePhotoFilename))
    8.             End With
    9.             Return ExecuteScalar(Of Integer)(Command)
    10.         End Function

    ProductPhotoProvider.Lookup:
    vb Code:
    1. Public Shared Function Lookup(ByVal ProductPhotoID As Integer) As ProductPhoto
    2.             Dim Command As DbCommand = GetCommand("Production.ProductPhoto_Get")
    3.             With Command.Parameters
    4.                 .Add(GetParameter("ProductPhotoID", DbType.Int32, ProductPhotoID))
    5.             End With
    6.             Return Hydrator.FillObject(ExecuteReader(Command))
    7.         End Function

    ProductPhotoProvider.Hydrator.FillObject:
    vb Code:
    1. Public Shared Function FillObject(ByVal reader As INullableReader) As ProductPhoto
    2.                 CheckNullOrClosedReader(reader)
    3.                 Dim Result As ProductPhoto = Nothing
    4.                 Using reader
    5.                     If reader.Read Then
    6.                         Result = Hydrate(reader)
    7.                     End If
    8.                 End Using
    9.                 Return Result
    10.             End Function

    ProductPhotoProvider.Hydrator.Hydrate:
    vb Code:
    1. Private Shared Function Hydrate(ByVal reader As INullableReader) As ProductPhoto
    2.                 Dim ID As Integer = reader.GetInt32("ProductPhotoID")
    3.  
    4.                 'images must be read in as an array of Bytes; no GetByte!
    5.                 Dim ThumbnailIndex As Integer = reader.GetOrdinal("ThumbnailPhoto")
    6.                 Dim ThumbnailPhoto As Byte() = Nothing
    7.                 If Not reader.IsDBNull("ThumbnailPhoto") Then
    8.                     ThumbnailPhoto = CType(reader.GetValue(ThumbnailIndex), Byte())
    9.                 End If
    10.  
    11.                 Dim ThumbnailPhotoFilename As String = reader.GetNullableString("ThumbnailPhotoFilename")
    12.  
    13.                 'images must be read in as an array of Bytes; no GetByte!
    14.                 Dim LargePhotoIndex As Integer = reader.GetOrdinal("LargePhoto")
    15.                 Dim LargePhoto As Byte() = Nothing
    16.                 If Not reader.IsDBNull("LargePhoto") Then
    17.                     LargePhoto = CType(reader.GetValue(LargePhotoIndex), Byte())
    18.                 End If
    19.  
    20.                 Dim LargePhotoFilename As String = reader.GetNullableString("LargePhotoFilename")
    21.                 Dim ModifiedDate As Date = reader.GetDateTime("ModifiedDate")
    22.  
    23.                 Dim Result As ProductPhoto = New ProductPhoto(ID, ThumbnailPhoto, ThumbnailPhotoFilename, _
    24.                                                               LargePhoto, LargePhotoFilename, ModifiedDate)
    25.                 Return Result
    26.             End Function

    My ProductPhotoProvider class is based off of an abstract class called AbstractDALProvider (which I can also provide if needed). I can provide the rest of my project, if needed, too.

    Oh, and for good measure: I was told that when you used to store images in Microsoft Access, there was some sort of problem when retrieving the data and you'd have to strip the first 72 bytes of data from it, or something. I can only assume that this is not a problem here, because I have no problem displaying other photos that were not created by me.

  2. #2
    PowerPoster gep13's Avatar
    Join Date
    Nov 2004
    Location
    The Granite City
    Posts
    21,963

    Re: File upload problem

    Hey,

    Is it possible that you can show the code where you are getting the Byte() information for the photo?

    As a pointer in the right direction, you might want to have a look here:

    http://www.vbforums.com/showthread.php?t=469562

    Also, how are you then showing the Image on the page? Are you using an HttpHandler to write the Response out to the page?

    As a side note, for my site, I opted to not store the image information directly in the database, but rather a pointer (i.e. the file path) to where the image was stored on the file system. I decided that it was easier to handle the image directly on the file system rather than in the database.

    Gary

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Sep 2003
    Location
    Edmonton, AB, Canada
    Posts
    2,629

    Re: File upload problem

    if this were my project, I would never store image data in the database (I'm a PHP developer and know the difficulties) -- I'm firmly against that and the unnecessary complexity of doing so. however, it isn't my choice.

    anyway, to answer your questions -- this is the code on my form that gets an uploaded file (there is an abstract class here that is used to only allow certain mime types, by the way):
    vb Code:
    1. Private Function GetUploadedPhoto(ByVal UploadedFile As FileUpload) As Byte()
    2.         Dim Photo As Byte() = Nothing
    3.         If UploadedFile.HasFile AndAlso UploadedFile.PostedFile IsNot Nothing Then
    4.             Dim Extension As String = Path.GetExtension(UploadedFile.PostedFile.FileName).ToLower
    5.             Dim MIMEType As String = "image/" + Extension.Replace(".", "")
    6.             If WebClient.UI.Handlers.AbstractStreamableImage.ImageFormats.ContainsValue(MIMEType) Then
    7.                 Dim Length As Long = UploadedFile.PostedFile.InputStream.Length
    8.                 Dim ImageBytes(Length) As Byte
    9.                 UploadedFile.PostedFile.InputStream.Read(ImageBytes, 0, Length)
    10.                 Photo = ImageBytes
    11.             Else
    12.                 Throw New Exception("Invalid file type uploaded - only picture files are allowed.")
    13.             End If
    14.         End If
    15.         Return Photo
    16.     End Function
    then, in my event handler for adding:
    vb Code:
    1. Dim aLargePhoto As Byte() = GetUploadedPhoto(LargePhotoUpload)
    2.                 Dim aThumbnailPhoto As Byte() = GetUploadedPhoto(ThumbnailPhotoUpload)
    3.  
    4.                 Dim Item As ProductPhoto = New ProductPhoto(aThumbnailPhoto, ThumbnailFilename.Text, aLargePhoto, LargePhotoFilename.Text)

    yes, I have an HTTPHandler that is reading the image. my business object has a readonly method that uses MemoryStream (like in the post you linked to) to stream the Byte() and create a new Bitmap() out of it, and returns an Image. for example:
    vb Code:
    1. Private _thumbnailPhotoImage As Image = Nothing
    2.     Public ReadOnly Property ThumbnailPhotoImage() As Image
    3.         Get
    4.             If _thumbnailPhotoImage Is Nothing Then
    5.                 If ThumbnailPhoto IsNot Nothing Then
    6.                     Dim Stream As MemoryStream = New MemoryStream(ThumbnailPhoto)
    7.                     _thumbnailPhotoImage = New Bitmap(Stream)
    8.                 End If
    9.             End If
    10.             Return _thumbnailPhotoImage
    11.         End Get
    12.     End Property
    and I do the same for the larger photo.

    this is the handler I'm using to load the images:
    vb Code:
    1. <%@ WebHandler Language="VB" Class="Handler" %>
    2.  
    3. Imports System
    4. Imports System.Drawing
    5. Imports System.Web
    6. Imports System.IO
    7. Imports WebClient.UI.Handlers
    8.  
    9. Public Class Handler : Implements IHttpHandler
    10.     Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
    11.         Try
    12.             Dim SizeParam As String = context.Request.Params("Size")
    13.             Dim IDParam As String = context.Request.Params("ID")
    14.             Dim ID As Integer
    15.             Dim Streamer As AbstractStreamableImage = Nothing
    16.             If Not String.IsNullOrEmpty(SizeParam) AndAlso Integer.TryParse(IDParam, ID) Then
    17.                 Select Case SizeParam.ToLower
    18.                     Case "large"
    19.                         Streamer = New ProductPhotoImage(ID, True) 'second parameter is a boolean of whether or not the size is large
    20.                     Case "thumbnail"
    21.                         Streamer = New ProductPhotoImage(ID, False)
    22.                 End Select
    23.             End If
    24.             If Streamer Is Nothing OrElse Streamer.StreamableImage Is Nothing Then
    25.                 Streamer = New DefaultImage("")
    26.             End If
    27.             Streamer.Write(context.Response)
    28.         Catch ex As Exception
    29.             context.Response.ContentType = "text/plain"
    30.             context.Response.Write("no image")
    31.         End Try
    32.         context.Response.Cache.SetCacheability(HttpCacheability.NoCache)
    33.     End Sub
    34.  
    35.     Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
    36.         Get
    37.             Return False
    38.         End Get
    39.     End Property
    40.  
    41. End Class

    and the ProductPhotoImage class that it's using simply looks up the data in the database, populates a business object, and returns it depending on the size used (_large is a boolean variable for either thumbnail/large photo). this class is based off of an abstract class that I can also post if needed:
    vb Code:
    1. Imports Microsoft.VisualBasic
    2. Imports System.Drawing
    3. Imports System.Drawing.Imaging
    4. Imports System.IO
    5. Imports AWSystem.Data
    6. Imports AWSystem.BLL
    7.  
    8. Namespace WebClient.UI.Handlers
    9.     Public Class ProductPhotoImage
    10.         Inherits AbstractStreamableImage
    11.  
    12.         Private _productPhotoID As Integer
    13.         Private _large As Boolean
    14.  
    15.         Public Sub New(ByVal pProductPhotoID As Integer, Optional ByVal pLarge As Boolean = True)
    16.             _productPhotoID = pProductPhotoID
    17.             _large = pLarge
    18.         End Sub
    19.  
    20.         Public Overrides ReadOnly Property StreamableImage() As Image
    21.             Get
    22.                 If _StreamableImage Is Nothing Then
    23.  
    24.                     Dim Controller As New ProductPhotoController()
    25.                     Dim Info As ProductPhoto = Controller.Lookup(_productPhotoID)
    26.                     Dim ProductPhoto As Image = Nothing
    27.  
    28.                     If Info IsNot Nothing Then
    29.                         If _large Then
    30.                             _StreamableImage = Info.LargePhotoImage
    31.                         Else
    32.                             _StreamableImage = Info.ThumbnailPhotoImage
    33.                         End If
    34.                     End If
    35.                 End If
    36.  
    37.                 Return _StreamableImage
    38.             End Get
    39.         End Property
    40.     End Class
    41. End Namespace

    however, the fact that all the other images display fine leads me to believe that my HTTPHandler and my readonly properties are working correctly.

    I'll take a look at some more of the code in the thread you posted and try a few things (though most of it looks very similar already at just a glance), and thanks for the reply!

  4. #4

    Thread Starter
    PowerPoster
    Join Date
    Sep 2003
    Location
    Edmonton, AB, Canada
    Posts
    2,629

    Re: File upload problem

    after examining the thread you posted, I'm at a loss. The only big difference is that they're using an SQLCommand and I'm using a DBCommand, and thus they are using SqlDbType.VarBinary. There is no DbType.VarBinary, though, so I'm just using DbType.Binary. but, I would think that this wouldn't matter.

    other than that, they're taking image data from the file system as an Image type and creating a MemoryStream to load it in so that Stream.GetBuffer() would have all of the binary data, correct? so if I'm having a user upload a file, I already have the binary data. I may not be using the correct method to store it, though, or something (in GetUploadedPhoto()). I'd appreciate any more help you may be able to provide!

  5. #5
    PowerPoster gep13's Avatar
    Join Date
    Nov 2004
    Location
    The Granite City
    Posts
    21,963

    Re: File upload problem

    Hey,

    It's been a long day for me, just finished a round of golf, and not really in the right mind set to have a look at all that code

    Will try and take a look at it tomorrow.

    Given that you are able to retrieve images that are already in the database, then that leads me to suspect that it has to be the import code that has the problem.

    On a side note, and to allow you to continue investigating, have a look here:

    http://www.asp.net/downloads/starter-kits/personal/

    It have a photo upload and storage section that does exactly what you are trying to implement, might be worth taking a look at that and comparing what they are doing.

    Gary

  6. #6

    Thread Starter
    PowerPoster
    Join Date
    Sep 2003
    Location
    Edmonton, AB, Canada
    Posts
    2,629

    Re: File upload problem

    hi! I got it fixed, but thanks for your help. thankfully, nothing was wrong with anything that I had done but instead it was the fault of whoever created the _Add/_Update stored procedures. the photo parameters that the procedures were taking in were VARBINARY, but a VARBINARY stores only one byte (didn't specify a length!), whereas the table stores the photos as VARBINARY(MAX). updating the stored procedures seems to have fixed everything! woohoo.

  7. #7
    PowerPoster gep13's Avatar
    Join Date
    Nov 2004
    Location
    The Granite City
    Posts
    21,963

    Re: File upload problem

    Hey,

    Glad to hear that you got it working!! I can only imagine the debugging and fault finding you had to go through to pin that one down!!

    Gary

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width