Sunday, March 15, 2009

Saving Images in a SQL database using ASP.Net

The ability to display images in a web application is a common requirement. There are two ways you can do this, either store images in a SQL database using the Binary Large Object (commonly know as BLOB) data type, or store the image on the disk. There are pro’s and cons to each of these methods, but in this article we’re going to learn how to store images into a SQL database.
For the purpose of this article I have created a table in SQL Server called Images, with three columns, Image Name, Image Type and the Image itself. Now let’s take a look at the form we are going to use, to upload images to this table.
Note: that the form enctype is multipart/form-data. This is necessary when we upload client files to a server.
So far, this looks pretty straightforward. Let’s take a look at the code which will process this request. To start with we see that File1 is derived from theHtmlInputfileclass

protected System.Web.UI.HtmlControls.HtmlInputFile File1;
This allows programmatic access to the HTML element on the server. We are going to use the PostedFile class to get the properties of the client image file. In the following piece of code we use the ContentLength and ContentType methods of this class to get the length, and type of the image file.

HttpPostedFile selectedFile = File1.PostedFile;
int imageLength = selectedFile.ContentLength;
string imageType = selectedFile.ContentType
If we were going to save this file to the server, all we need to do, is use the SaveAs method. In this case we are going to store the image in a SQL database, so we need to convert it into a format that SQL can understand. We are going to create a byte array. The size of the array is the length of the image that we were able to retrieve using the Contentlength property of the HttpPostedFile class.

binaryImagedata = new byte[imageLength];
The HttpPostedFile class also has an InputStream method, which returns the image data in bytes. We are going to use this to populate our byte array

selectedFile.InputStream.Read(binaryImagedata,0,imageLength);

We now have all the fields needed (imageLength, File1.PostedFile.FileName and binaryImagedata) to populate the database.
This covers the basics of how to upload an image to a database. In a real application, there are other things we might want to do, for example some validation checks. By checking the value of selectedFile.ContentLength you can enforce size restrictions on the image file. A ContentLength of 0, indicates that the file either does not exist or an empty file is being uploaded. The following code would check for empty files :

if (selectedFile.ContentLength==0)
{
errs ="0 length file ";
}
Note: The default file size that can be uploaded is 4MB, and a larger size will cause .Net to throw an exception. To change the default size for all applications on the server, the machine.config file will need to be modified. In the httpRuntime section, there is a maxRequestLength attribute,. Change the length to whatever new default you need.
If you want to make the change for only a single application however, then this setting can be overridden in the web.config file of the application in question. You would need to create a section and add the maxRequestLength attribute with the size you require. For further information on this topic, see the documentation for the
HttpRuntime element
We can also check the value of selectedFile.ContentType and verify if the file type is one we allow to be uploaded. The ContentType returns the MIME encoding in string format of the request. This is typically in category / subcategory format. Some common types include
"text/HTML" or "image/GIF". To ensure that the user can only upload GIF files, add the following code

if (selectedFile.ContentType.ToLower() != @"image/gif")
{
errs +="Invalid filetype";
}
In some cases we might also need to check for the dimensions of the image. Often, an application has a pre-determined space to display the image, and you might want to ensure that the height and width of the image match the allotted space. The HttpPostedFile class is not limited to just image files, so does not provide for any methods to retrieve this information. To retrieve further information about images, we are going to use the image class in the System.Drawingnamespace. For the purpose of this article we are only interested in the length and width of the image, however there is a lot more that you can do with this class, refer to System.Drawing.Image . To start with we create an Image object

System.Drawing.Image drawingImage = null;
The next step is to read the byte array binaryImagedata into our Image object.

drawingImage = System.Drawing.Image.FromStream(new System.IO.MemoryStream(binaryImagedata));
Now we have access to both the height and width of the array, so if your application requires your images have a length and width of 300 px you would use the following code
If ((drawingImage.Width != 300) && (drawingImage.Height != 300)) {
Errs = “Image is the wrong size”;
}

Hopefully this article covers all the basic elements of uploading images to a SQL database. To retrieve images to display in a web form - Displaying SQL Images in an ASP.Net datagrid,
The ability to display images in a web application is a common requirement. There are two ways you can do this, either store images in a SQL database using the Binary Large Object (commonly know as BLOB) data type, or store the image on the disk. There are pro’s and cons to each of these methods, but in this article we’re going to learn how to store images into a SQL database.
For the purpose of this article I have created a table in SQL Server called Images, with three columns, Image Name, Image Type and the Image itself. Now let’s take a look at the form we are going to use, to upload images to this table.

Saving Images in a SQL database using ASP.Net

The ability to display images in a web application is a common requirement. There are two ways you can do this, either store images in a SQL database using the Binary Large Object (commonly know as BLOB) data type, or store the image on the disk. There are pro’s and cons to each of these methods, but in this article we’re going to learn how to store images into a SQL database.
For the purpose of this article I have created a table in SQL Server called Images, with three columns, Image Name, Image Type and the Image itself. Now let’s take a look at the form we are going to use, to upload images to this table.

Saving Images in a SQL database using ASP.Net

The ability to display images in a web application is a common requirement. There are two ways you can do this, either store images in a SQL database using the Binary Large Object (commonly know as BLOB) data type, or store the image on the disk. There are pro’s and cons to each of these methods, but in this article we’re going to learn how to store images into a SQL database.
For the purpose of this article I have created a table in SQL Server called Images, with three columns, Image Name, Image Type and the Image itself. Now let’s take a look at the form we are going to use, to upload images to this table.

FileUpload in asp.net using C#

Uploading image to a database using datatype image

Intro
Uploading images to a Sql Server database is extremely easy using ASP.NET and C#. A couple of months ago I wrote a similar article, using VB.NET. This article will show you how to upload Images (or any Binary Data ) to a Sql Server database using ASP.NET and C#. Part II, Retrieving Images from a Database ( C# ) , will show you how extract images from a database.

Building the Database Table
We start out by building our database table. Our image table is going to have a few columns describing the image data, plus the image itself. Here is the sql required to build our table in SQL Server or MSDE.
Building the Database Table
We start out by building our database table. Our image table is going to have a few columns describing the image data, plus the image itself. Here is the sql required to build our table in SQL Server or MSDE.
CREATE TABLE [dbo].[image] (
[img_pk] [int] IDENTITY (1, 1) NOT NULL ,
[img_name] [varchar] (50) NULL ,
[img_data] [image] NULL ,
[img_contenttype] [varchar] (50) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[image] WITH NOCHECK ADD
CONSTRAINT [PK_image] PRIMARY KEY NONCLUSTERED
(
[img_pk]
) ON [PRIMARY] GO
I'm a great fan of having a single column primary key, and making that key an Identity column, in our example, that column is img_pk. The next column is img_name, which is used to store a friendly name of our image, for example "Mom and Apple Pie". img_data is actually our image data column, and is where we will be storing our binary image data. img_contenttype will be used to record the content-type of the image, for example "image/gif" or "image/jpeg" so we will know what content-type we need to output back to the client, in our case the browser.

Building our Webform
Now that we have a warm, fuzzy place to store our images, lets build a webform to upload our images into the database.
Enter A Friendly Name



Select File To Upload:



Working with the Uploaded Image
Once the user posts the data, we have to be able to parse the binary data and send it to the database. Along with the main body of the code, we use a helper function called SaveToDB() to achieve this.
private int SaveToDB(string imgName, byte[] imgbin, string imgcontenttype)
{
//use the web.config to store the connection string
SqlConnection connection = new SqlConnection(ConfigurationSettings.AppSettings["DSN"]);
SqlCommand command = new SqlCommand( "INSERT INTO Image (img_name,img_data,img_contenttype) VALUES ( @img_name, @img_data,@img_contenttype )", connection );

SqlParameter param0 = new SqlParameter( "@img_name", SqlDbType.VarChar,50 );
param0.Value = imgName;
command.Parameters.Add( param0 );

SqlParameter param1 = new SqlParameter( "@img_data", SqlDbType.Image );
param1.Value = imgbin;
command.Parameters.Add( param1 );

SqlParameter param2 = new SqlParameter( "@img_contenttype", SqlDbType.VarChar,50 );
param2.Value = imgcontenttype;
command.Parameters.Add( param2 );

connection.Open();
int numRowsAffected = command.ExecuteNonQuery();
connection.Close();

return numRowsAffected;
}
In this function we are passing in 3 different parameters
imgName - the friendly name we want to give out image data
imgbin -- the binary or Byte array of our data
imgcontenttype - the content type of our image. For example: image/gif or image/jpeg

There are 3 parameters as SQLParameters and defines the type. Our first SQLParameter is @img_name and is defined as a VarChar with a length of 50. The 2nd parameter, @img_data, is the binary or Byte() of data and is defined with a data type of Image. The last parameter is @img_contenttype, is defined as a VarChar with a length of 50 characters. The remainder of the function opens a connection to the database and executes the command by calling command.ExecuteNonQuery().

Calling our Functions
Ok, now that we have our worker functions written, let's go ahead and get our image data.
Stream imgStream = UploadFile.PostedFile.InputStream;
int imgLen = UploadFile.PostedFile.ContentLength;
string imgContentType = UploadFile.PostedFile.ContentType;
string imgName = txtImgName.Value;
byte[] imgBinaryData = new byte[imgLen];
We need to access three important pieces of data for our example. We need the image:
Name (imgName_value)
Content-Type (imgContentType)
and the Image Data. (imgBindaryData)
First we access to the image stream, which we are able to get by using the property UploadFile.PostedFile.InputStream. (Remember, UploadFile was the name of our upload control on the webform). We also need to know how long the Byte array we are going to create needs to be. We can get this number by calling UploadFile.PostedFile.ContentLength, and storing it's value in imgLen. Once we have the length of the image, we create a byte array by byte[] imgBinaryData = new byte[imgLen]; We access the content type of the image by accessing the ContentType property of UploadFile.PostedFile. Lastly we need the friendly name we are going to use for the image.

The Good Stuff
Ok, we know how to connect to the database, we know how to insert data into the database, and we have access to the uploaded image's properties. But how do we pass the stream of the image to SaveToDB(). Again, .NET comes to the rescue. With 1 line of code we are able to access the image stream and convert it to a Byte array.
int n = imgStream.Read(imgBinaryData,0,imgLen);
The stream object provides a method called Read(). Read() takes 3 parameters:
buffer - An array of bytes. A maximum of count bytes are read from the current stream and stored in buffer.
offset -The byte offset in buffer at which to begin storing the data read from the current stream.
count - The maximum number of bytes to be read from the current stream.
So we pass in our Byte array, imgBinaryData; the place to start at, 0; and the amount of bytes we want to read. n number of bytes read into our array is returned.
Extending Beyond Images
Because we are able to access the binary stream of data, images are not the only object we can store in the database. Some other objects might be streaming video, com objects, or sound clips. As an example I also uploaded a streaming avi into my database. I ran a select query to show the results.


Conclusion
So there we have it, ASP.NET provides us some easy functionality for uploading images into a database. In Part II, we will actually look at pulling these images out of a database and sending them to a browser. The complete code used for this article can be found below.
Image SQL
CREATE TABLE [dbo].[image] (
[img_pk] [int] IDENTITY (1, 1) NOT NULL ,
[img_name] [varchar] (50) NULL ,
[img_data] [image] NULL ,
[img_contenttype] [varchar] (50) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[image] WITH NOCHECK ADD
CONSTRAINT [PK_image] PRIMARY KEY NONCLUSTERED
(
[img_pk]
) ON [PRIMARY]
GO
UploadImage.aspx
<%@ Page language="c#" Src="UploadImage.aspx.cs" Inherits="DBImages.UploadImage" %>







The ASPFree Friendly Image Uploader


Enter A Friendly Name



Select File To Upload:







UploadImage.aspx.cs ( codebehind file)
using System;
using System.Configuration;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Web;
using System.IO;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace DBImages
{
public class UploadImage : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button UploadBtn;
protected System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1;
protected System.Web.UI.HtmlControls.HtmlInputText txtImgName;
protected System.Web.UI.HtmlControls.HtmlInputFile UploadFile;

public UploadImage() { }

private void Page_Load(object sender, System.EventArgs e){ }

public void UploadBtn_Click(object sender, System.EventArgs e)
{
if (Page.IsValid) //save the image
{
Stream imgStream = UploadFile.PostedFile.InputStream;
int imgLen = UploadFile.PostedFile.ContentLength;
string imgContentType = UploadFile.PostedFile.ContentType;
string imgName = txtImgName.Value;
byte[] imgBinaryData = new byte[imgLen];
int n = imgStream.Read(imgBinaryData,0,imgLen);

int RowsAffected = SaveToDB( imgName, imgBinaryData,imgContentType);
if ( RowsAffected>0 )
{
Response.Write("
The Image was saved");
}
else
{
Response.Write("
An error occurred uploading the image");
}

}
}


private int SaveToDB(string imgName, byte[] imgbin, string imgcontenttype)
{
//use the web.config to store the connection string
SqlConnection connection = new SqlConnection(ConfigurationSettings.AppSettings["DSN"]);
SqlCommand command = new SqlCommand( "INSERT INTO Image (img_name,img_data,img_contenttype) VALUES ( @img_name, @img_data,@img_contenttype )", connection );

SqlParameter param0 = new SqlParameter( "@img_name", SqlDbType.VarChar,50 );
param0.Value = imgName;
command.Parameters.Add( param0 );

SqlParameter param1 = new SqlParameter( "@img_data", SqlDbType.Image );
param1.Value = imgbin;
command.Parameters.Add( param1 );

SqlParameter param2 = new SqlParameter( "@img_contenttype", SqlDbType.VarChar,50 );
param2.Value = imgcontenttype;
command.Parameters.Add( param2 );

connection.Open();
int numRowsAffected = command.ExecuteNonQuery();
connection.Close();

return numRowsAffected;
}
}
}
Web.Config