Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Simple ASP.NET Flickr Application

0.00/5 (No votes)
17 Nov 2010 1  
A simple Flickr application using the Flickr.Net API library and some cool effects.

Introduction

First of all, I want to thank Sam Judson who created a very useful project and that he shared it to us all. Without his effort, this article will be much longer and tedious. So thanks to him and other people who collaborated on that project. All project details and downloads can be found at this address: http://flickrnet.codeplex.com/.

I also used a light-weight, customizable lightbox plug-in for jQuery 1.3 and 1.4, called ColorBox, for adding a nice effect on the image preview. ColorBox is written by Jack Moore, and thanks to him too; you can find more details here: http://colorpowered.com/colorbox/. The version I'm using is 1.3.3, but you can update your projects with latest versions if you wish. More details about the version history can be obtained here: http://colorpowered.com/colorbox/core/README.

Another essential thing in order to use a Flickr API is creating your own API key and your secret key. If you already have a Yahoo! account, it will be quite simple; otherwise, you should create one. In both cases, you can start from here: http://www.flickr.com/services/api/keys/. For more details about the Flick API, visit http://www.flickr.com/services/api/.

Note that the API key and secret key used in the sample application are fake, they will not work. You'll get an error message when executing the application. So you should change them, in the web.config, with data you got from Flicker! (Haven't you created your own key? Bad bad, go to http://www.flickr.com/services/api/keys/.)

Getting started

Start by creating an empty ASP.NET Web Site. I used Visual Studio 2010 Ultimate, but the same can be accomplished with Visual Studio Express as it can be done with previous versions of Visual studio such as 2008 or 2005.

Using the code

Let's write some code. Add to your project an ASP.NET folder App_Code and create a new class and call it FlickrBLL. This is the code to be added:

using System;
using System.ComponentModel;
using System.Configuration;
using FlickrNet;

namespace Infrastructure.BLL
{
    /// <summary>
    /// Helper class for confortable pagining and binding
    /// </summary>
    [DataObject(true)]
    public class FlickrBLL
    {
        [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
        public static PhotosetPhotoCollection GetPagedSet(string setId, 
                      int maximumRows, int startRowIndex)
        {
            Flickr flickr = new Flickr(ConfigurationManager.AppSettings["apiKey"],
                ConfigurationManager.AppSettings["shardSecret"]);
            PhotosetPhotoCollection photos = flickr.PhotosetsGetPhotos(setId, GetPageIndex(
                startRowIndex, maximumRows) + 1, maximumRows);

            return photos;
        }

        public static int GetPagedSetCount(string setId)
        {
            Flickr flickr = new Flickr(ConfigurationManager.AppSettings["apiKey"],
                ConfigurationManager.AppSettings["shardSecret"]);
            Photoset set = flickr.PhotosetsGetInfo(setId);
            return set.NumberOfPhotos;
        }

        [DataObjectMethodAttribute(DataObjectMethodType.Select, false)]
        public static PhotosetCollection GetPhotoSetsByUser(string userId)
        {
            Flickr flickr = new Flickr(ConfigurationManager.AppSettings["apiKey"],
                ConfigurationManager.AppSettings["shardSecret"]);

            return flickr.PhotosetsGetList(userId);
        }

        protected static int GetPageIndex(int startRowIndex, int maximumRows)
        {
            if (maximumRows <= 0)
                return 0;
            else
                return (int)Math.Floor((double)startRowIndex / (double)maximumRows);
        }
    }
}

Let's analyze some of these methods.

The Fickr.Net library method PhotosetsGetPhotos expects the page index, and not the index of the first record to retrieve, so I created the GetPageIndex helper method for the conversion.

The method GetPhotoSetsByUser returns the result of PhotosetsGetList. Note that this function doesn't expect as parameter the Flickr user name, but the user id. You can retrieve this data using other methods integrated into the Flicker.Net API or using websites such as http://www.xflickr.com/fusr/.

Don't get scared by the GetPagedSet method attribute. Components such as the ObjectDataSource control and the ObjectDataSourceDesigner class examine the values of this attribute, if present, to help determine which data method to call at run time. It isn't necessary, but it simplifies the work. The same attribute is used to indicate that this class is a data object ([DataObject(true)]). I decides to make use of pagination in this example, and it was easy because the API already provides this functionality. The method simply calls the PhotosetsGetPhotos available in the Flicker.Net library, and uses the opportune overload.

The Count method needed for paging uses GetPagedSetCount, which gets the requested set's info and returns the number of items in the set.

The web.config

In order to acquire authentication data and other parameters that may vary, we need to create an appSettings section in our web.config.

<appSettings>
  <add key="apiKey" value="6370a3f6c4f1c031afd636247a648385"/>
  <add key="shardSecret" value="42cf8c1g85e6d3b2"/>
  <add key="defaultUser" value="10734446@N06"/>
  <add key="defaultPageSize" value="44"/>
</appSettings>

apiKey and sharedSecret are dummy values. You need to register and replace them to obtain a full functionality, but you can still use the default user and the default page size. If you are using a different layout, you can change the number of photos shown on each page, by simply varying this value.

Constructing the page

Add a new web form to your project and place inside it a DropDownList. After that, place inside the page an ObjectDataSurce control. For this ObjectDataSurce control, you can use the Designer and the Smart Task for making things quicker.

<p>
    List of default user sets:
    <br />
    <asp:DropDownList ID="ddlSets" runat="server" 
        AutoPostBack="True" DataSourceID="odsSets"
        DataTextField="Title" DataValueField="PhotosetId" 
        Height="21px" Width="450px"
        OnSelectedIndexChanged="ddlSets_SelectedIndexChanged">
    </asp:DropDownList>
</p>
<asp:ObjectDataSource ID="odsSets" runat="server" 
        OldValuesParameterFormatString="original_{0}"
        OnSelecting="odsSets_Selecting" 
        SelectMethod="GetPhotoSetsByUser" 
        TypeName="Infrastructure.BLL.FlickrBLL">
    <SelectParameters>
        <asp:Parameter Name="userId" Type="String" />
    </SelectParameters>
</asp:ObjectDataSource> 

As you can see, our method is expecting a value so it can properly retrieve the data. As our user ID is stored in the web.config, this is the approach for passing a requested argument:

protected void odsSets_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
   e.InputParameters["userId"] = ConfigurationManager.AppSettings["defaultUser"].ToString();
}

Intercept the Selecting event and manually set the expected parameter. I'm getting it from the web.config; you can choose any other way, e.g.: using another control in the page (if you create a user search). If you are inexperienced, you may be wondering how I got the DataTextField and DataValueField values. Simple, they are properties of the Photoset class, which is an element of PhotosetCollection, that is our called method return type. To explore other properties, create an instance of the Photoset class, select it, and hit F12.

Now I will add a ListView control in order to list the data that is the outcome of my query.

<asp:ListView ID="lvImages" runat="server" DataSourceID="odsPhotos">
    <EmptyDataTemplate>
        <span>No data was returned.</span>
    </EmptyDataTemplate>
    <ItemTemplate>
        <a href="<%# Eval("MediumUrl") %>" rel="images" title="<%# Eval("Title") %>">
            <img alt="" src="<%# Eval("SquareThumbnailUrl") %>" />
	</a> 
	</ItemTemplate>
    <LayoutTemplate>
        <div id="itemPlaceholderContainer" runat="server" style="">
            <span runat="server" id="itemPlaceholder" />
        </div>
            <asp:DataPager ID="DataPager1" runat="server" PageSize="<%$ appSettings:defaultPageSize %>">
                <Fields>
                    <asp:NextPreviousPagerField ButtonType="Image" ShowFirstPageButton="true" ShowNextPageButton="false"
                        ShowPreviousPageButton="true" FirstPageImageUrl="~/images/first.gif" PreviousPageImageUrl="~/images/previous.gif" />
                    <asp:TemplatePagerField>
                        <PagerTemplate>
                            Page
                            <asp:Label runat="server" ID="labelCurrentPage" 
		Text="<%# Container.TotalRowCount > 0 ? (Container.StartRowIndex / Container.PageSize) + 1 : 0 %>" />
                            of
                            <asp:Label runat="server" ID="labelTotalPages" 
                Text="<%#  Math.Ceiling ((double)Container.TotalRowCount / Container.PageSize) %>" />
                        </PagerTemplate>
                    </asp:TemplatePagerField>
                    <asp:NextPreviousPagerField ButtonType="Image" ShowLastPageButton="true" ShowNextPageButton="true"
                        ShowPreviousPageButton="false" LastPageImageUrl="~/images/last.gif" NextPageImageUrl="~/images/next.gif" />
                    <asp:TemplatePagerField>
                        <PagerTemplate>
                            <br />
                            Total Pictures in this set:
                            <asp:Label runat="server" ID="labelTotalPictures" Text="<%#  (double)Container.TotalRowCount %>" />
                        </PagerTemplate>
                    </asp:TemplatePagerField>
                </Fields>
            </asp:DataPager>
    </LayoutTemplate>
</asp:ListView>

Note that I specified a very simple ItemTemplate; the code speaks for itself. The important thing to note is that inside the layout template, there is a DataPager control. When the DataPager is inside a ListView control, setting the PagedControlID of the DataPager isn't necessary. The container ListView is automatically associated as the paged control.

Obviously, this will not work without a data source, so here we go, an ObjectDataSource is served.

<asp:ObjectDataSource ID="odsPhotos" runat="server" 
        EnablePaging="True" OldValuesParameterFormatString="original_{0}"
        SelectCountMethod="GetPagedSetCount" 
        SelectMethod="GetPagedSet" TypeName="Infrastructure.BLL.FlickrBLL"
        OnSelecting="odsPhotos_Selecting">
    <SelectParameters>
        <asp:ControlParameter ControlID="ddlSets" 
            DefaultValue="0" Name="setId" PropertyName="SelectedValue"
            Type="String" />
    </SelectParameters>
</asp:ObjectDataSource>

You can use Designer and the Smart Task, but be aware that a guided procedure will add the parameters that are used for paging and the app will not work correctly. Take a look at the properties that enable paging and the count method.

Now we need to set a maximum rows property, but as this property is specified in the web.config, we will do it from code.

protected void odsPhotos_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
   e.Arguments.MaximumRows = 
     int.Parse(ConfigurationManager.AppSettings["defaultPageSize"]);
}

That's almost it, but there are some small problems, like viewing the second page of a set and then changing the set, setting one that has just one page. Badly sad, more simply, at each set change, we need to reset the page counter.

protected void ddlSets_SelectedIndexChanged(object sender, EventArgs e)
{
    DataPager pgr = lvImages.FindControl("DataPager1") as DataPager;
    if (pgr != null && lvImages.Items.Count != pgr.TotalRowCount)
    {
        pgr.SetPageProperties(0, pgr.MaximumRows, false);
    }
}

Now, that's it, and everything should work perfectly!

AJAXing

Let's get rid of postbacks. Add on the page a ScriptManager and make the following changes:

Surround the ListView with the following code:

<asp:UpdatePanel ID="upImages" 
              runat="server" style="text-align: center;">
    <ContentTemplate>
        // my list view
    </ContentTemplate>
    <Triggers>
        <asp:AsyncPostBackTrigger ControlID="ddlSets" />
    </Triggers>
</asp:UpdatePanel>

As the DropDownList is outside of the ListView, we need to indicate that even that control triggers a postback and that should be managed properly. Can't be simpler!

The make up

I said before that we will use a lighbox plug-in called Colorbox. So let's set it up. First of all, put all the images that are coming with this plug-in into the images directory, then do the same for the CSS style. Open the CSS file that you just copied, and check the image paths. Pay attention to comments about IE workarounds and the connected paths. Copy the necessary scripts to a script folder and then be ready for some code. We should link our scripts and the CSS file, so in the page head, add the following:

<link href="Styles/colorbox.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="scripts/jquery.min.js"></script>
<script type="text/javascript" src="scripts/jquery.colorbox-min.js"></script>

Once we are done, we need to create an instance of Colorbox in order for this to work. As the JavaScript is no longer "bound" after a callback made via UpdatePanel, we need to reinitialize our Colorbox.

<script type="text/javascript">
        $(document).ready(function () {
            $("a[rel='images']").colorbox({ transition: "fade" });
        });

        function pageLoad(sender, args) {
            if (args.get_isPartialLoad()) {
                $("a[rel='images']").colorbox({ transition: "fade" });
            }
        }
</script>

For further information about the light box, and how you can get more from this practical plug-in, refer to the Colorbox webpage.

The result

In the end, by using a style that was automatically created by VS2010, this is the result:

FlickrPreview1.jpg

Here is a bit more detailed view:

FlickrPreview2.jpg

Notes

The default user for Filckr in the demo is actually an active and very nice Flickr profile. It's my friend's profile, mind_in_motion, so if you like nice photos, check it out. Thanks Jean Claude! This is my first article on CodeProject, so please be merciful! I'll try to answer all of your questions, if any.

Joyful programming!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here