Click here to Skip to main content
Click here to Skip to main content

A Simple ASP.NET Flickr Application

, 16 Nov 2010
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mario Majčica
Software Developer (Senior) Cenosco B.V.
Netherlands Netherlands
An accomplished software engineer specialized in object-oriented design and analysis on Microsoft .NET platform with extensive experience in the full life cycle of the software design process.
Experienced in agile software development via scrum and kanban frameworks supported by the TFS ALM environment and JIRA. In depth know how on all automation process leading to continuous integration.
Additionally, I have a strong hands-on experience on deploying and administering Microsoft Team Foundation Server (migrations, builds, deployment, branching strategies, etc.).
 
Specialties: Microsoft .NET Framework, C#, SQL Server, WCF, WebAPI, ASP.NET MVC, HTML5, ALM with TFS, continous integration, design patterns, software architecture, ASP.NET Web Forms, JavaScript.
Follow on   Twitter   LinkedIn

Comments and Discussions

 
Question{"HTTP Error 403, Forbidden"} PinmemberMember 346208028-Jun-14 11:15 
AnswerRe: {"HTTP Error 403, Forbidden"} PinpremiumMario Majčica29-Jun-14 23:04 
QuestionHow to get first (or one) image of Sets PinmemberMember 18973039-Jun-13 20:01 
Questionthank you and question PinmemberAnne at fastzone20-Dec-12 6:12 
AnswerRe: thank you and question PinmemberMario Majčica20-Dec-12 23:11 
GeneralMy vote of 3 PinmemberAndrey Mazoulnitsyn18-May-11 8:05 
GeneralRe: My vote of 3 PinmemberMario Majcica20-Jun-11 1:11 
GeneralMy vote of 5 PinmemberTed Malone2-Jan-11 15:25 
AnswerRe: My vote of 5 PinmemberMario Majcica4-Jan-11 9:19 
GeneralMy vote of 5 Pinmembersantosh poojari30-Dec-10 17:39 
Generalgood one - have 5 from me PinmemberPranay Rana18-Dec-10 10:02 
GeneralMy vote of 4 Pinmemberapoloion24-Nov-10 1:19 
GeneralMy vote of 5 PinmemberLuca Leonardo Scorcia19-Nov-10 10:51 
GeneralRe: My vote of 5 PinmemberMario Majcica19-Nov-10 10:54 
GeneralMy vote of 5 PinmemberShahriar Iqbal Chowdhury13-Nov-10 20:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 17 Nov 2010
Article Copyright 2010 by Mario Majčica
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid