5,286,006 members and growing! (21,137 online)
Email Password   helpLost your password?
Web Development » Charts, Graphs and Images » Images and multimedia     Intermediate License: The GNU General Public License (GPL)

Gallery Server Pro - An ASP.NET Gallery for Sharing Photos, Video, Audio and Other Media

By Roger Martin

Gallery Server Pro is a complete, stable ASP.NET gallery for sharing photos, video, audio and other media. This article presents the overall architecture and major features.
Javascript, XML, CSS, SQL, HTML, XHTML, C# 2.0, VB 8.0, C#, VBWindows, .NET, .NET 3.0, .NET 2.0, Win2K, WinXP, Win2003, Vista, ASP.NET, GDI+, SQL, ADO.NET, WPF, WebForms, Ajax, VS2005, VS, CEO, Arch, DBA, Dev

Posted: 28 Oct 2007
Updated: 7 May 2008
Views: 68,693
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
55 votes for this Article.
Popularity: 8.10 Rating: 4.65 out of 5
1 vote, 1.8%
1
0 votes, 0.0%
2
6 votes, 10.9%
3
5 votes, 9.1%
4
43 votes, 78.2%
5
Screen shot of Gallery Server Pro

Introduction

Gallery Server Pro is a powerful and easy-to-use ASP.NET web application that lets you share and manage photos, video, audio, and other files over the web.

  • Stable, production ready
  • Use any web browser to organize your media files into albums you can easily add, edit, delete, rotate, rearrange, copy and move
  • Easily add thousands of files using one-click synchronize and ZIP file upload functions. Thumbnail and compressed versions are automatically created
  • Powerful user security with flexible, per-album granularity
  • Integrates with DotNetNuke and other Frameworks to provide a superior media gallery
  • Image metadata extraction. Supports these formats: EXIF, XMP, tEXt, IFD, and IPTC
  • Search function queries title, caption, filename, and image metadata
  • Image watermarking with your own text and/or image
  • AJAX-enabled for more responsive UI
  • Web-based installer makes installation painless
  • Uses SQL Server 2000 or higher as the data store. Supports MSDE 2000 and SQL Server 2005 Express
  • Uses ASP.NET Membership provider so you can integrate with your existing accounts, including Active Directory
  • Data access uses the ASP.NET Provider model, which allows other data stores such as MySQL, Microsoft Access, or Oracle to be used instead of SQL Server
  • 100% managed code written in C# and ASP.NET 2.0
  • Source code is released under the open source GNU General Public License
  • All web pages target XHTML 1.0 Strict and CSS 2.1 standards to ensure maximum forward compatibility

You can play with an online demo of Gallery Server Pro to get a sense of its capabilities. A pre-compiled version is available here along with additional documentation and a support forum.

Background

This project started in 2002 from my desire to share my photos over the web. I wanted my photos to remain on my own server, not somebody else's like EasyShare's or Shutterfly's. Since there weren't any free solutions to choose from at the time, I wrote my own.

It turned out so well that I released version 1 to the world in January 2006, and it was downloaded over 30,000 times. I spent most of 2006 and 2007 working on version 2, rewriting the code from the ground up to use the new features of .NET 2.0. This includes ASP.NET Membership, Roles, Profiles, generics, the data provider model, and several well known design patterns (strategy, iterator, factory, template method, and composite).

In this article I present the overall architecture and major features of Gallery Server Pro. The topics presented here can help if you want to learn more about:

  • Implementing a web gallery to share photos, video, audio, and other documents
  • Using ASP.NET Membership, Roles and Profile API
  • Using the composite design pattern to manage infinitely hierarchical relationships. In this case it is media objects and albums, but it also applies to employee/supervisor relationships, bill of materials, file/directory relationships, and other similar structured items
  • When and how to use the strategy design pattern
  • Using the data provider model in ASP.NET 2.0
  • A flexible technique for rendering distinct HTML to a browser based on the type of browser and type of object being rendered
  • Extracting metadata from images using the .NET 2.0 technique and the new WPF classes in .NET 3.0

Using Gallery Server Pro

Gallery Server Pro is a fully functional and stable web application ready for production use.

  1. Download the source code in this article and compile. Or download the compiled version. Then deploy the compiled web application to the destination web server.
  2. Use Internet Information Services (IIS) Manager to configure the directory as a web application. Make sure the application is running under ASP.NET 2.0.
  3. If using a version of IIS earlier than IIS 7, make sure the default document is set to default.aspx. IIS 7 users can skip this step.
  4. Use Windows Explorer to give the user account IIS that is running under "modify" permission to the config and mediaobjects directories.
  5. Using an SQL management tool such as SQL Management Studio (SQL Server 2005) or SQL Enterprise Manager (SQL Server 2000), create a new, empty database.
  6. Use a web browser to navigate to the Installer directory to start the web-based installer. For example, if you installed the files to C:\inetpub\wwwroot\gs\, then the URL is http://localhost/gs/installer/.
  7. Step through the install wizard. When finished, you have a working version of Gallery Server Pro.

Gallery Server Pro stores media objects such as photos, video, audio, and documents in albums. These files and albums are stored in a directory named mediaobjects within the web application. (This can be changed to any location on the web server.) An album is really just a directory, so an album named Vacation Photos is stored as a similarly named directory.

There are two main techniques for adding media objects:

  1. Upload a ZIP file containing the media files. If the ZIP file contains directories, they are converted to albums.
  2. Copy your media files to the media objects directory, and then start a synchronization in Gallery Server Pro.

When adding a media object, the following steps occur:

  1. The file is saved to the media objects directory. (If adding a media object via the synchronization technique, then this step is already done.)
  2. A thumbnail image is created and saved to the hard drive.
  3. For images, a compressed, bandwidth-friendly version is created and metadata such as camera model and shutter speed is extracted.
  4. A record is added to the data store to represent this media object.

Media objects are streamed to the browser through an HTTP handler. Below you can see a photo and a video being displayed. If watermarking is enabled, the watermark is applied to the in-memory version of the image just before it is sent.

Screenshot - imageview.jpg Screenshot - videoview.jpg

If you click the View metadata toolbar item above a media object, a popup DIV window displays the image's metadata, as shown below.

Screenshot - metadata.jpg

By default, everyone can browse the media objects. However, you must log on to perform any action that modifies an album or media object. Authorization to modify data is configured by type of permission and the albums to which it applies. For example, you can set up user Soren to have edit permission to the album Soren's photos. Another user Margaret is given edit permission to the album Margaret's photos. Each user can administer his or her own album but cannot edit albums outside his or her domain.

To learn more about how to use Gallery Server Pro from an end-user perspective, read the Administrator's Guide. Otherwise, read on to learn about the architecture and programming techniques.

Solution Architecture

The Visual Studio solution in the download contains ten projects. They are:

Project name Description
gsweb UI layer - ASP.NET 2.0 web application
TIS.GSP.WebControls Contains custom web server controls used in the web app
TIS.GSP.Business Business layer logic
TIS.GSP.Provider Data provider. Defines the contract the data layer must comply with
TIS.GSP.Business.Interfaces Defines all interfaces used in the solution
TIS.GSP.ErrorHandler Provides error handling support
TIS.GSP.Configuration Provides read/write access to settings stored in the configuration file galleryserverpro.config
TIS.GSP.Business.Wpf Provides enhanced image metadata extraction through the use of new WPF classes available in .NET 3.0. Contained in a separate project and invoked through reflection in a way that degrades gracefully when .NET 3.0 is not present
TIS.GSP.Data Data layer logic. Provides read/write access to data stored in SQL Server
TracingTools Provides tracing support

User Management and Security

User accounts are managed through the ASP.NET Membership, Roles, and Profile APIs. By default, Gallery Server Pro is configured to use SqlMembershipProvider for users, SqlRoleProvider for roles, and SqlProvider for profiles. However, because of the flexibility offered by the provider model, you can use any data store that has a membership provider. For example, you can use ActiveDirectoryMembershipProvider to plug Gallery Server Pro into your existing base of Active Directory users. The Administrator's Guide contains a section for Membership Configuration that provides more information.

Media Object, Albums and the Composite Pattern

Recall that each media object (photo, video, etc) is stored in an album. Albums can be nested within other albums, with no restriction on the number of levels. This is similar to how files and directories are stored on a hard drive.

It turns out that albums and media objects have a lot in common. They both have properties such as Id, Title, DateAdded, and FullPhysicalPath; and they both have methods such as Save, Delete, Copy, Remove, and ValidateTitle. This is the ideal situation in which to use the "Composite" design pattern, where common functionality is defined in a base object. I start by defining two interfaces — IGalleryObject and IAlbum:

Screenshot - IGalleryObject_classdiagram.jpg

The IAlbum interface inherits from IGalleryObject and then adds a method and a few properties that are specific to albums. Then I create the abstract base class GalleryObject. It implements the IGalleryObject interface and provides default behavior that is common to albums and media objects. For example, here is the Title property:

public string Title
{
  get
  {
    VerifyObjectIsInflated(this._title);
    return this._title;
  }
  set
  {
    value = ValidateTitle(value);

    this._hasChanges = (this._title == value ? _hasChanges : true);
    this._title = value;
  }
}

Now that the common functionality is defined in the abstract base class, I can create concrete classes to represent albums, images, video, audio, and other types of media objects:

Screenshot - galleryobject_classdiagram.jpg

With this approach there is very little duplicate code, the structure is maintainable, and it is easy to work with. For example, when Gallery Server Pro wants to display the title and thumbnail image for all the objects in an album, there might be any combination of child albums, images, video, audio, and other documents. But I don't need to worry about all the different classes or about casting problems. All I need is the following code:

// Assume we are loading an album with ID=42

IAlbum album = Factory.LoadAlbumInstance(42, true);
foreach (IGalleryObject galleryObject in album.GetChildGalleryObjects())
{
  string title = galleryObject.Title;
  string thumbnailPath = galleryObject.Thumbnail.FileNamePhysicalPath;
}

Beautiful, isn't it? But what happens when the functionality is slightly different between two types of objects? For example, Gallery Server Pro needs to enforce a maximum length of 200 characters for an album title and 1000 characters for the title of a media object (image, video, etc). Both types of objects need a Title property, but the validation is different. Does that mean we have to remove the Title property from the base class and put it in the derived classes?

Not at all! Refer back to the property definition for Title in the code we looked at earlier. Notice that in the setter there is a call to ValidateTitle. Here is what ValidateTitle looks like in the GalleryObject class:

protected virtual string ValidateTitle(string title)
{
  // Validate that the title is less than the maximum limit. 

  // Truncate it if necessary.

  int maxLength =
    GalleryServerPro.Configuration.ConfigManager.
    GetGalleryServerProConfigSection().DataStore.MediaObjectTitleLength;

  if (title.Length > maxLength)
  {
    title = title.Substring(0, maxLength).Trim();
  }
  return title;
}

The procedure is defined as virtual, allowing a derived class to override it if needed. In fact, that is exactly what the Album class does:

protected override string ValidateTitle(string title)
{
  int maxLength =
    GalleryServerPro.Configuration.ConfigManager.
    GetGalleryServerProConfigSection().DataStore.AlbumTitleLength;

  if (title.Length > maxLength)
  {
    title = title.Substring(0, maxLength).Trim();
  }

  return title;
}

The end result is that there is a base implementation in the base class that provides functionality for most cases, and code that is unique to albums is contained in the Album class. There isn't any duplicate code and the logic is nicely encapsulated. It is a thing of beauty to behold.

Using the Strategy Pattern for Persisting to the Data Store

We just saw how to override a method in the base class when we need to alter its behavior. I could have done something similar when it comes to saving the albums and media objects to the database. The Save method in the GalleryObject class could have been defined as virtual, and I could have overridden the method in each of the derived classes. But since the classes Image, Video, Audio, and GenericMediaObject all represent objects that get stored in the same table (gs_MediaObject), that would have meant writing the same code in all four classes, with only the Album class being different.

I could eliminate the problem of duplicate code by providing a default implementation in the Save method in the GalleryObject class. In that method, I save to the media object table, and then depend on the Album class to override the behavior, much like we did with the ValidateTitle method. However, this is putting a substantial amount of behavior in a base class that doesn't really belong there. We should limit the base class to contain state and behavior that applies to ALL derived objects.

You might argue that I violated this rule when I provided a default implementation of the ValidateTitle method that I overrode in the Album class. You are absolutely right. But I justify it by suggesting that implementing the title validation in every derived class creates undesirable duplicate code, and refactoring it to use the strategy pattern is overkill. These are not hard and fast rules. Architecting an application is as much art as it is science, and you must weigh the pros and cons of each approach.

Getting back to our challenge of persisting data to the data store, the approach I came up with was to use the "strategy" pattern to encapsulate behavior. First, I defined an interface ISaveBehavior :

public interface ISaveBehavior { void Save(); }

Then I wrote two classes that implemented the interface: AlbumSaveBehavior and MediaObjectSaveBehavior. The Save method takes care of persisting the object to the hard drive and data store. For example, here is the Save method in AlbumSaveBehavior:

public void Save()
{
  if (this._albumObject.IsVirtualAlbum)
    return; // Don't save virtual albums.


  // Save to disk.

  PersistToFileSystemStore(this._albumObject);

  // Save to the data store.

  GalleryServerPro.Provider.DataProviderManager.Provider.Album_Save
        (this._albumObject);
}

Notice that there is a call to PersistToFileSystemStore, which is a private method that ensures a directory exists corresponding to this album. Then there is a call to the Album_Save method of the Provider class, which persists the data to the gs_Album table in SQL Server. If you use a data provider other than the default SqlDataProvider, then the method delegates to that provider. We'll talk more about the data provider model later in this article.

OK, we have two classes for saving data to the data store — one for albums and one for media objects. How do we invoke the appropriate Save method from the GalleryObject base class?

Recall that the GalleryObject class is abstract, so it can never be directly instantiated. Instead, we instantiate an instance of the Album, Image, Video, Audio, or GenericMediaObject class. The constructor for each of these classes assigns the appropriate save behavior. For example, in the constructor of the Album class, we have:

this.SaveBehavior = Factory.GetAlbumSaveBehavior(this);

The GetAlbumSaveBehavior method just returns an instance of the AlbumSaveBehavior class:

public static ISaveBehavior GetAlbumSaveBehavior(IAlbum albumObject)
{
  return new AlbumSaveBehavior(albumObject);
}

The SaveBehavior property of the GalleryObject class is of type ISaveBehavior. Since both classes implement this interface, we can assign instances of either class to the property.

The Save method in the GalleryObject class simply calls the Save method on the SaveBehavior property. It has no idea whether the property is an instance of AlbumSaveBehavior or MediaObjectSaveBehavior, and it doesn't care. All that matters is that each class knows how to save its designated object.

This is an example of using the strategy pattern. Specifically, the strategy pattern is defined as a family of algorithms that are encapsulated and interchangeable. In our case, we have two save behaviors that are self-contained and can both be assigned to the same property (interchangeable). It is a powerful pattern and has many uses.

Rendering HTML for Video, Images, Audio and More

Displaying an image in a web browser is easy because all browsers recognize the <img> tag. But how does one implement a gallery that also includes video, audio, and documents such as Adobe PDF or Microsoft Word files? Browsers, by themselves, cannot play video and audio or natively display any files other than a few basic types like HTML, TXT, and maybe XML. These types of objects require plug-ins, and one cannot make any assumptions about what, if any, plug-ins are installed in a user's browser. Furthermore, Gallery Server Pro is meant to be flexible so that administrators can customize the HTML output rendered by Gallery Server Pro. For example, some users might prefer that video files are rendered with <object> tags in order to pass XHTML validation, while others might prefer <embed> for maximum backward compatibility. Lastly, different browsers require different syntax, and new versions of browsers are frequently released, potentially breaking something that works today.

The solution was to use a combination of HTML templates stored in a configuration file and automatic browser sniffing provided by ASP.NET. The configuration file galleryserverpro.config (stored in the config directory) contains HTML templates for each major type of media object. For example, rendering the HTML for an image is pretty straightforward. Here is the relevant entry in galleryserverpro.config:

<galleryObject>
 <mediaObjects>

  <mediaObject mimeType="image/*">
   <browsers>
    <browser id="default" htmlOutput="<div class="op1">
<div class="op2"><div class="sb">
<div class="ib"><img id="mo_img"
src="{MediaObjectUrl}" class="{CssClass}"
alt="{TitleNoHtml}" title="{TitleNoHtml}"
style="height:{Height}px;width:{Width}px;" />
</div></div></div></div>" />

The mediaObject tag specifies that the inner tags apply to the image/* MIME type. The asterisk (*) means that it will match all images, such as image/jpg, image/jpeg, and image/gif. Now, let's take a closer look at what is in the htmlOutput attribute of the browser tag:

<div class="op1">
 <div class="op2">
  <div class="sb">
   <div class="ib">
    <img id="mo_img" src="{MediaObjectUrl}"
class="{CssClass}" alt="{TitleNoHtml}"
title="{TitleNoHtml}" style="height:{Height}px;width:{Width}px;" />
   </div>

  </div>
 </div>
</div>

Note: In the configuration file the <, >, and " characters within the htmlOutput attribute are escaped with &lt;, &gt; and &quot;, but I show them here for easier readability.

The four <div> tags that surround the <img> tag support the drop shadow and border that appear around each image. But what is that stuff in the brackets, like {MediaObjectUrl}? Those are placeholders that are replaced with dynamically generated content at runtime. For example, {Height} is replaced with the height of the image. A full list and descriptions of these placeholders can be found in the Administrator's Guide.

When Gallery Server Pro uses the above template to render an image to the browser, it ends up looking something like this:

<div class="op1">
 <div class="op2">
  <div class="sb">
   <div class="ib">
    <img id="mo_img"
src="http://www.codeproject.com/gs/handler/getmediaobject.ashx?
moid=2064&aid=169&mo=D%3A%5Cgs%5Cmediaobjects%
5CzThumb_100_1768.jpeg&mtc=1&dt=1" alt="Grand Canyon"
style="width:86px;height:115px;" />

   </div>
  </div>
 </div>
</div>

If desired, one can tweak this template to change how <img> tags are rendered. For example, if you wanted to use the width and height attributes instead of a style, update the config file like this:

<browser id="default"
htmlOutput="<div class="op1"><div class="op2">
<div class="sb"><div class="ib">
<img id="mo_img" src="{MediaObjectUrl}"
class="{CssClass}" alt="{TitleNoHtml}"
title="{TitleNoHtml}" width="{Width}" height="{Height}" />
</div></div></div></div>" />

Image rendering is pretty straight forward, and the technique presented here would be an overkill if all we were doing was displaying images. But it becomes worthwhile once we get into the more complicated media types. For example, let's look at the relevant section of galleryserverpro.config that describes how video is rendered:

<mediaObject mimeType="video/*">
 <browsers>
  <browser id="default"
htmlOutput="<object type="{MimeType}"
data="{MediaObjectUrl}" style="width:{Width}px;height:{Height}px;" >
 <param name="src" value="{MediaObjectUrl}" />

<param name="autostart" value="{AutoStartMediaObjectInt}" />
</object>" />

Notice there are two mediaObject elements – one that specifies the MIME type video/* and the other that specifies video/quicktime. The HTML template under video/* handles all generic cases of rendering video. The second element handles the more specific case of QuickTime video, since that type requires different HTML. One could add additional mediaObject elements if, for example, AVI files required custom HTML.

Take a closer look at the browser entries inside the video/* template. There are two browser elements here – one with id="default" and the other id="ie". The id attribute uniquely identifies the browser element, and it must match the internal identifier of a browser as specified in the .NET Framework's browser definition file. See this for a hierarchical list of ids recognized by .NET Framework 2.0.

These two elements specify one HTML template for the default browser, and another for IE. If you look at the HTML templates closely, you will notice they are identical except that one specifies AutoStartMediaObjectInt and the other AutoStartMediaObjectText. That's because IE requires the autostart parameter to be text, like true or false, while other browsers require a numerical value (1 for true, 0 for false).

If, for example, you discovered that the Safari browser wasn't working quite right because of HTML incompatibilities, you could add a browser element with id="safari". Then add the HTML template using the syntax required by Safari, and you are finished. Gallery Server Pro and ASP.NET automatically detect the browser type and send the correct HTML.

Data Provider Model

One of the cool new features of ASP.NET 2.0 is the "provider model." In Gallery Server Pro, I used the provider model to define the API for reading and writing data to the data store. This allows one to use any source for data storage as long as a provider is written for it. Gallery Server Pro 2.0 includes SqlDataProvider, allowing it to interact with SQL Server. Additional providers can be written that use MySQL, Oracle, Microsoft Access, or even an XML file as the data store.

The diagram below shows the SqlDataProvider and DataProvider classes. Even though the names sound like official .NET Framework classes, these are classes I wrote specifically for Gallery Server Pro. The DataProvider class is an abstract class that inherits from the Microsoft .NET Framework class System.Configuration.Provider.ProviderBase. It doesn't contain any behavior; it only defines the methods that must be implemented by the "real" data provider, which in this case is SqlDataProvider. All data access in Gallery Server Pro passes through one of the methods in SqlDataProvider (except user account functions that pass through the other providers — membership, roles, and profile).

Screenshot - providerclassdiagram.jpg

To use an alternative data store such as MySQL, Oracle, Microsoft Access, or something else, write a new class that inherits from the DataProvider abstract base class. You can do this in a new project or by adding a class to the TIS.GSP.Data project. If you use a tool such as Visual Studio, it will automatically define all the methods that must be implemented. For example, here is the skeleton for the method to delete an album:

public override void Album_Delete(IAlbum album)
{
}

Gallery Server Pro will call this method whenever an album is to be deleted. It is your job, as the writer of this custom provider, to write the code that will delete the album record from your data store. How you do it is up to you.

Note: Refer to the code in the SqlDataProvider class to ensure you provide similar behavior. For example, when deleting an album the SqlDataProvider class executes a stored procedure that recursively deletes all child albums of the specified album. Your custom provider should behave similarly.

Once you have implemented all the methods and compiled your code, you are ready to configure Gallery Server Pro to use your provider. Copy the DLL containing your provider into the bin directory of the Gallery Server Pro web application. Update the data provider section of galleryserverpro.config. For example, if your provider is in a class named OracleDataProvider that is in an assembly named GalleryServerPro.Data.Oracle.dll, the data provider section will look like this:

<dataProvider defaultProvider="OracleDataProvider">
  <providers>
    <add name="OracleDataProvider"
type="GalleryServerPro.Data.Oracle.OracleDataProvider, 
        GalleryServerPro.Data.Oracle" />
  </providers>
</dataProvider>

Image Metadata Extraction

Image files, most commonly JPGs, can contain metadata such as camera model and shutter speed. In addition, utilities such as Vista's Photo Gallery allow users to add keywords, titles, ratings, and more. Gallery Server Pro can extract this data in any of the following formats: EXIF, XMP, tEXt, IFD, and IPTC.

The code to extract metadata is based on the Code Project article A Library to Simplify Access to Image Metadata, which itself was based on the article Photo Properties. I'd like to thank these authors for their hard work. The techniques in these articles are based on parsing the metadata that is accessible through the PropertyItems property of a System.Drawing.Image object. I refactored much of the code to make it easier to understand (and therefore maintain), faster, more flexible, and more robust.

The introduction of the System.Windows.Media.Imaging namespace in .NET 3.0 provided an improved method of extracting metadata, including the ability to get data not previously accessible — most notably titles and keywords.

So now there are two ways to get metadata from an image — the .NET 2.0 way and the .NET 3.0 way. While the .NET 3.0 technique is better, I wanted Gallery Server Pro to work on a system without .NET 3.0 installed. As a result, the metadata is extracted using the following process:

  1. If .NET 3.0 is installed on the web server, use the BitmapMetadata class in the System.Windows.Media.Imaging namespace to extract as much metadata as possible into a custom collection named GalleryObjectMetadataItemCollection.
  2. Instantiate the image into a System.Imaging.Image object. Use the PropertyItems property to extract as much metadata as possible. For each metadata item (e.g. shutter speed), add it to the GalleryObjectMetadataItemCollection collection, but only if it wasn't already added in step 1.

In other words, if the same metadata item is extracted using both techniques, we keep the data from the .NET 3.0 method and discard the .NET 2.0 version.

The logic for extracting metadata is hidden behind the business layer class MediaObjectMetadataExtractor. When an image is added to the gallery, the following code is executed in the GalleryServerPro.Business.Image constructor:

Metadata.MediaObjectMetadataExtractor metadata =
new Metadata.MediaObjectMetadataExtractor(imageFile.FullName);
this.MetadataItems.AddRange(metadata.GetGalleryObjectMetadataItemCollection());

The variable imageFile is an instance of System.IO.FileInfo that refers to the image. The MetadataItems property is a GalleryObjectMetadataItemCollection collection. Once the metadata is extracted and saved, one can easily iterate through the items and get the name/value pairs:

// Assume we are loading an image with ID=27

IGalleryObject image = 
    GalleryServerPro.Business.Factory.LoadMediaObjectInstance(27);
foreach (IGalleryObjectMetadataItem metadataItem in image.MetadataItems)
{
  string name = metadataItem.Description; // e.g. Camera model, Shutter speed

  string value = metadataItem.Value; // e.g. F5.7, 1/350 sec

}

Summary

This has been a brief introduction to the architecture and programming techniques used in Gallery Server Pro. Feel free to download the source code and use the bits to help in your own project. Cheers!

Article History

2007 Oct 28: Article release.

2008 May 6: Updated to include latest source files and minor content updates.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPL)

About the Author

Roger Martin


I have over 12 years of industry experience in software development, architecture, and Microsoft Office products. My company Tech Info Systems provides custom software development services for corporations, governments, and other organizations. Tech Info Systems is a registered member of the Microsoft Partner Program and I am a Microsoft Certified Solutions Developer (MCSD).

I am the creator and lead developer of Gallery Server Pro, a free, open source ASP.NET gallery for sharing photos, video, audio, documents, and other files over the web. It has been developed over several years and has involved thousands of hours. The end result is a robust, configurable, and professional grade gallery that can be integrated into your web site, whether you are a large corporation, small business, professional photographer, or a local church.
Occupation: Web Developer
Location: United States United States

Other popular Charts, Graphs and Images articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 70 (Total in Forum: 70) (Refresh)FirstPrevNext
Subject  Author Date 
Generalhelp me in playing the video filememberravurirkk0:35 7 Jul '08  
GeneralVideo first framemembershahara21:30 30 Jun '08  
GeneralError: The project type is not supported [modified]memberyymca14:07 27 Jun '08  
GeneralRe: Error: The project type is not supportedmemberRoger Martin10:31 29 Jun '08  
Generalunable to open csproj in vs2005memberITConfluence9:12 20 Jun '08  
GeneralRe: unable to open csproj in vs2005memberRoger Martin9:20 20 Jun '08  
Generalrequest for helpmembervahidseydi1:31 14 Jun '08  
QuestionErrormemberJohnAndre13:09 13 Jun '08  
AnswerRe: ErrormemberRoger Martin6:58 14 Jun '08  
QuestionSet different start pagememberrrlevron13:55 12 May '08  
AnswerRe: Set different start pagememberRoger Martin14:16 12 May '08  
QuestionRe: Set different start pagememberrrlevron15:39 12 May '08  
AnswerRe: Set different start pagememberRoger Martin11:01 13 May '08  
GeneralBeautiful Work! Execelente! (in spanish)memberMember 170077111:53 29 Mar '08