Web Code Blog

A web repository of coding tips and knowledge base articles

Archive for August, 2010

Save and retrieve images / documents into SQL Server using ASP.NET

Posted by Stefan Zvonar on August 22, 2010

In this article I will explain how to save and retrieve VARBINARY(MAX) data into SQL Server using ASP.NET.  You may opt to do this to store images or documents into the database.

So, let us start at the database level.  Below is a simplistic table definition for storing our files into a table:

CREATE TABLE [dbo].[tb_File](
    [FileID] [int] IDENTITY(1,1) NOT NULL,
    [FileName] [varchar](255) NOT NULL,
    [FileData] [varbinary](max) NOT NULL,
    [FileContentType] [varchar](255) NOT NULL,
 CONSTRAINT [PK_TB_FILE] PRIMARY KEY CLUSTERED
(
    [FileID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

And here are two simple stored procedures to save and retrieve the file data:

CREATE PROCEDURE dbo.usp_File_Get
(
     @FileID int
)

AS

BEGIN

    SET NOCOUNT ON

    SELECT FileID
      ,[FileName]
      ,FileData
      ,FileContentType
    FROM tb_File
    WHERE FileID = @FileID
   SET NOCOUNT OFF

END
GO

And

CREATE PROCEDURE dbo.usp_File_Insert
( 
     @FileName varchar(255),
     @FileData varbinary(max),
     @FileContentType varchar(255)
)

AS

BEGIN

    SET NOCOUNT ON
  
    INSERT INTO tb_File ([FileName], FileData, FileContentType)
    VALUES (@FileName, @FileData, @FileContentType) 
    SET NOCOUNT OFF

END
GO

Now that we have the database objects in place, lets create a basic maintenance web page to be able to upload a file and save it to the database:

Markup:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Upload file to database</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                File Name:
            </div>
            <div>
                <asp:TextBox runat="server" ID="txtFileName"></asp:TextBox>
            </div>
            <br />
            <div>
                File:
            </div>
            <div>
                <asp:fileupload runat="server" id="uplFile" />
            </div>
            <br />
            <div>
                <asp:button ID="btnSave" runat="server" text="Save" OnClick="btnSave_Click" />
            </div>
        </form>
    </body>
</html>

Code-Behind:

 Partial Class _Default
    Inherits System.Web.UI.Page

    Private m_strFileName, m_strFileContentType As String
    Private m_intFileLen As Integer
    Private m_byteFileData As Byte()

    Protected Sub btnSave_Click(ByVal sender As Object, ByVal e As EventArgs)

        GetFileData()
        SaveData()

    End Sub

    Private Sub GetFileData()

        Dim myFile As HttpPostedFile = uplFile.PostedFile
        m_strFileName = System.IO.Path.GetFileName(uplFile.FileName)
        m_strFileContentType = myFile.ContentType
        m_intFileLen = myFile.ContentLength
        m_byteFileData = Nothing

        ' make sure the size of the file is > 0
        If m_intFileLen > 0 Then
            ' Allocate a buffer for reading of the file
            m_byteFileData = New Byte(m_intFileLen - 1) {}

            ' Read uploaded file from the Stream
            myFile.InputStream.Read(m_byteFileData, 0, m_intFileLen)

        End If

    End Sub

    Private Sub SaveData()

        Dim conSQL = New SqlClient.SqlConnection
        conSQL.ConnectionString = "Your database connection string"
        conSQL.Open()

        Dim comSQL As New SqlClient.SqlCommand()

        With comSQL

            .CommandText = "dbo.usp_File_Insert"
            .Connection = conSQL
            .CommandType = CommandType.StoredProcedure
            .Parameters.AddWithValue("@FileName", m_strFileName)

            .Parameters.Add("@DocData", SqlDbType.VarBinary, -1)   ' Need to set size to -1 since it is varbinary(max)
            If m_byteFileData Is Nothing Then
                .Parameters("@DocData").Value = System.DBNull.Value
            Else
                .Parameters("@DocData").Value = m_byteFileData
            End If

            .Parameters.AddWithValue("@DocContentType", m_strFileContentType)
            .ExecuteNonQuery()
        End With

        conSQL.Close()
        conSQL.Dispose()

    End Sub

End Class

Now lets look at how we can view the stored binary data through ASP.NET. Below we have a simple handler that is passed a File ID as a Querystring. It will look up the ID in the database and then write the object out as a byte stream.

<%@ WebHandler Language="VB" Class="FileHandler" %>
Imports System
Imports System.Web
Imports System.Web.Services

Public Class FileHandler
    Implements System.Web.IHttpHandler

    Private m_strFileContentType As String = String.Empty
    Private m_objFileData As Object
    Private m_intFileID As Integer

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


    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

        GetData(context)
        ShowFile(context)

    End Sub

    Private Sub GetData(ByVal context As HttpContext)

        If context.Request.QueryString("ID") IsNot Nothing AndAlso context.Request.QueryString("ID").Trim() <> String.Empty AndAlso IsNumeric(context.Request.QueryString("ID").Trim()) Then
            m_intFileID = CInt(context.Request.QueryString("ID").Trim())

            Dim conSQL = New SqlClient.SqlConnection
            conSQL.ConnectionString = "Your database connection string"
            conSQL.Open()

            Dim comSQL As New SqlCommand("dbo.usp_File_Get")
            comSQL.Connection = conSQL
            comSQL.Parameters.AddWithValue("@FileID", m_intFileID)
            comSQL.CommandType = CommandType.StoredProcedure

            'read record from database
            Dim drdDrillInstructions As SqlDataReader
            drdDrillInstructions = comSQL.ExecuteReader()
            Try
                If (drdDrillInstructions.HasRows) Then
                    While drdDrillInstructions.Read()
                        m_strFileContentType = drdDrillInstructions.Item("FileContentType").ToString()
                        m_objFileData = drdDrillInstructions.Item("FileData")
                    End While
                End If
            Catch ex As Exception
                ' Publish error here
            Finally
                If Not drdDrillInstructions.IsClosed Then
                    drdDrillInstructions.Close()
                End If
                conSQL.Close()
                conSQL.Dispose()
            End Try
        End If

    End Sub

    Private Sub ShowFile(ByVal context As HttpContext)

        ' Clear out the existing HTTP header information
        context.Response.Expires = 0
        context.Response.Buffer = True
        context.Response.Clear()

        If m_objFileData IsNot Nothing AndAlso (Not DBNull.Value.Equals(m_objFileData)) Then
            context.Response.ContentType = m_strFileContentType
            context.Response.BinaryWrite(DirectCast(m_objFileData, Byte()))
        Else
            context.Response.Write("<html><body bgcolor='#D6EBFF'><p align='center'><br /><br /><br /><br /><br />")
            context.Response.Write("<font class='text'>(No file available)</font>")
            context.Response.Write("</p></body></html>")
        End If

    End Sub

End Class

Hope this helps,

Stefan.

For more Web Code, ASP.NET, SQL Server and other development tips, please check back here at webcodeblog.com often.

Posted in .NET, ASP.NET, SQL Server | 3 Comments »

 
Follow

Get every new post delivered to your Inbox.