HomeASP.NET Slapping a Photo Gallery Together in ASP.N...
Slapping a Photo Gallery Together in ASP.NET Part I
You have a pile of photos that everyone is dying to see. While you could just upload them to a photo gallery on the Web, you're not happy about the various restrictions involved (such as bandwidth and Web space). You would like to create your own photo gallery, but you don't want to spend a lot of time or effort on it. This article, the first of two parts, shows how to throw a photo gallery together fairly quickly using ASP.NET.
Contributed by Harish Kamath Rating: / 39 April 04, 2005
What’s worse: going to back to work after a well-deserved vacation or keeping your friends and relatives - keen to catch a glimpse of the beautiful pictures that you've clicked on your vacation - at bay?
Well, I do not have an answer to the first problem; I'm pretty sure that no one does. But, I can surely suggest a viable solution for the second: upload the photographs to the World Wide Web. This way, everyone can view the photographs at their own leisure and you can avoid having to flip through them for every Tom, Dick and Harry who wants to see them.
There are numerous websites that allow users to upload photographs and organize them into albums, making it easy for everyone to view them. However, each of them come with their own little caveats. Some restrict the amount of Web space (digital photographs can guzzle up disk space very quickly) for your albums, while others restrict the amount of bandwidth that you can utilize and, more often than not, this results in your online galleries being disabled for long periods of time.
That’s where this article comes in. During the course of this two part series, I'll attempt to teach how to develop a basic, functional online photo gallery using ASP.NET. Fortunately, for you and me, the .NET platform is equipped with a bunch of useful classes that make the task of managing folders and files (including image files) on the server very easy.
Before I get into the nitty gritty of coding the "Photo Gallery" application, let me give you a little note on how I've organized my photo collection on the server. I've already hinted that I plan to use the file and folder management classes available on the .NET platform in order to develop this application. So, it logically follows that the most convenient manner to organize the photographs on the file-system is by creating a folder structure that reflects the location and purpose of each vacation.
As seen above, the folder structure is almost self-explanatory as far as the location and purpose of each vacation is concerned. You can easily follow a similar naming convention for each image file in each album and voila - you do not need to worry about storing the descriptions for your photographs separately!
Next, you have to look into the permissions assigned to the entire folder structure that forms a part of the application. It is essential to ensure that the special "ASPNET" user - created at the time of installation of the .NET framework - has the required permissions (especially if you wish to create folders dynamically using ASP.NET scripts) across the entire folder structure, listed above.
Now, its time to get our hands dirty with some code - the following example introduces the Directory() object:
Save this script under the root folder of the Web server and load it into your favorite browser to view the one of the following outputs:
1. If the "Gallery" folder, stored in the "strPhotoGalleryRoot" variable, exists.
2. If the "Gallery" folder does not exist at the specified location.
Coming back to the code listing: for starters, I've imported the "System.IO" namespace as the Directory() object as part of the "System.IO" .NET assembly. As you may already know, it is recommended that you import the required namespaces using the "import" directive, as it allows you to create object instances without having to provide the complete class path at the time of instantiation.
Next, I've defined a variable titled "strPhotoGalleryRoot" - as the name suggests, I use this string variable to store the path to the root folder of my "Photo Gallery."
It's time to say hello the Directory() object. This .NET object, equipped with a bunch of static methods, allows you to work with any folder located on the file system of the Web server. For the uninitiated, static methods are object methods that can be invoked without the need to create an object instance of the underlying class.
Finally, the above example demonstrates the use of the Exists() static method of the Directory() object - it returns a "true" value if a particular path exists or a "false" value otherwise.
While I'll agree that the example in the previous section wasn't as complex as a session on "Theory of Relativity" would be, it does its job of laying down a foundation on which I can build further. Take a peek at the next code listing; that should convince you of the utility of this Directory() object.
// custom function to return the list of photographs // a.k.a. image files for a particular file system location void GetPhotos(string strFileSystemPath) {
// define array to store list of "Photos" string[] aryPhotos;
// use the GetFiles() static method // to obtain a list of image i.e. JPEG files aryPhotos = Directory.GetFiles(strFileSystemPath, "*.jpg");
// iterate over array of "Photos" to // get details of each Photo foreach(string strPhoto in aryPhotos) {
// custom function to return the list of photo albums // a.k.a folders for a particular file system location void GetPhotoAlbums(string strFileSystemPath) {
// define array to store list of "Photo Galleries" string[] aryPhotoAlbums;
// check if the current folder exists if(Directory.Exists(strFileSystemPath)) {
// use the GetDirectories() static method // to obtain a list of sub-folders aryPhotoAlbums = Directory.GetDirectories(strFileSystemPath);
output.Text += "<UL>";
// iterate over array of "Photo Album" to // get details of each Photo Album foreach(string strPhotoAlbum in aryPhotoAlbums) {
// invoke the GetPhotos() custom function // to list the "Image Files" in a particular folder GetPhotos(strFileSystemPath);
output.Text += "</UL>";
} else {
output.Text += "Sorry, the folder <U>" + strFileSystemPath + "</U> could not be located."; }
}
void Page_Load(Object sender, EventArgs e) {
// path to the root folder of the "Photo Gallery" string strPhotoGalleryRoot = "E:\\inetpub\\wwwroot\\Gallery";
// function to retrieve the Albums GetPhotoAlbums(strPhotoGalleryRoot); } </SCRIPT> <HTML> <HEAD> <TITLE>My Gallery</TITLE> <BASEFONT face="Arial" /> </HEAD> <BODY> <asp:Label id="output" runat="server" /> </BODY> </HTML>
This is what the output of the script should like for a two level "Photo Gallery" - the top level consists of albums, i.e. folders, and the second level consists of photographs, i.e. image files.
Evident from the output, the above code listing iterates over my two-level "Photo Gallery" folder structure and displays the names of the sub-folders under the root folder, followed by the names of the files (with a "jpg" extension only) present in each sub-folder.
Time for some explanation. Let me first focus on the de facto Page_Load() function. Here, I've already stated the purpose of the "strPhotoGalleryRoot" string variable. So, let me skip straight to the GetAlbums() custom function.
As the name suggests, the GetAlbums() function takes a file-system path to a folder and uses the GetDirectories() method of the Directory() object to retrieve an array of string values. Each value in this array represents the name of a sub-folder (a.k.a. "Albums" in our custom "Photo Gallery" terminology) of the root folder (passed as an input parameter).
Within my GetPhotoAlbums() custom function, I've defined an array - aryPhotoAlbums[] - to store the list of sub-folders, as described above. Next, I perform a little check to see if the current folder exists. If it does, I've invoked the GetDirectories() method and stored the return array value in the aryPhotoAlbums[] array.
Next, I've used the "foreach" loop to iterate through my aryPhotoAlbums[] array. Once again, I've invoked the GetPhotoAlbums() function to fetch subsequent sub-folders; this recursive mechanism ensures that the above script is capable of handling an n-level folder hierarchy without any changes.
Finally, I have defined another custom function called GetPhotos(), this uses the GetFiles() static method of the Directory() object to retrieve an array containing the names of the files present in a particular folder.
And since I am putting together a "Photo Gallery," it makes sense to restrict the contents of the array to image files. Hence, the second optional parameter of the GetFiles() method; this allows me to specify a pattern, and the list will be filtered accordingly. For example, the pattern *.jpg returns a list of files with the "jpg" extension.
One more point that I would like to highlight here is the use of the Substring() method to format the output by stripping of the file-system path up to the file (or folder) in question.
Before we move to the next section, here is a quick peek at the output if the "root" folder specified in the "strPhotoGalleryRoot" does not exist:
Remember the idiom "there is more than one way to skin a cat"? There is no better example for this than the file management assemblies on the .NET framework.
Why, you may wonder?
Take a look at the Directory() (that I introduced in the earlier section) and the DirectoryInfo() (that I'll introduce in the current section) objects. The two .NET objects are similar as far as functionality is concerned. However, the methods associated with the new DirectoryInfo() object are non-static. In plain English, I must create an instance of the DirectoryInfo() class before I can invoke any of its methods, unlike for the Directory() class.
Time to review the next code listing that introduces the DirectoryInfo() object:
// custom function to return the list of photo albums // a.k.a folders for a particular file system location void GetPhotoAlbums(string strFileSystemPath) {
// define a null object to store list of "Photo Galleries" DirectoryInfo[] objPhotoAlbums = null;
try {
// create an instance of the DirectoryInfo() object // on the basis of the file-system path provided DirectoryInfo objCurrentPhotoAlbum = new DirectoryInfo(strFileSystemPath);
output.Text += "<UL>";
// use the GetDirectories() method // to obtain a list of sub-folders objPhotoAlbums = objCurrentPhotoAlbum.GetDirectories();
// iterate over collection of DirectoryInfo objects // get details of each "Photo Album" foreach(DirectoryInfo objPhotoAlbum in objPhotoAlbums) {
// no value in query string // start at root level of "Photo Gallery" strCurrentPhotoAlbumPath = strImageGalleryRoot;
} else {
// enable the "Up One Folder Link" // only if we are NOT at the root folder level if(Request.QueryString["strPhotoAlbumPath"] != strImageGalleryRoot) {
// escape the "\" character from the query string value strCurrentPhotoAlbumPath = Request.QueryString["strPhotoAlbumPath"].Replace("\\","\\\\"); }
// display the name of the current "Photo Album" // using the "strCurrentPhotoAlbumPath" variable int intStartPosition = strCurrentPhotoAlbumPath.LastIndexOf("\\") + 1; int intLength = strCurrentPhotoAlbumPath.Length - intStartPosition; output.Text += "You are currently viewing the <U>" + strCurrentPhotoAlbumPath.Substring(intStartPosition, intLength) + "</U> Photo Album.";
// get the Photo Albums and Photos under current Photo Album GetPhotoAlbums(strCurrentPhotoAlbumPath); } </SCRIPT> <HTML> <HEAD> <TITLE>My Gallery</TITLE> <BASEFONT face="Arial" /> </HEAD> <BODY> <asp:Label id="output" runat="server" style="line-height:25px" /> <BR /><BR/> <asp:Label id="back" runat="server" visible="true" /> </BODY> </HTML>
And here is the output:
One of the most noticeable changes in the output is the association of a hyperlink with each Photo Album in the listing. Click on a Photo Album at the root level and the script will immediately display a list of more Photo Albums (a.k.a. sub-folders) and Photos (a.k.a. the image files) present under the current Photo Album (a.k.a. folder).
A resourceful "Up One Level" hyperlink allows the viewer to navigate back to the parent folder with great ease.
The programming logic behind this example is straightforward - I've set up the script to recursively pass the file-system path to the selected Photo Album (a.k.a. folder) in the query string. The same script, then, retrieves this path using the "QueryString" property of the Request() object. If there is no such value - for example, when you load the script for the first time - the script defaults to the root folder of the "Photo Gallery."
Note that you may have to escape the "backslash" character from the file-system path in order to avoid any unforeseen errors.
This is followed by some deft string manipulation in order to retrieve the name of the current Photo Album (a.k.a. folder).
Once again, I've resorted to my custom GetPhotoAlbums() function. However, this time around the function has been totally re-written in order to leverage on the properties and methods of the DirectoryInfo() object.
To begin with, I've defined an array titled "objPhotoAlbums" to a collection of DirectoryInfo() objects. The purpose remains the same as in the earlier example, only the data type to be stored in the array is different.
Within the resourceful try-catch-finally block, I've created my first instance of the DirectoryInfo() object. Note that you have to pass the file-system path as an input parameter to the constructor of the object. If the path does not exist, the script will immediately throw an exception and exit, as shown below.
But if the directory exists, the script invokes the GetDirectories() method of the DirectoryInfo(). This is where the two objects, i.e. the Directory() and DirectoryInfo() objects, differ in their behavior. Much to the satisfaction of OOPs purists, this GetDirectories() method returns a collection of DirectoryInfo() objects - one for each sub-folder. I can easily obtain the names of each sub-folder (representing a "Photo Album") using the "Name" property of the DirectoryInfo() object. However, I need the complete path to the sub-folder in order to generate the required hyperlink. No sweat; the DirectoryInfo() object is equipped with a "FullName" property that gives me the entire path to the sub-folder, including the starting drive letter.
Note that I have re-used the static GetFiles() method of the Directory() object in order to retrieve the image files present in the current folder. There is no sinister motive behind this move; only an attempt to keep things simple.
In the next section, I will take a little detour from my "Photo Gallery" application and show you how to create folders using this new DirectoryInfo() object.
So far, I've demonstrated how you can use different .NET objects to navigate around the file system. For the sake of completeness, I will now demonstrate how you can create folders using the DirectoryInfo() object.
// path to the root folder string strFileSystemPath = "E:\\inetpub\\wwwroot\\Gallery";
// create an instance of the DirectoryInfo() object // on the basis of the file-system path provided DirectoryInfo objCurrentFolder = new DirectoryInfo(strFileSystemPath);
// A quick check if a folder by the same name already exists string strNewFolderPath = strFileSystemPath + "\\" + txtDirectoryName.Text; DirectoryInfo objNewFolder = new DirectoryInfo(strNewFolderPath);
// check if folder exists already if(objNewFolder.Exists) {
// if it does, display error message... output.Text = "A folder by this name already exists.";
} else {
// ... and if it does, create a new folder with the required name objNewFolder = objCurrentFolder.CreateSubdirectory(txtDirectoryName.Text); output.Text = "Folder \"" + txtDirectoryName.Text + "\" was created successfully."; }
} else {
output.Text = "Please enter a folder name to be created."; }
Here is the output after the required folder has been successfully created:
If things do not go quite the way you expected, you should an error that looks like this:.
To kick things off in this script, I've created an instance DirectoryInfo() object for the root folder, specified in the "strFileSystemPath" string variable. Next, I've instantiated another DirectoryInfo() object representing the new folder that I wish to create.
The "Exists" property of the DirectoryInfo() object can be used to verify whether a folder with the same name already exists. If yes, the script exits with a polite message, as seen above. If not, I've invoked the CreateSubdirectory() method to create the required folder.
The many "if-else" blocks in the script take care of different scenarios that I may come across. A closer look at the error messages associated with each block should help to make things clear.
Deleting a directory is not a problem. The DirectoryInfo() object has a handy Delete() method to delete a particular directory. Go ahead, give it a shot and I'm sure that you'll not be disappointed.
Want to make things interesting? Just pass a Boolean "true" value to this Delete() method. Within seconds, the Delete() method will wipe out your entire collection. As you might have guessed, if this Boolean parameter is set to "true," the ASP.NET script will delete all files recursively.
This is not a very smart move. Always use the Delete() method with great care. Period.
This brings us to the conclusion of the first part of this two part series. Today, I began with the intention of creating a no-frills "Photo Gallery" application. To that end, I've already shown you how to organize the photographs on the server. This was followed by an introduction to the Directory() and DirectorInfo() objects; the main difference between these two counterparts of the System.IO .NET assembly is that the former contains mostly static methods whereas the latter does not. For the sake of completeness, I have also shown you how to create and delete folder(s) on the server in your ASP.NET scripts.
In the second part of the tutorial, I shall concentrate on files. You should not be surprised to learn that once again, we have to deal with two different objects: the File() and the FileInfo() objects. Finally, I will demonstrate my no-frills "Photo Gallery" application - something that all of you have been waiting for with bated breath.
So, till next time - stay healthy and keep clicking!
Note: All examples in this article have been tested on Windows 2000 Server with ASP.NET version 1.1 . Examples are illustrative only, and are not meant for a production environment. YMMV!