posts - 14, comments - 10, trackbacks - 0

My Links

News

Archives

Post Categories

How to download multiple images (/files) from SQL Server to client using ASP.NET and DotNetZip?

How to download multiple images (/files) from SQL Server to client using ASP.NET and DotNetZip?
Here is a simple way you can use to let your web site users download multiple images or files at once. For this article, I will be focused on images but the same technique can be used for downloading files also. I will be describing how to zip all the images in a folder and send the zipped file to the client.
In my case, the images were stored in SQL Server as binary data so I had to come up with a process to first get the images out of the database and then zip them.
I was working on the Personal Website Starter kit available at www.asp.net. It has an Album section where users can view and download pictures. The download method available in the starter kit is not very user friendly. The user has to click the “Download Photo” button which opens the image in a browser window. The user can then right click the image and do a Save Picture As…
What my method does is it zips all the images in the current album and then sends it to the client by just a click of a button. When the user clicks the Download button, she/he is presented with an “Open, Save, Cancel” message box for the download. For now, this method sends all the images in an album to the client but can be easily modified to send only the selected images or selected albums or selected files or whatever.
I will be using a DotNetZip zipping library available at http://www.codeplex.com/DotNetZip.
To summarize the steps:
1.       Create temporary User Directory to store images and zipped file.
2.       Get all photos by album id.
3.        Store images in the folder
4.       Zip the folder
5.       Download the zipped file
6.       Delete all temporary files and folders (optional).
 To start: You should create a folder in your web site directory to store temporary images and zipped files. I created a folder named “Download” just for that.
This is how it will work. My code creates temporary directories by user names for the registered users when they try to download an album. If a user is not registered and is trying to download a public album, I create a folder using GUID so that the folder names do not interfere with each other.
Now down to business: Here’s the code:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Data.SqlClient;
using Ionic.Utils.Zip;
 
public partial class Photos_aspx : System.Web.UI.Page
{
    int albumID = -1;
      
    protected void Page_Load(object sender, EventArgs e)
    {
        albumID = Convert.ToInt32(Request.QueryString["AlbumID"]);
    }
 
    protected void DownloadButton_Click(object sender, ImageClickEventArgs e)
    {
        if (albumID == -1)
        {
            return;
        }
 
        string folderName = Server.MapPath("~/") + "\\Download\\";
 
        // Create a temp directory for the logged in user
 
        DirectoryInfo di = CreateUserDirectory(folderName);
 
        // Get images from database into a dataset on webserver
 
        DataSet ds = GetPhotosByAlbumID(albumID);
 
        // Store the images from dataset to a folder
 
        StoreImagesInFolder(ds, di.FullName);
 
        // Zip contents of the folder
 
        string fileName = ZipFolder(di.FullName);
 
        Download(fileName);
 
        di.Delete(true);
    }
 
    /* Create temporary User Directory to store images and zipped file. */
 
    public DirectoryInfo CreateUserDirectory(string directoryPath)
    {
        // Initialize userName by GUID

        string userName = System.Guid.NewGuid().ToString("N");
       
        // If user is registered, use the new userName else use GUID
 
        if (!string.IsNullOrEmpty(User.Identity.Name))
        {
            userName = User.Identity.Name;
        }

        string userDirectoryName = directoryPath + "\\" + userName;
        DirectoryInfo di;
  
        // Create a directory for the user
 
        if (!Directory.Exists(userDirectoryName))
        {
            di = System.IO.Directory.CreateDirectory(userDirectoryName);
            return di;
        }
        else
        {
            di = new DirectoryInfo(userDirectoryName);
        }
        return di;
    }
 
    /* Get all photos by album id */
 
    public DataSet GetPhotosByAlbumID(int AlbumID)
    {
        //Initialize SQL Server connection.
 
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Personal"].ConnectionString))
        {
            SqlDataAdapter adapter = new SqlDataAdapter();
 
            using (SqlCommand command = new SqlCommand("GetPhotos", connection))
            {
                command.CommandType = CommandType.StoredProcedure;
                command.Parameters.Add(new SqlParameter("@AlbumID", AlbumID));
                bool filter = !(HttpContext.Current.User.IsInRole("Friends") || HttpContext.Current.User.IsInRole("Administrators"));
                command.Parameters.Add(new SqlParameter("@IsPublic", filter));
                connection.Open();
                adapter.SelectCommand = command;
                DataSet dataSet = new DataSet();
                adapter.Fill(dataSet, "Photos");
                return dataSet;
            }
        }
    }
 
    /* Store images in the folder */
 
    public void StoreImagesInFolder(DataSet ds, string folderName)
    {
        foreach (DataRow row in ds.Tables["Photos"].Rows)
        {
            // Get the image caption

            string FileName = row["Caption"].ToString();
            FileStream outStream;
            if (FileName.Contains(".JPG") || FileName.Contains(".jpg"))
            {
                outStream = File.OpenWrite(folderName + "\\" + FileName);
            }
            else
            {
                outStream = File.OpenWrite(folderName + "\\" + FileName + ".JPG");
            }
 
            //Get the original image data
 
            byte[] imageData = (byte[])row["BytesOriginal"];
 
            //Read image data into a memory stream

            using (MemoryStream ms = new MemoryStream(imageData, 0, imageData.Length))
            {
                ms.WriteTo(outStream);
 
                outStream.Flush();
                outStream.Close();
 
            }
        }
    }
 
    /* Zip the folder */
 
    private string ZipFolder(string folderName)
    {
        // This call is just to get the Album name, you can skip this and name it anything, like may be use GUID again
 
        System.Collections.Generic.List<Album> list = PhotoManager.GetAlbumByAlbumID(albumID);
 
        string albumName = list[0].Caption;
       
        //string fileName = folderName + "\\" + System.Guid.NewGuid().ToString("N") + ".zip";
        string fileName = folderName + "\\" + albumName + ".zip";
        using (ZipFile zip = new ZipFile("MyZipFile.zip"))
        {
            // add this file into the "images" directory in the zip archive

            zip.AddDirectory(folderName);
            zip.Save(fileName);
        }

        // Return zipped file name
 
        return fileName;
    }  
 
    /* Download the zipped file */
 
    public void Download(string fileName)
    {
        System.IO.FileInfo file = new System.IO.FileInfo(fileName);
        //-- if the file exists on the server
        //set appropriate headers
        if (file.Exists)
        {
            Response.Clear();
            Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
            Response.AddHeader("Content-Length", file.Length.ToString());
            Response.ContentType = "application/octet-stream";
            Response.WriteFile(file.FullName);
            Response.Flush();
            Response.Close();
        }
        else
        {
            Response.Write("This file does not exist.");
        }
    }
}
Here's the Stored Procedure GetPhotos:
CREATE PROCEDURE [dbo].[GetPhotos]
      @AlbumID int,
      @IsPublic bit
AS
      SELECT *
      FROM [Photos] LEFT JOIN [Albums]
            ON [Albums].[AlbumID] = [Photos].[AlbumID]
      WHERE [Photos].[AlbumID] = @AlbumID
            AND ([Albums].[IsPublic] = @IsPublic OR [Albums].[IsPublic] = 1)
    ORDER BY [Photos].[Caption] 
RETURN
If you notice, instead of using Response.End() in the Download method I have user Response.Flush() with Response.Close(). This is important if you want to delete the folders after you are done. If you want to keep all the files after sending it to the client, you can just replace those two lines with Response.End().
I hope this helps someone. 

Print | posted on Friday, January 09, 2009 1:20 AM | Filed Under [ ASP.NET ]

Feedback

Gravatar

# re: How to download multiple images (/files) from SQL Server to client using ASP.NET and DotNetZip?

I want the database of this code(stored procedure).Please send if u can
2/24/2009 11:09 PM | Vikas
Gravatar

# re: How to download multiple images (/files) from SQL Server to client using ASP.NET and DotNetZip?

Vikas-

I have added the stored procedure to the post.
2/25/2009 1:19 AM | bullpit

Post Comment

Title  
Name  
Email
Url
Comment   

Powered by: