Asp .Net FileUpload to save image to the DataBase
I have worked in GridView for displaying different kind of data. The interesting portion is when there is a possibility to attach image, photo. This is not a very big task. But if it is done properly, the result will be very useful to the end user.
For this article I would like to extend bit further to add some image viewing capability to the GridView using HttpHandler. The following is the intention of this article.
1) ASP.Net FileUpload to upload the image to the web server
2) Read it as a byte array and don’t save it to the file system
3) Update the byte array to save it to the database
4) Load the grid with image control and reference the image path to a HttpHandler
5) Develop the HttpHandler to read the data into a byte array
6) In HttpHandler render the data as image and set the content type as image
Asp.Net File Upload to upload file
The uploaded data can be easily accessed using the object PostedFile, if you want to save use the PostedFile.SaveAs () method to save to a file system. But our intention is to save it to a DB so we just access the byte array into a variable and push it to database later.
As explained earlier the File Upload is going to be in the GridView. And the selected file has to be uploaded to the web server using a PostBack. So we use a submit button along with the FileUpload in the ItemTemplate. (For further information regarding wiring command to the buttons in the ItemTemplate, read here Asp .net GridView with templates)
Fetch data from File Upload Control into a byte array
In the RowCommand event of the GridView after the CommandName is verified, the Command argument can be used to fetch the current row (based on the assumption that the command argument is bound with the Container.DataItemIndex in the markup).
Once the row is available use the FindControl to get the FileUpload, PostedFile object has an InputStream, with that the byte array can be populated with the uploaded file.
Update the Database with byte array
We are using Northwind Database for the sample, this time we have taken the employees table. Basically the update query will be
Update Employees set Photo=@Photo where EmployeeId=@EmployeeId
So we need two SqlParameters to pass the Employee id and the byte array. Byte array we have just seen how to fetch it and the employee id can be taken from the Datakeys. Remember to assign DataKeyNames in the markup to GridView as EmployeeId (for this sample).
HttpHandler to show the image in GridView
Fetch the data for the respective employee
The data for the photo in the table can not be viewed without converting it to image. To make the development simpler and easier to manage, we don’t save the image uploaded by Asp .Net FileUpload to the file location or to disk. I have experienced lot of troubles if we are saving the data to the disk. So now I am going to stream the content to the client with response. HttpHandler is the best to handle this.
HttpHandler will retrieve the data from the database into a byte array. To get the respective row from employees table we need the EmployeeId. This employee id can be passed as a parameter to the Handler as we do for URLs.
Render the image
After the data has been fetched from the table, then content can be rendered into the response stream using context.Response.OutputStream.Write().We need to set the Content Type as image before rendering. There are few content types available for images(Note: we can detect the content type of the uploaded image using Asp .Net FileUpload ). I have chosen bitmaps for this sample. It is a good practice to save the content type, file name of the uploaded file(using Asp .Net FileUpload ) along with file data in the database. So that later when we streaming we can stream them with proper content type.
Source Code
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 id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView runat="server" AutoGenerateColumns="false"
AllowSorting="true" ID="GridView1"
ShowFooter="true" DataKeyNames="EmployeeId">
<Columns>
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:TemplateField>
<ItemTemplate>
<asp:Image runat="server"
ImageUrl='<%# "DbImageHandler.ashx?EmployeeId=" & eval("EmployeeId") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:FileUpload runat="server" ID="FileUpload1" />
<asp:Button runat="server" ID="btnSubmit" Text="Submit"
CommandName="UPLOAD" CommandArgument="<%# Container.DataItemIndex %>" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</form>
</body>
</html>
Code-Behind
Imports System.Data.SqlClient
Imports System.Data
Imports System.IO
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
If (Not IsPostBack) Then
LoadGrid()
End If
End Sub
Private ReadOnly Property ConnectionString() As String
Get
Return "Server=.\SQLEXPRESS;Database=NorthWind;Trusted_Connection=True"
End Get
End Property
Private ReadOnly Property Connection() As SqlConnection
Get
Dim ConnectionToFetch As New SqlConnection(ConnectionString)
ConnectionToFetch.Open()
Return ConnectionToFetch
End Get
End Property
Public Function GetData() As DataSet
Dim SelectQry = " Select * from Employees "
Dim SampleSource As New DataSet
Try
Dim SampleDataAdapter As New SqlDataAdapter(SelectQry, ConnectionString)
SampleDataAdapter.Fill(SampleSource)
Catch ex As Exception
Throw ex
End Try
Return SampleSource
End Function
Protected Sub LoadGrid()
GridView1.DataSource = GetData().Tables(0)
GridView1.DataBind()
End Sub
Protected Sub GridView1_RowCommand(ByVal sender As Object, _
ByVal e As GridViewCommandEventArgs) _
Handles GridView1.RowCommand
If (e.CommandName = "UPLOAD") Then
UpdateEmployee(Convert.ToInt32(e.CommandArgument))
End If
End Sub
Protected Sub GridView1_RowDataBound(ByVal sender As Object, _
ByVal e As GridViewRowEventArgs) _
Handles GridView1.RowDataBound
If (e.Row.RowState = DataControlRowState.Edit) Then
End If
End Sub
Private Sub UpdateEmployee(ByVal RowID As Integer)
Dim UpdateQuery = " Update Employees " & _
" set Photo=@Photo " & _
" where EmployeeId=@EmployeeId "
Dim CurrentRow = GridView1.Rows(RowID)
Dim Uploader As FileUpload = CurrentRow.FindControl("FileUpload1")
Dim EmployeeId = GridView1.DataKeys(RowID).Value
Dim UpdateCommand As New SqlCommand(UpdateQuery, Connection)
Dim IdParam As New SqlParameter("EmployeeId", SqlDbType.Int)
Dim PhotoParam As New SqlParameter("Photo", SqlDbType.Image)
Dim PhotoData(Uploader.PostedFile.InputStream.Length) As Byte
Uploader.PostedFile.InputStream.Read(PhotoData, 0, PhotoData.Length)
IdParam.Value = EmployeeId
PhotoParam.Value = PhotoData
UpdateCommand.Parameters.Add(IdParam)
UpdateCommand.Parameters.Add(PhotoParam)
UpdateCommand.ExecuteNonQuery()
End Sub
End Class
HttpHandler
<%@ WebHandler Language="VB" Class="DbImageHandler" %>
Imports System
Imports System.Web
Imports System.Data.SqlClient
Imports System.Data
Public Class DbImageHandler : Implements IHttpHandler
Private ReadOnly Property ConnectionString() As String
Get
Return "Server=.\SQLEXPRESS;Database=NorthWind;Trusted_Connection=True"
End Get
End Property
Private ReadOnly Property Connection() As SqlConnection
Get
Dim ConnectionToFetch As New SqlConnection(ConnectionString)
ConnectionToFetch.Open()
Return ConnectionToFetch
End Get
End Property
Public Function GetData(ByVal EmployeeId As String) As DataSet
Dim SelectQry = " Select * from Employees where " & _
" EmployeeId =" & EmployeeId
Dim SampleSource As New DataSet
Try
Dim SampleDataAdapter As New SqlDataAdapter(SelectQry, ConnectionString)
SampleDataAdapter.Fill(SampleSource)
Catch ex As Exception
Throw ex
End Try
Return SampleSource
End Function
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.Clear()
context.Response.ContentType = "image/bmp"
Dim ImageBuffer As Byte()
Dim EmployeeId As String = context.Request.Params("EmployeeId")
ImageBuffer = GetData(EmployeeId).Tables(0).Rows(0)("Photo")
context.Response.OutputStream.Write(ImageBuffer, 0, ImageBuffer.Length)
context.Response.End()
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class